783 lines
34 KiB
PHP
783 lines
34 KiB
PHP
<?php
|
||
|
||
namespace app\common\service;
|
||
|
||
use app\common\model\Demands;
|
||
use app\common\traits\ServiceTrait;
|
||
use Exception;
|
||
use think\Db;
|
||
use think\Log;
|
||
|
||
class DemandService
|
||
{
|
||
use ServiceTrait;
|
||
|
||
/** @var Demands */
|
||
public static $Model = Demands::class;
|
||
|
||
// 订单状态
|
||
const STATUS_NO = 0; //关闭
|
||
const STATUS_BIDDING = 1; //招标中
|
||
const STATUS_SIGNING = 2; //签约中
|
||
const STATUS_WORKING = 3; //工作中
|
||
const STATUS_ACCEPTING = 4; //验收中
|
||
const STATUS_CONFIRM_RECEIPT = 5; //待收货
|
||
const STATUS_FINISHED = 6; //已完成
|
||
const STATUS_CANCEL = 7; //已取消
|
||
|
||
const STATUS_MAP = [
|
||
self::STATUS_NO => '已关闭',
|
||
self::STATUS_BIDDING => '招标中',
|
||
self::STATUS_SIGNING => '签约中',
|
||
self::STATUS_WORKING => '工作中',
|
||
self::STATUS_ACCEPTING => '验收中',
|
||
self::STATUS_CONFIRM_RECEIPT => '待收货',
|
||
self::STATUS_FINISHED => '已完成',
|
||
self::STATUS_CANCEL => '已取消',
|
||
];
|
||
|
||
const PUBLISH_STATUS_MAP = [
|
||
CommonService::NO => '',
|
||
CommonService::ONGOING => '审核中',
|
||
CommonService::SUCCESS => '已发布',
|
||
CommonService::FAILED => '发布失败',
|
||
];
|
||
|
||
const WORK_STATUS_MAP = [
|
||
CommonService::NO => '',
|
||
CommonService::ONGOING => '工作中',
|
||
CommonService::SUCCESS => '工作完成',
|
||
CommonService::FAILED => '工作失败',
|
||
];
|
||
|
||
const ACCEPT_STATUS_MAP = [
|
||
CommonService::NO => '',
|
||
CommonService::ONGOING => '验收中',
|
||
CommonService::SUCCESS => '验收通过',
|
||
CommonService::FAILED => '验收失败',
|
||
];
|
||
|
||
const SETTLE_STATUS_MAP = [
|
||
CommonService::NO => '',
|
||
CommonService::ONGOING => '结算中',
|
||
CommonService::SUCCESS => '结算完成',
|
||
CommonService::FAILED => '结算失败',
|
||
];
|
||
|
||
const BUTTON_CONFIRM = 'confirm';//确认接单
|
||
const BUTTON_CONTRACT_DEV = 'contractDev'; //开发者签约
|
||
const BUTTON_CONTRACT_CUSTOMER = 'contractCustomer'; //客户签约
|
||
const BUTTON_COMPLETE_WORK = 'completeWork'; //完成工作
|
||
const BUTTON_ACCEPT_PASSED = 'acceptPassed'; //验收通过
|
||
const BUTTON_CONFIRM_RECEIPT = 'confirmReceipt'; //确认收货
|
||
const BUTTON_DELIVER_GOODS = 'deliverGoods'; //开发者发货
|
||
|
||
/**
|
||
* 创建需求
|
||
*
|
||
* @param array $data 需求数据
|
||
* @param int $userId 用户ID
|
||
* @return bool
|
||
* @throws Exception
|
||
*/
|
||
public static function create($data, $userId)
|
||
{
|
||
$saveData = [
|
||
'type' => 0,
|
||
'user_id' => $userId,
|
||
'parent_order_no' => generate_order_sn(),
|
||
'title' => mb_substr($data['desc'], 0, 16),
|
||
'desc' => $data['desc'],
|
||
'develop_type' => $data['develop_type'] ?? '',
|
||
'contact' => $data['contact'],
|
||
'images' => $data['images'] ?? [],
|
||
'files' => $data['files'] ?? [],
|
||
'budget_amount' => $data['budget_amount'] ?? 0,
|
||
'limit_time' => $data['limit_time'] ?? 0,
|
||
'publish_status' => CommonService::ONGOING,
|
||
'status' => self::STATUS_NO
|
||
];
|
||
|
||
$result = self::$Model::create($saveData);
|
||
if (!$result) {
|
||
throw new Exception('需求保存失败');
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @throws
|
||
*/
|
||
public static function operateDemand($requestData, $userId)
|
||
{
|
||
$opType = $requestData['opType'] ?? 0;
|
||
switch ($opType) {
|
||
case self::BUTTON_CONFIRM:
|
||
$res = self::confirmDemand($requestData, $userId);
|
||
break;
|
||
case self::BUTTON_CONTRACT_DEV:
|
||
$res = self::devContract($requestData, $userId);
|
||
break;
|
||
case self::BUTTON_CONTRACT_CUSTOMER:
|
||
$res = self::customerContract($requestData);
|
||
break;
|
||
case self::BUTTON_COMPLETE_WORK:
|
||
$res = self::completeWork($requestData, $userId);
|
||
break;
|
||
case self::BUTTON_ACCEPT_PASSED:
|
||
$res = self::acceptPassed($requestData);
|
||
break;
|
||
case self::BUTTON_CONFIRM_RECEIPT:
|
||
$res = self::confirmReceipt($requestData, $userId);
|
||
break;
|
||
case self::BUTTON_DELIVER_GOODS:
|
||
$res = self::deliverGoods($requestData, $userId);
|
||
break;
|
||
default:
|
||
throw new \Exception('非法操作');
|
||
}
|
||
|
||
return $res;
|
||
}
|
||
|
||
/**
|
||
* 确认接单
|
||
* @param $requestData
|
||
* @param int $userId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function confirmDemand($requestData, int $userId = 0)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$agree = intval($requestData['agree'] ?? 0);
|
||
$demand = self::getOne(['id' => $demandId]);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if (!in_array($demand->status, [self::STATUS_BIDDING])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能不能确认');
|
||
}
|
||
$userInfo = UserService::getOne(['id' => $userId]);
|
||
$where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN, 'process_status' => DemandBiddingService::STATUS_PROCESS_ONGOING];
|
||
$demandBidding = DemandBiddingService::getOne($where);
|
||
if (!$demandBidding) {
|
||
throw new \Exception('您无需确认');
|
||
}
|
||
//修改投标状态
|
||
if ($agree) {
|
||
//确认接单
|
||
$upRes = DemandBiddingService::where($where)->update(['process_status' => DemandBiddingService::STATUS_PROCESS_CONFIRMED]);
|
||
if (!$upRes) {
|
||
throw new \Exception('更新投标状态失败');
|
||
}
|
||
//修改状态
|
||
$demand->status = self::STATUS_SIGNING;
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新需求状态失败');
|
||
}
|
||
//更新显示二维码
|
||
DemandGroupChatService::updateQrCode($demandId);
|
||
//客户发送消息
|
||
$msgData = [
|
||
'values' => [
|
||
$userInfo->nickname,
|
||
'需求开发',
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_DEMAND_MATCH_SUCCESS]['remark'],
|
||
]
|
||
];
|
||
(new EasyWeChatService())->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_DEMAND_MATCH_SUCCESS, $msgData);
|
||
} else {
|
||
//拒绝接单
|
||
$upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO, 'process_status' => DemandBiddingService::STATUS_PROCESS_FAILED]);
|
||
if (!$upRes) {
|
||
throw new \Exception('更新投标状态失败');
|
||
}
|
||
//扣除信誉分5分,添加日志
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '拒绝接单扣除', 0, AccountLogService::CREDIT_TYPE_DEMAND_REFUSE, AccountLogService::INC_EXP_EXPEND, $demandId);
|
||
AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
|
||
}
|
||
Db::commit();
|
||
$info = DemandBiddingService::getOne($where);
|
||
return $info;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 开发者签约
|
||
* @param $requestData
|
||
* @param int $userId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function devContract($requestData, int $userId)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$agree = intval($requestData['agree'] ?? 0);
|
||
$demand = self::getOne(['id' => $demandId]);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if ($agree) {
|
||
if (!in_array($demand->status, [self::STATUS_SIGNING])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能不能签约');
|
||
}
|
||
//生成两个订单,签约记录
|
||
OrderService::createDemandOrder($requestData);
|
||
Db::commit();
|
||
//给客户发送签约提醒
|
||
$msgData = [
|
||
'values' => [
|
||
$demand->parent_order_no,
|
||
mb_substr($demand->desc, 0, 6),
|
||
intval($requestData['formData']['totalCost'] ?? 0),
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_CONTRACT_SIGN]['remark'],
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_CONTRACT_SIGN, $msgData);
|
||
} else {
|
||
//拒绝签约
|
||
//中标去除
|
||
$where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
|
||
$upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO]);
|
||
if (!$upRes) {
|
||
exception('更新中标状态失败');
|
||
}
|
||
//扣除信誉分5分,添加日志
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '放弃签约扣除', 0, AccountLogService::CREDIT_TYPE_CONTRACT_REFUSE, AccountLogService::INC_EXP_EXPEND, $demandId);
|
||
AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
|
||
//订单状态还原
|
||
$demand->status = self::STATUS_BIDDING;
|
||
$demand->save();
|
||
Db::commit();
|
||
}
|
||
|
||
return $demand;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 客户签约
|
||
* @param $requestData
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function customerContract($requestData)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$contractType = $requestData['contractType'] ?? 1;
|
||
$demand = self::getOne(['id' => $demandId]);
|
||
$formData = $requestData['formData'] ?? [];
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if (!in_array($demand->status, [self::STATUS_SIGNING])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能签约');
|
||
}
|
||
//更新签约记录
|
||
$winContract = ContractService::updateCustomerContractData($demandId, $formData);
|
||
//如果新的合同金额与旧的合同金额不符,则通过修改尾款订单的金额的方式来弥补差价
|
||
$firstContract = ContractService::getFirstContract($demandId);
|
||
if ($firstContract && $firstContract->total_amount != $winContract->total_amount && $winContract->status2 != ContractService::STATUS_FINISHED) {
|
||
$diffAmount = $winContract->total_amount - $firstContract->total_amount;
|
||
//更新尾款订单的金额
|
||
$finalOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT);
|
||
$finalOrder->total_amount += $diffAmount;
|
||
$finalOrder->goods_amount += $diffAmount;
|
||
$finalOrder->payment_amount += $diffAmount;
|
||
$saveRes = $finalOrder->save();
|
||
if (!$saveRes) {
|
||
exception('弥补订单差价金额失败');
|
||
}
|
||
}
|
||
//获取签约订单用于支付
|
||
$order = OrderService::getDemandOrder($demand->parent_order_no, $contractType);
|
||
if (!$order) {
|
||
throw new \Exception('获取签约订单失败');
|
||
}
|
||
//如果客户已支付预付款,则直接调用支付成功的处理
|
||
if (in_array($order->order_status, [OrderService::ORDER_STATUS_WAIT_SHIP])) {
|
||
self::customerContractFinishedDeal(0, $demandId);
|
||
}
|
||
|
||
Db::commit();
|
||
return $order;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 完成工作
|
||
* @param $requestData
|
||
* @param $userId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function completeWork($requestData, $userId)
|
||
{
|
||
try {
|
||
$agree = intval($requestData['agree'] ?? 0);
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$demand = self::getOne(['id' => $demandId]);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if ($agree) {
|
||
//完成工作
|
||
if (!in_array($demand->status, [self::STATUS_WORKING])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能完成');
|
||
}
|
||
$demand->status = self::STATUS_ACCEPTING;
|
||
$demand->work_status = CommonService::SUCCESS;
|
||
$demand->accept_status = CommonService::ONGOING;
|
||
$demand->save();
|
||
Db::commit();
|
||
//给客户发送验收通知
|
||
$msgData = [
|
||
'values' => [
|
||
$demand->parent_order_no,
|
||
mb_substr($demand->desc, 0, 6),
|
||
mb_substr($demand->desc, 0, 11),
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT]['remark'],
|
||
]
|
||
];
|
||
(new EasyWeChatService())->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT, $msgData);
|
||
} else {
|
||
//完成失败
|
||
//中标去除
|
||
$where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
|
||
$upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO]);
|
||
if (!$upRes) {
|
||
exception('更新中标状态失败');
|
||
}
|
||
//扣除信誉分5分,添加日志
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 10, '需求完成失败-信誉分扣除', 0, AccountLogService::CREDIT_TYPE_DEMAND_FAILED, AccountLogService::INC_EXP_EXPEND, $demandId);
|
||
AccountService::updateData($userId, 0, 0, -10, 0, $log_res->id);
|
||
//冻结余额退回
|
||
AccountService::freezeAmountRefund($demandId, $userId);
|
||
Db::commit();
|
||
//等待客服操作是否取消订单或重新安排开发人员
|
||
}
|
||
|
||
return $demand;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验收通过
|
||
* @param $requestData
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function acceptPassed($requestData)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$contractType = $requestData['contractType'] ?? 2;
|
||
$agree = $requestData['agree'] ?? 0;
|
||
$reason = $requestData['reason'] ?? '';
|
||
$demand = self::getOne(['id' => $demandId], ['winBidding']);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if (!in_array($demand->status, [self::STATUS_ACCEPTING])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能验收');
|
||
}
|
||
if (!$agree) {
|
||
//驳回重新工作
|
||
$demand->status = self::STATUS_WORKING;
|
||
$demand->work_status = CommonService::ONGOING;
|
||
$demand->accept_status = CommonService::FAILED;
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新需求状态失败');
|
||
}
|
||
//给开发者发送验收失败的通知
|
||
$msgData = [
|
||
'values' => [
|
||
'整体功能验收',
|
||
'验收失败',
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT]['remarkFail'],
|
||
mb_substr($reason, 0, 16) ?: '需求未按要求完成开发'
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($demand->winBidding->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT, $msgData);
|
||
} else {
|
||
//返回订单用于支付尾款
|
||
$order = OrderService::getDemandOrder($demand->parent_order_no, $contractType);
|
||
if (!$order) {
|
||
throw new \Exception('获取签约订单失败');
|
||
}
|
||
}
|
||
Db::commit();
|
||
return $order ?? [];
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 规范化交付链接(只允许 1 个)
|
||
* 支持数组或字符串,仅保留第一个 http(s) 开头的合法链接
|
||
* @param array|string $links
|
||
* @return array
|
||
*/
|
||
public static function normalizeDeliverLinks($links): array
|
||
{
|
||
if (is_string($links)) {
|
||
$links = preg_split('/[,,\r\n]+/', $links) ?: [];
|
||
}
|
||
foreach ((array)$links as $item) {
|
||
$url = is_array($item) ? trim($item['url'] ?? '') : trim((string)$item);
|
||
if ($url && preg_match('/^https?:\/\//i', $url)) {
|
||
//只保留第一个合法链接
|
||
return [$url];
|
||
}
|
||
}
|
||
|
||
return [];
|
||
}
|
||
|
||
/**
|
||
* 开发者发货(交付开发成果)
|
||
* 凭证截图、交付附件与备注写入订单发货表,尾款订单转为已发货(待收货)
|
||
* @param $requestData
|
||
* @param $userId
|
||
* @return bool
|
||
* @throws Exception
|
||
*/
|
||
public static function deliverGoods($requestData, $userId)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$images = array_values($requestData['images'] ?? []);
|
||
$files = array_values($requestData['files'] ?? []);
|
||
$links = self::normalizeDeliverLinks($requestData['links'] ?? '');
|
||
$remark = trim($requestData['remark'] ?? '');
|
||
Db::startTrans();
|
||
//源码一般在企业微信沟通群直接交付(无大小限制),平台只登记发货状态,
|
||
//故仅凭证截图必填,附件与交付链接均选填
|
||
if (!$images) {
|
||
throw new \Exception('请上传开发完成的凭证截图');
|
||
}
|
||
$demand = self::getOne(['id' => $demandId], ['winBidding']);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
if ($demand->status != self::STATUS_CONFIRM_RECEIPT) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能发货');
|
||
}
|
||
if (!$demand->winBidding || $demand->winBidding->user_id != $userId) {
|
||
throw new \Exception('只有中标开发者才能发货');
|
||
}
|
||
//尾款订单必须已支付(待发货)才能发货
|
||
$finalOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT);
|
||
if (!$finalOrder) {
|
||
throw new \Exception('获取尾款订单失败');
|
||
}
|
||
if ($finalOrder->order_status != OrderService::ORDER_STATUS_WAIT_SHIP) {
|
||
throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$finalOrder->order_status] . ',不能发货');
|
||
}
|
||
//交付内容写入订单发货表
|
||
$spuId = $finalOrder->orderGoods[0]->spu_id ?? 0;
|
||
OrderShipService::createDemandDelivery($finalOrder->order_no, $spuId, $demandId, $images, $files, $remark, $links);
|
||
//尾款订单改为已发货(待收货)
|
||
$upRes = OrderService::where(['id' => $finalOrder->id])->update(['order_status' => OrderService::ORDER_STATUS_SHIPPED]);
|
||
if (!$upRes) {
|
||
exception('更新发货状态失败');
|
||
}
|
||
Db::commit();
|
||
//给客户发送确认收货提醒(跳转需求详情查看交付内容)
|
||
$msgData = [
|
||
'page' => SubscribeMessageService::PAGE_DEMAND_DETAIL,
|
||
'param' => ['id' => $demand->id],
|
||
'values' => [
|
||
//character_string 字段不支持中文,产品名称填需求编号
|
||
$demand->parent_order_no,
|
||
$finalOrder->order_no,
|
||
$finalOrder->payment_amount,
|
||
mb_substr($remark ?: SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_CONFIRM_RECEIPT]['remark'], 0, 20),
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_CONFIRM_RECEIPT, $msgData);
|
||
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 确认收货
|
||
* @param $requestData
|
||
* @param $userId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function confirmReceipt($requestData, $userId)
|
||
{
|
||
try {
|
||
$demandId = $requestData['demandId'] ?? 0;
|
||
$demand = self::getOne(['id' => $demandId, 'user_id' => $userId]);
|
||
if (!$demand) {
|
||
throw new \Exception('该需求不存在');
|
||
}
|
||
Db::startTrans();
|
||
if (!in_array($demand->status, [self::STATUS_CONFIRM_RECEIPT])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能确认收货');
|
||
}
|
||
//订单完成
|
||
$demand->status = self::STATUS_FINISHED;
|
||
$demand->settle_status = CommonService::ONGOING; //结算中
|
||
//返回订单用于支付尾款
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新需求状态失败');
|
||
}
|
||
//关联订单状态改为已完成
|
||
$upRes = OrderService::where(['parent_order_no' => $demand->parent_order_no])->update(['order_status' => OrderService::ORDER_STATUS_FINISHED]);
|
||
if (!$upRes) {
|
||
exception('更新订单状态失败');
|
||
}
|
||
Db::commit();
|
||
return $demand;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 客户签约并支付成功处理需求
|
||
* @param $parent_order_no
|
||
* @param int $demandId
|
||
* @return void
|
||
* @throws Exception
|
||
*/
|
||
public static function customerContractFinishedDeal($parent_order_no, int $demandId = 0)
|
||
{
|
||
$where = function ($query) use ($parent_order_no, $demandId) {
|
||
$query->where('parent_order_no', $parent_order_no)->whereOr('id', $demandId);
|
||
};
|
||
$demand = self::getOne($where, ['winBidding']);
|
||
if ($demand) {
|
||
//更新客户的签约状态 $demand->id
|
||
$contract = ContractService::getWinBiddingContract($demand->id);
|
||
//如果客户已经签约过,则跳过防止重复给开发者增加冻结金额
|
||
if ($contract->status2 == ContractService::STATUS_FINISHED) {
|
||
return;
|
||
}
|
||
$contract->status2 = ContractService::STATUS_FINISHED;
|
||
$contract->save();
|
||
//更新需求的状态
|
||
$demand->status = self::STATUS_WORKING;
|
||
$demand->save();
|
||
$userId = $contract->demandBidding->user_id;
|
||
//开发者冻结金额增加
|
||
$demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FIRST_PAYMENT);
|
||
$ratio = (float)config('site.platform_commission_ratio');
|
||
$amount = $demandOrder->payment_amount * (1 - $ratio);
|
||
$title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益';
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id);
|
||
AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id);
|
||
//给开发者发送开始工作的消息通知
|
||
$msgData = [
|
||
'values' => [
|
||
mb_substr($demand->desc, 0, 6),
|
||
date('Y.m.d', strtotime('+1 days')) . ' ~ ' . date('Y.m.d', strtotime("+$contract->need_days days")),
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_START]['remark'],
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($userId, SubscribeMessageService::MSG_TEMP_WORK_START, $msgData);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 客户验收完成处理需求
|
||
* @param $parent_order_no
|
||
* @return void
|
||
* @throws Exception
|
||
*/
|
||
public static function customerWorkAcceptFinishedDeal($parent_order_no)
|
||
{
|
||
$demand = self::getOne(['parent_order_no' => $parent_order_no], ['winBidding']);
|
||
if ($demand && $demand->status == self::STATUS_ACCEPTING && $demand->accept_status != CommonService::SUCCESS) {
|
||
//更新需求的状态
|
||
$demand->status = self::STATUS_CONFIRM_RECEIPT;
|
||
$demand->accept_status = CommonService::SUCCESS;
|
||
$demand->accept_time = time();
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新验收状态失败');
|
||
}
|
||
$userId = $demand->winBidding->user_id;
|
||
//开发者冻结金额增加
|
||
$demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT);
|
||
$ratio = (float)config('site.platform_commission_ratio');
|
||
$amount = $demandOrder->payment_amount * (1 - $ratio);
|
||
$title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益';
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id);
|
||
AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id);
|
||
//给开发者发送验收结果的消息通知
|
||
$msgData = [
|
||
'values' => [
|
||
'整体功能验收',
|
||
'验收通过',
|
||
SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT]['remark'],
|
||
'功能验收完成'
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($demand->winBidding->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT, $msgData);
|
||
//给开发者发送发货提醒(客户已支付尾款,跳转需求详情去发货)
|
||
$shipMsgData = [
|
||
'page' => SubscribeMessageService::PAGE_DEMAND_DETAIL,
|
||
'param' => ['id' => $demand->id],
|
||
'values' => [
|
||
$demandOrder->order_no,
|
||
mb_substr($demand->title, 0, 20),
|
||
'待发货',
|
||
'客户已支付尾款,请及时发货交付',
|
||
]
|
||
];
|
||
(new EasyWeChatService)->sendMsg($userId, SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED, $shipMsgData);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 重新投标
|
||
* @param $demand
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public static function resetBiddingDeal($demand)
|
||
{
|
||
try {
|
||
Db::startTrans();
|
||
if (in_array($demand->status, [self::STATUS_CONFIRM_RECEIPT, self::STATUS_FINISHED, self::STATUS_CANCEL])) {
|
||
throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能重新投标');
|
||
}
|
||
if (in_array($demand->settle_status, [CommonService::SUCCESS])) {
|
||
throw new \Exception('该需求为' . self::SETTLE_STATUS_MAP[$demand->settle_status] . ',不能重新投标');
|
||
}
|
||
$demandId = $demand->id;
|
||
$where = ['demand_id' => $demandId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
|
||
$winBidding = DemandBiddingService::where($where)->find();
|
||
if ($winBidding) {
|
||
//中标去除
|
||
$winBidding->bidding_status = DemandBiddingService::STATUS_BIDDING_NO;
|
||
$upRes = $winBidding->save();
|
||
if (!$upRes) {
|
||
exception('更新中标状态失败');
|
||
}
|
||
$userId = $winBidding->user_id;
|
||
//扣除信誉分5分,添加日志
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '系统自动操作-信誉分扣除', 0, AccountLogService::CREDIT_TYPE_ADMIN_OPERATE, AccountLogService::INC_EXP_EXPEND, $demandId);
|
||
AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
|
||
//冻结余额退回
|
||
AccountService::freezeAmountRefund($demandId, $userId);
|
||
}
|
||
//继续投标,重置状态
|
||
$demand->status = self::STATUS_BIDDING;
|
||
$demand->work_status = CommonService::NO;
|
||
$demand->accept_status = CommonService::NO;
|
||
$demand->settle_status = CommonService::NO;
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新需求状态失败');
|
||
}
|
||
Db::commit();
|
||
return $demand;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理订单收益解冻
|
||
*/
|
||
public static function unfreeze()
|
||
{
|
||
//
|
||
$where = [
|
||
'order_status' => DemandService::STATUS_CONFIRM_RECEIPT,
|
||
'settle_status' => CommonService::ONGOING,
|
||
];
|
||
$ratio = (float)config('site.platform_commission_ratio');
|
||
Demands::with(['demandContracts', 'winBidding'])->where($where)->chunk(100, function ($demands) use ($ratio) {
|
||
foreach ($demands as $demand) {
|
||
try {
|
||
//开启事务 抛出异常时自动回滚
|
||
DB::transaction(function () use ($demand, $ratio) {
|
||
$userId = $demand->merchant->user_id;
|
||
$show_time = $demand->goodsInfo->show_time ? $demand->goodsInfo->show_time : $demand->goodsInfo->created_at;
|
||
Log::info('订单收益解冻:', ['show_time' => $show_time, 'unfreeze_time' => strtotime(date('Y-m-d', strtotime($show_time) + 3 * 3600) . ' 09:00')]);
|
||
if (time() > strtotime(date('Y-m-d', strtotime('+1 day', strtotime($show_time) + 3 * 3600)) . ' 09:00')) {
|
||
$demand->status = DemandService::STATUS_FINISHED;
|
||
$demand->settle_status = CommonService::SUCCESS;
|
||
$demand->save();
|
||
$amount = ($demand->demandContracts->total_amount ?? 0) * (1 - $ratio);
|
||
//写入余额日志
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, -$amount, '需求收益解冻-冻结扣除', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount);
|
||
$log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_AMOUNT, +$amount, '需求收益解冻-余额增加', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount);
|
||
//减去冻结,加到余额里面
|
||
AccountService::updateData($userId, $amount, -$amount, 0, 0, $log_res->id);
|
||
//发送余额解冻通知
|
||
}
|
||
});
|
||
} catch (\Exception $e) {
|
||
Log::info('需求结算处理异常:' . json_encode(['file' => $e->getFile(), 'line' => $e->getLine(), 'error' => $e->getMessage(), 'demand' => $demand], JSON_UNESCAPED_UNICODE));
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 审核
|
||
* @param $id
|
||
* @return void
|
||
*/
|
||
public static function auditPass($id)
|
||
{
|
||
Db::transaction(function () use ($id) {
|
||
$demand = self::getOne(['id' => $id]);
|
||
if (!$demand) {
|
||
exception('该需求不存在');
|
||
}
|
||
if ($demand->publish_status == CommonService::SUCCESS) {
|
||
exception('已经审核通过,请勿重复审核');
|
||
}
|
||
//修改审核状态
|
||
$demand->status = self::STATUS_BIDDING;
|
||
$demand->publish_status = CommonService::SUCCESS;
|
||
$saveRes = $demand->save();
|
||
if (!$saveRes) {
|
||
exception('更新审核状态失败');
|
||
}
|
||
//发送审核结果-站内消息通知
|
||
});
|
||
}
|
||
} |