DemandService.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\Demands;
  4. use app\common\traits\ServiceTrait;
  5. use Exception;
  6. use think\Db;
  7. use think\Log;
  8. class DemandService
  9. {
  10. use ServiceTrait;
  11. /** @var Demands */
  12. public static $Model = Demands::class;
  13. // 订单状态
  14. const STATUS_NO = 0; //关闭
  15. const STATUS_BIDDING = 1; //招标中
  16. const STATUS_SIGNING = 2; //签约中
  17. const STATUS_WORKING = 3; //工作中
  18. const STATUS_ACCEPTING = 4; //验收中
  19. const STATUS_CONFIRM_RECEIPT = 5; //待收货
  20. const STATUS_FINISHED = 6; //已完成
  21. const STATUS_CANCEL = 7; //已取消
  22. const STATUS_MAP = [
  23. self::STATUS_NO => '已关闭',
  24. self::STATUS_BIDDING => '招标中',
  25. self::STATUS_SIGNING => '签约中',
  26. self::STATUS_WORKING => '工作中',
  27. self::STATUS_ACCEPTING => '验收中',
  28. self::STATUS_CONFIRM_RECEIPT => '待收货',
  29. self::STATUS_FINISHED => '已完成',
  30. self::STATUS_CANCEL => '已取消',
  31. ];
  32. const PUBLISH_STATUS_MAP = [
  33. CommonService::NO => '',
  34. CommonService::ONGOING => '审核中',
  35. CommonService::SUCCESS => '已发布',
  36. CommonService::FAILED => '发布失败',
  37. ];
  38. const WORK_STATUS_MAP = [
  39. CommonService::NO => '',
  40. CommonService::ONGOING => '工作中',
  41. CommonService::SUCCESS => '工作完成',
  42. CommonService::FAILED => '工作失败',
  43. ];
  44. const ACCEPT_STATUS_MAP = [
  45. CommonService::NO => '',
  46. CommonService::ONGOING => '验收中',
  47. CommonService::SUCCESS => '验收通过',
  48. CommonService::FAILED => '验收失败',
  49. ];
  50. const SETTLE_STATUS_MAP = [
  51. CommonService::NO => '',
  52. CommonService::ONGOING => '结算中',
  53. CommonService::SUCCESS => '结算完成',
  54. CommonService::FAILED => '结算失败',
  55. ];
  56. const BUTTON_CONFIRM = 'confirm';//确认接单
  57. const BUTTON_CONTRACT_DEV = 'contractDev'; //开发者签约
  58. const BUTTON_CONTRACT_CUSTOMER = 'contractCustomer'; //客户签约
  59. const BUTTON_COMPLETE_WORK = 'completeWork'; //完成工作
  60. const BUTTON_ACCEPT_PASSED = 'acceptPassed'; //验收通过
  61. const BUTTON_CONFIRM_RECEIPT = 'confirmReceipt'; //确认收货
  62. /**
  63. * 创建需求
  64. *
  65. * @param array $data 需求数据
  66. * @param int $userId 用户ID
  67. * @return bool
  68. * @throws Exception
  69. */
  70. public static function create($data, $userId)
  71. {
  72. $saveData = [
  73. 'type' => 0,
  74. 'user_id' => $userId,
  75. 'parent_order_no' => generate_order_sn(),
  76. 'title' => mb_substr($data['desc'], 0, 16),
  77. 'desc' => $data['desc'],
  78. 'develop_type' => $data['develop_type'] ?? '',
  79. 'contact' => $data['contact'],
  80. 'images' => $data['images'] ?? [],
  81. 'files' => $data['files'] ?? [],
  82. 'budget_amount' => $data['budget_amount'] ?? 0,
  83. 'limit_time' => $data['limit_time'] ?? 0,
  84. 'publish_status' => CommonService::ONGOING,
  85. 'status' => self::STATUS_NO
  86. ];
  87. $result = self::$Model::create($saveData);
  88. if (!$result) {
  89. throw new Exception('需求保存失败');
  90. }
  91. return true;
  92. }
  93. /**
  94. * @throws
  95. */
  96. public static function operateDemand($requestData, $userId)
  97. {
  98. $opType = $requestData['opType'] ?? 0;
  99. switch ($opType) {
  100. case self::BUTTON_CONFIRM:
  101. $res = self::confirmDemand($requestData, $userId);
  102. break;
  103. case self::BUTTON_CONTRACT_DEV:
  104. $res = self::devContract($requestData, $userId);
  105. break;
  106. case self::BUTTON_CONTRACT_CUSTOMER:
  107. $res = self::customerContract($requestData);
  108. break;
  109. case self::BUTTON_COMPLETE_WORK:
  110. $res = self::completeWork($requestData, $userId);
  111. break;
  112. case self::BUTTON_ACCEPT_PASSED:
  113. $res = self::acceptPassed($requestData);
  114. break;
  115. case self::BUTTON_CONFIRM_RECEIPT:
  116. $res = self::confirmReceipt($requestData, $userId);
  117. break;
  118. default:
  119. throw new \Exception('非法操作');
  120. }
  121. return $res;
  122. }
  123. /**
  124. * 确认接单
  125. * @param $requestData
  126. * @param int $userId
  127. * @return mixed
  128. * @throws Exception
  129. */
  130. public static function confirmDemand($requestData, int $userId = 0)
  131. {
  132. try {
  133. $demandId = $requestData['demandId'] ?? 0;
  134. $agree = intval($requestData['agree'] ?? 0);
  135. $demand = self::getOne(['id' => $demandId]);
  136. if (!$demand) {
  137. throw new \Exception('该需求不存在');
  138. }
  139. Db::startTrans();
  140. if (!in_array($demand->status, [self::STATUS_BIDDING])) {
  141. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能不能确认');
  142. }
  143. $userInfo = UserService::getOne(['id' => $userId]);
  144. $where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN, 'process_status' => DemandBiddingService::STATUS_PROCESS_ONGOING];
  145. $demandBidding = DemandBiddingService::getOne($where);
  146. if (!$demandBidding) {
  147. throw new \Exception('您无需确认');
  148. }
  149. //修改投标状态
  150. if ($agree) {
  151. //确认接单
  152. $upRes = DemandBiddingService::where($where)->update(['process_status' => DemandBiddingService::STATUS_PROCESS_CONFIRMED]);
  153. if (!$upRes) {
  154. throw new \Exception('更新投标状态失败');
  155. }
  156. //修改状态
  157. $demand->status = self::STATUS_SIGNING;
  158. $saveRes = $demand->save();
  159. if (!$saveRes) {
  160. exception('更新需求状态失败');
  161. }
  162. //更新显示二维码
  163. DemandGroupChatService::updateQrCode($demandId);
  164. //客户发送消息
  165. $msgData = [
  166. 'values' => [
  167. $userInfo->nickname,
  168. '需求开发',
  169. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_DEMAND_MATCH_SUCCESS]['remark'],
  170. ]
  171. ];
  172. (new EasyWeChatService())->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_DEMAND_MATCH_SUCCESS, $msgData);
  173. } else {
  174. //拒绝接单
  175. $upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO, 'process_status' => DemandBiddingService::STATUS_PROCESS_FAILED]);
  176. if (!$upRes) {
  177. throw new \Exception('更新投标状态失败');
  178. }
  179. //扣除信誉分5分,添加日志
  180. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '拒绝接单扣除', 0, AccountLogService::CREDIT_TYPE_DEMAND_REFUSE, AccountLogService::INC_EXP_EXPEND, $demandId);
  181. AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
  182. }
  183. Db::commit();
  184. $info = DemandBiddingService::getOne($where);
  185. return $info;
  186. } catch (\Exception $e) {
  187. Db::rollback();
  188. throw $e;
  189. }
  190. }
  191. /**
  192. * 开发者签约
  193. * @param $requestData
  194. * @param int $userId
  195. * @return mixed
  196. * @throws Exception
  197. */
  198. public static function devContract($requestData, int $userId)
  199. {
  200. try {
  201. $demandId = $requestData['demandId'] ?? 0;
  202. $agree = intval($requestData['agree'] ?? 0);
  203. $demand = self::getOne(['id' => $demandId]);
  204. if (!$demand) {
  205. throw new \Exception('该需求不存在');
  206. }
  207. Db::startTrans();
  208. if ($agree) {
  209. if (!in_array($demand->status, [self::STATUS_SIGNING])) {
  210. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能不能签约');
  211. }
  212. //生成两个订单,签约记录
  213. OrderService::createDemandOrder($requestData);
  214. Db::commit();
  215. //给客户发送签约提醒
  216. $msgData = [
  217. 'values' => [
  218. $demand->parent_order_no,
  219. mb_substr($demand->desc, 0, 6),
  220. intval($requestData['formData']['totalCost'] ?? 0),
  221. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_CONTRACT_SIGN]['remark'],
  222. ]
  223. ];
  224. (new EasyWeChatService)->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_CONTRACT_SIGN, $msgData);
  225. } else {
  226. //拒绝签约
  227. //中标去除
  228. $where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
  229. $upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO]);
  230. if (!$upRes) {
  231. exception('更新中标状态失败');
  232. }
  233. //扣除信誉分5分,添加日志
  234. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '放弃签约扣除', 0, AccountLogService::CREDIT_TYPE_CONTRACT_REFUSE, AccountLogService::INC_EXP_EXPEND, $demandId);
  235. AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
  236. //订单状态还原
  237. $demand->status = self::STATUS_BIDDING;
  238. $demand->save();
  239. Db::commit();
  240. }
  241. return $demand;
  242. } catch (\Exception $e) {
  243. Db::rollback();
  244. throw $e;
  245. }
  246. }
  247. /**
  248. * 客户签约
  249. * @param $requestData
  250. * @return mixed
  251. * @throws Exception
  252. */
  253. public static function customerContract($requestData)
  254. {
  255. try {
  256. $demandId = $requestData['demandId'] ?? 0;
  257. $contractType = $requestData['contractType'] ?? 1;
  258. $demand = self::getOne(['id' => $demandId]);
  259. $formData = $requestData['formData'] ?? [];
  260. if (!$demand) {
  261. throw new \Exception('该需求不存在');
  262. }
  263. Db::startTrans();
  264. if (!in_array($demand->status, [self::STATUS_SIGNING])) {
  265. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能签约');
  266. }
  267. //更新签约记录
  268. $winContract = ContractService::updateCustomerContractData($demandId, $formData);
  269. //如果新的合同金额与旧的合同金额不符,则通过修改尾款订单的金额的方式来弥补差价
  270. $firstContract = ContractService::getFirstContract($demandId);
  271. if ($firstContract && $firstContract->total_amount != $winContract->total_amount && $winContract->status2 != ContractService::STATUS_FINISHED) {
  272. $diffAmount = $winContract->total_amount - $firstContract->total_amount;
  273. //更新尾款订单的金额
  274. $finalOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT);
  275. $finalOrder->total_amount += $diffAmount;
  276. $finalOrder->goods_amount += $diffAmount;
  277. $finalOrder->payment_amount += $diffAmount;
  278. $saveRes = $finalOrder->save();
  279. if (!$saveRes) {
  280. exception('弥补订单差价金额失败');
  281. }
  282. }
  283. //获取签约订单用于支付
  284. $order = OrderService::getDemandOrder($demand->parent_order_no, $contractType);
  285. if (!$order) {
  286. throw new \Exception('获取签约订单失败');
  287. }
  288. //如果客户已支付预付款,则直接调用支付成功的处理
  289. if (in_array($order->order_status, [OrderService::ORDER_STATUS_WAIT_SHIP])) {
  290. self::customerContractFinishedDeal(0, $demandId);
  291. }
  292. Db::commit();
  293. return $order;
  294. } catch (\Exception $e) {
  295. Db::rollback();
  296. throw $e;
  297. }
  298. }
  299. /**
  300. * 完成工作
  301. * @param $requestData
  302. * @param $userId
  303. * @return mixed
  304. * @throws Exception
  305. */
  306. public static function completeWork($requestData, $userId)
  307. {
  308. try {
  309. $agree = intval($requestData['agree'] ?? 0);
  310. $demandId = $requestData['demandId'] ?? 0;
  311. $demand = self::getOne(['id' => $demandId]);
  312. if (!$demand) {
  313. throw new \Exception('该需求不存在');
  314. }
  315. Db::startTrans();
  316. if ($agree) {
  317. //完成工作
  318. if (!in_array($demand->status, [self::STATUS_WORKING])) {
  319. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能完成');
  320. }
  321. $demand->status = self::STATUS_ACCEPTING;
  322. $demand->work_status = CommonService::SUCCESS;
  323. $demand->accept_status = CommonService::ONGOING;
  324. $demand->save();
  325. Db::commit();
  326. //给客户发送验收通知
  327. $msgData = [
  328. 'values' => [
  329. $demand->parent_order_no,
  330. mb_substr($demand->desc, 0, 6),
  331. mb_substr($demand->desc, 0, 11),
  332. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT]['remark'],
  333. ]
  334. ];
  335. (new EasyWeChatService())->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT, $msgData);
  336. } else {
  337. //完成失败
  338. //中标去除
  339. $where = ['demand_id' => $demandId, 'user_id' => $userId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
  340. $upRes = DemandBiddingService::where($where)->update(['bidding_status' => DemandBiddingService::STATUS_BIDDING_NO]);
  341. if (!$upRes) {
  342. exception('更新中标状态失败');
  343. }
  344. //扣除信誉分5分,添加日志
  345. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 10, '需求完成失败-信誉分扣除', 0, AccountLogService::CREDIT_TYPE_DEMAND_FAILED, AccountLogService::INC_EXP_EXPEND, $demandId);
  346. AccountService::updateData($userId, 0, 0, -10, 0, $log_res->id);
  347. //冻结余额退回
  348. AccountService::freezeAmountRefund($demandId, $userId);
  349. Db::commit();
  350. //等待客服操作是否取消订单或重新安排开发人员
  351. }
  352. return $demand;
  353. } catch (\Exception $e) {
  354. Db::rollback();
  355. throw $e;
  356. }
  357. }
  358. /**
  359. * 验收通过
  360. * @param $requestData
  361. * @return mixed
  362. * @throws Exception
  363. */
  364. public static function acceptPassed($requestData)
  365. {
  366. try {
  367. $demandId = $requestData['demandId'] ?? 0;
  368. $contractType = $requestData['contractType'] ?? 2;
  369. $agree = $requestData['agree'] ?? 0;
  370. $reason = $requestData['reason'] ?? '';
  371. $demand = self::getOne(['id' => $demandId], ['winBidding']);
  372. if (!$demand) {
  373. throw new \Exception('该需求不存在');
  374. }
  375. Db::startTrans();
  376. if (!in_array($demand->status, [self::STATUS_ACCEPTING])) {
  377. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能验收');
  378. }
  379. if (!$agree) {
  380. //驳回重新工作
  381. $demand->status = self::STATUS_WORKING;
  382. $demand->work_status = CommonService::ONGOING;
  383. $demand->accept_status = CommonService::FAILED;
  384. $saveRes = $demand->save();
  385. if (!$saveRes) {
  386. exception('更新需求状态失败');
  387. }
  388. //给开发者发送验收失败的通知
  389. $msgData = [
  390. 'values' => [
  391. '整体功能验收',
  392. '验收失败',
  393. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT]['remarkFail'],
  394. mb_substr($reason, 0, 16) ?: '需求未按要求完成开发'
  395. ]
  396. ];
  397. (new EasyWeChatService)->sendMsg($demand->winBidding->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT, $msgData);
  398. } else {
  399. //返回订单用于支付尾款
  400. $order = OrderService::getDemandOrder($demand->parent_order_no, $contractType);
  401. if (!$order) {
  402. throw new \Exception('获取签约订单失败');
  403. }
  404. }
  405. Db::commit();
  406. return $order ?? [];
  407. } catch (\Exception $e) {
  408. Db::rollback();
  409. throw $e;
  410. }
  411. }
  412. /**
  413. * 确认收货
  414. * @param $requestData
  415. * @param $userId
  416. * @return mixed
  417. * @throws Exception
  418. */
  419. public static function confirmReceipt($requestData, $userId)
  420. {
  421. try {
  422. $demandId = $requestData['demandId'] ?? 0;
  423. $demand = self::getOne(['id' => $demandId, 'user_id' => $userId]);
  424. if (!$demand) {
  425. throw new \Exception('该需求不存在');
  426. }
  427. Db::startTrans();
  428. if (!in_array($demand->status, [self::STATUS_CONFIRM_RECEIPT])) {
  429. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能确认收货');
  430. }
  431. //订单完成
  432. $demand->status = self::STATUS_FINISHED;
  433. $demand->settle_status = CommonService::ONGOING; //结算中
  434. //返回订单用于支付尾款
  435. $saveRes = $demand->save();
  436. if (!$saveRes) {
  437. exception('更新需求状态失败');
  438. }
  439. Db::commit();
  440. return $demand;
  441. } catch (\Exception $e) {
  442. Db::rollback();
  443. throw $e;
  444. }
  445. }
  446. /**
  447. * 客户签约并支付成功处理需求
  448. * @param $parent_order_no
  449. * @param int $demandId
  450. * @return void
  451. * @throws Exception
  452. */
  453. public static function customerContractFinishedDeal($parent_order_no, int $demandId = 0)
  454. {
  455. $where = function ($query) use ($parent_order_no, $demandId) {
  456. $query->where('parent_order_no', $parent_order_no)->whereOr('id', $demandId);
  457. };
  458. $demand = self::getOne($where, ['winBidding']);
  459. if ($demand) {
  460. //更新客户的签约状态 $demand->id
  461. $contract = ContractService::getWinBiddingContract($demand->id);
  462. //如果客户已经签约过,则跳过防止重复给开发者增加冻结金额
  463. if ($contract->status2 == ContractService::STATUS_FINISHED) {
  464. return;
  465. }
  466. $contract->status2 = ContractService::STATUS_FINISHED;
  467. $contract->save();
  468. //更新需求的状态
  469. $demand->status = self::STATUS_WORKING;
  470. $demand->save();
  471. $userId = $contract->demandBidding->user_id;
  472. //开发者冻结金额增加
  473. $demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FIRST_PAYMENT);
  474. $ratio = (float)config('site.platform_commission_ratio');
  475. $amount = $demandOrder->payment_amount * (1 - $ratio);
  476. $title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益';
  477. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id);
  478. AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id);
  479. //给开发者发送开始工作的消息通知
  480. $msgData = [
  481. 'values' => [
  482. mb_substr($demand->desc, 0, 6),
  483. date('Y.m.d', strtotime('+1 days')) . ' ~ ' . date('Y.m.d', strtotime("+$contract->need_days days")),
  484. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_START]['remark'],
  485. ]
  486. ];
  487. (new EasyWeChatService)->sendMsg($userId, SubscribeMessageService::MSG_TEMP_WORK_START, $msgData);
  488. }
  489. }
  490. /**
  491. * 客户验收完成处理需求
  492. * @param $parent_order_no
  493. * @return void
  494. * @throws Exception
  495. */
  496. public static function customerWorkAcceptFinishedDeal($parent_order_no)
  497. {
  498. $demand = self::getOne(['parent_order_no' => $parent_order_no], ['winBidding']);
  499. if ($demand && $demand->status == self::STATUS_ACCEPTING && $demand->accept_status != CommonService::SUCCESS) {
  500. //更新需求的状态
  501. $demand->status = self::STATUS_CONFIRM_RECEIPT;
  502. $demand->accept_status = CommonService::SUCCESS;
  503. $demand->accept_time = time();
  504. $saveRes = $demand->save();
  505. if (!$saveRes) {
  506. exception('更新验收状态失败');
  507. }
  508. $userId = $demand->winBidding->user_id;
  509. //开发者冻结金额增加
  510. $demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT);
  511. $ratio = (float)config('site.platform_commission_ratio');
  512. $amount = $demandOrder->payment_amount * (1 - $ratio);
  513. $title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益';
  514. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id);
  515. AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id);
  516. //给开发者发送验收结果的消息通知
  517. $msgData = [
  518. 'values' => [
  519. '整体功能验收',
  520. '验收通过',
  521. SubscribeMessageService::MSG_MAP[SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT]['remark'],
  522. '所有功能验收完成'
  523. ]
  524. ];
  525. (new EasyWeChatService)->sendMsg($demand->winBidding->user_id, SubscribeMessageService::MSG_TEMP_WORK_ACCEPT_RESULT, $msgData);
  526. }
  527. }
  528. /**
  529. * 重新投标
  530. * @param $demand
  531. * @return mixed
  532. * @throws Exception
  533. */
  534. public static function resetBiddingDeal($demand)
  535. {
  536. try {
  537. Db::startTrans();
  538. if (in_array($demand->status, [self::STATUS_CONFIRM_RECEIPT, self::STATUS_FINISHED, self::STATUS_CANCEL])) {
  539. throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能重新投标');
  540. }
  541. if (in_array($demand->settle_status, [CommonService::SUCCESS])) {
  542. throw new \Exception('该需求为' . self::SETTLE_STATUS_MAP[$demand->settle_status] . ',不能重新投标');
  543. }
  544. $demandId = $demand->id;
  545. $where = ['demand_id' => $demandId, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN];
  546. $winBidding = DemandBiddingService::where($where)->find();
  547. if ($winBidding) {
  548. //中标去除
  549. $winBidding->bidding_status = DemandBiddingService::STATUS_BIDDING_NO;
  550. $upRes = $winBidding->save();
  551. if (!$upRes) {
  552. exception('更新中标状态失败');
  553. }
  554. $userId = $winBidding->user_id;
  555. //扣除信誉分5分,添加日志
  556. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_CREDIT_SCORE, $userId, 5, '系统自动操作-信誉分扣除', 0, AccountLogService::CREDIT_TYPE_ADMIN_OPERATE, AccountLogService::INC_EXP_EXPEND, $demandId);
  557. AccountService::updateData($userId, 0, 0, -5, 0, $log_res->id);
  558. //冻结余额退回
  559. AccountService::freezeAmountRefund($demandId, $userId);
  560. }
  561. //继续投标,重置状态
  562. $demand->status = self::STATUS_BIDDING;
  563. $demand->work_status = CommonService::NO;
  564. $demand->accept_status = CommonService::NO;
  565. $demand->settle_status = CommonService::NO;
  566. $saveRes = $demand->save();
  567. if (!$saveRes) {
  568. exception('更新需求状态失败');
  569. }
  570. Db::commit();
  571. return $demand;
  572. } catch (\Exception $e) {
  573. Db::rollback();
  574. throw $e;
  575. }
  576. }
  577. /**
  578. * 处理订单收益解冻
  579. */
  580. public static function unfreeze()
  581. {
  582. //
  583. $where = [
  584. 'order_status' => DemandService::STATUS_CONFIRM_RECEIPT,
  585. 'settle_status' => CommonService::ONGOING,
  586. ];
  587. $ratio = (float)config('site.platform_commission_ratio');
  588. Demands::with(['demandContracts', 'winBidding'])->where($where)->chunk(100, function ($demands) use ($ratio) {
  589. foreach ($demands as $demand) {
  590. try {
  591. //开启事务 抛出异常时自动回滚
  592. DB::transaction(function () use ($demand, $ratio) {
  593. $userId = $demand->merchant->user_id;
  594. $show_time = $demand->goodsInfo->show_time ? $demand->goodsInfo->show_time : $demand->goodsInfo->created_at;
  595. Log::info('订单收益解冻:', ['show_time' => $show_time, 'unfreeze_time' => strtotime(date('Y-m-d', strtotime($show_time) + 3 * 3600) . ' 09:00')]);
  596. if (time() > strtotime(date('Y-m-d', strtotime('+1 day', strtotime($show_time) + 3 * 3600)) . ' 09:00')) {
  597. $demand->status = DemandService::STATUS_FINISHED;
  598. $demand->settle_status = CommonService::SUCCESS;
  599. $demand->save();
  600. $amount = ($demand->demandContracts->total_amount ?? 0) * (1 - $ratio);
  601. //写入余额日志
  602. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, -$amount, '需求收益解冻-冻结扣除', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount);
  603. $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_AMOUNT, +$amount, '需求收益解冻-余额增加', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount);
  604. //减去冻结,加到余额里面
  605. AccountService::updateData($userId, $amount, -$amount, 0, 0, $log_res->id);
  606. //发送余额解冻通知
  607. }
  608. });
  609. } catch (\Exception $e) {
  610. Log::info('需求结算处理异常:' . json_encode(['file' => $e->getFile(), 'line' => $e->getLine(), 'error' => $e->getMessage(), 'demand' => $demand], JSON_UNESCAPED_UNICODE));
  611. }
  612. }
  613. });
  614. }
  615. /**
  616. * 审核
  617. * @param $id
  618. * @return void
  619. */
  620. public static function auditPass($id)
  621. {
  622. Db::transaction(function () use ($id) {
  623. $demand = self::getOne(['id' => $id]);
  624. if (!$demand) {
  625. exception('该需求不存在');
  626. }
  627. if ($demand->publish_status == CommonService::SUCCESS) {
  628. exception('已经审核通过,请勿重复审核');
  629. }
  630. //修改审核状态
  631. $demand->status = self::STATUS_BIDDING;
  632. $demand->publish_status = CommonService::SUCCESS;
  633. $saveRes = $demand->save();
  634. if (!$saveRes) {
  635. exception('更新审核状态失败');
  636. }
  637. //发送审核结果-站内消息通知
  638. });
  639. }
  640. }