Files
code-bang/backend/application/common/service/DemandService.php
T
2026-10-14 15:46:49 +08:00

812 lines
34 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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'; //开发者发货
/**
* 获取平台服务费比例(0~1),后台填写大于 1 时按百分比处理,如 10 表示 10%
* @return string
*/
public static function getPlatformCommissionRatio(): string
{
$ratio = config('site.platform_commission_ratio');
if (!is_numeric($ratio) || $ratio <= 0) {
return '0';
}
$ratio = (string)$ratio;
if (bccomp($ratio, '1', 4) > 0) {
$ratio = bcdiv($ratio, '100', 4);
}
return bccomp($ratio, '1', 4) > 0 ? '1' : bcadd($ratio, '0', 4);
}
/**
* 计算扣除平台服务费后开发者实得金额
* @param mixed $amount 订单金额(元)
* @return string
*/
public static function getDeveloperIncome($amount): string
{
$ratio = self::getPlatformCommissionRatio();
return bcmul((string)$amount, bcsub('1', $ratio, 4), 2);
}
/**
* 创建需求
*
* @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('更新订单状态失败');
}
//交易完成:结算推广佣金
PromotionService::settleOrders(['parent_order_no' => $demand->parent_order_no]);
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);
$amount = self::getDeveloperIncome($demandOrder->payment_amount);
$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);
$amount = self::getDeveloperIncome($demandOrder->payment_amount);
$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,
];
Demands::with(['demandContracts', 'winBidding'])->where($where)->chunk(100, function ($demands) {
foreach ($demands as $demand) {
try {
//开启事务 抛出异常时自动回滚
DB::transaction(function () use ($demand) {
$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 = self::getDeveloperIncome($demand->demandContracts->total_amount ?? 0);
//写入余额日志
$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('更新审核状态失败');
}
//发送审核结果-站内消息通知
});
}
}