You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

887 lines
32 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Service;
  3. use App\Commons\Log;
  4. use App\Constants\LogLabel;
  5. use App\Model\Coupon;
  6. use App\Model\CouponRec;
  7. use App\Model\CouponUserUse;
  8. use App\Model\Goods;
  9. use App\Model\Order;
  10. use App\Model\OrderGoods;
  11. use App\Model\OrderMain;
  12. use App\Model\OrderSalesStatistic;
  13. use App\Model\SpecCombination;
  14. use App\Model\Store;
  15. use Exception;
  16. use Hyperf\DbConnection\Db;
  17. use Hyperf\Snowflake\IdGeneratorInterface;
  18. use Hyperf\Utils\ApplicationContext;
  19. use Hyperf\Di\Annotation\Inject;
  20. use App\Service\WxRefundServiceInterface;
  21. use App\Service\UserServiceInterface;
  22. use App\Model\Users;
  23. use App\Constants\SsdbKeysPrefix;
  24. class OrderService implements OrderServiceInterface
  25. {
  26. /**
  27. * @Inject
  28. * @var Log
  29. */
  30. protected $log;
  31. /**
  32. * @Inject
  33. * @var CouponServiceInterface
  34. */
  35. protected $couponService;
  36. /**
  37. * @Inject
  38. * @var WxRefundServiceInterface
  39. */
  40. protected $wxRefundService;
  41. /**
  42. * @Inject
  43. * @var UserServiceInterface
  44. */
  45. protected $userService;
  46. /**
  47. * @Inject
  48. * @var PurchaseLimitServiceInterface
  49. */
  50. protected $purchaseLimitService;
  51. /**
  52. * @inheritDoc
  53. */
  54. public function addOnlineOrder($data)
  55. {
  56. bcscale(6);
  57. $dataMain = $data;
  58. Db::beginTransaction();
  59. try {
  60. // TODO 这个字段后续可能不用了,之前由达达订单号从前端传上来
  61. $dataMain['order_num'] = 'o'.date('YmdHis').mt_rand(1000,9999);
  62. // 计算当前订单可用红包优惠金额
  63. $couponMoney = 0;
  64. $receiveCouponIds = [];
  65. if (isset($data['receive_coupon_ids'])&&$data['receive_coupon_ids']) {
  66. $receiveCouponIds = explode(',', str_replace(',',',',$data['receive_coupon_ids']));
  67. $couponMoney = $this->getCouponAmount($receiveCouponIds, $data['money'], $data['user_id'], $data['market_id']);
  68. }
  69. $dataMain['yhq_money2'] = $couponMoney;
  70. // 获取分布式全局ID
  71. $generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
  72. $dataMain['global_order_id'] = $generator->generate();
  73. // 店铺IDs
  74. $dataMain['store_ids'] = '';
  75. $storeList = json_decode(html_entity_decode($data['store_list']), true);
  76. if (!is_array($storeList)||empty($storeList)) {
  77. Db::rollBack();
  78. return '订单中商品不存在或已失效';
  79. }
  80. // 获取商户IDs
  81. foreach ($storeList as &$item) {
  82. $dataMain['store_ids'] .= empty($dataMain['store_ids']) ? $item['store_id'] : ','.$item['store_id'];
  83. }
  84. // 主订单插入数据
  85. $currentTime = time();
  86. $dataMain['time'] = date('Y-m-d H:i:s', $currentTime);
  87. $dataMain['time_add'] = $currentTime;
  88. $dataMain['pay_time'] = '';
  89. $dataMain['state'] = OrderMain::ORDER_STATE_UNPAY;
  90. $dataMain['code'] = $dataMain['global_order_id'];
  91. $dataMain['jj_note'] = '';
  92. // 主订单模型保存
  93. $orderMain = OrderMain::create($dataMain);
  94. $orderMainId = $orderMain->id;
  95. // 统计订单中所有店铺当日订单数,做店铺订单序号
  96. $countsArr = Order::query()
  97. ->selectRaw('store_id, COUNT(*) AS count')
  98. ->whereIn('store_id', explode(',', $dataMain['store_ids']))
  99. ->where(['type' => OrderMain::ORDER_TYPE_ONLINE])
  100. ->whereBetween('time', [date('Y-m-d 00:00:00'), date('Y-m-d 23:59:59')])
  101. ->groupBy('store_id')
  102. ->get()
  103. ->toArray();
  104. $storeOrderCounts = [];
  105. foreach ($countsArr as $key => &$row) {
  106. $storeOrderCounts[$row['store_id']] = $row['count'];
  107. }
  108. // 循环处理订单总额、子订单总额、商品、商户订单等信息
  109. $orderAmountTotal = 0; # 总订单金额
  110. $orderGoods = [];
  111. foreach ($storeList as $key => &$item) {
  112. // 子订单数据处理
  113. $dataChild = [
  114. 'uniacid' => $data['uniacid'],
  115. 'order_num' => 's'.date('YmdHis', time()) . rand(1111, 9999),
  116. 'user_id' => $orderMain->user_id,
  117. 'store_id' => $item['store_id'],
  118. 'order_main_id' => $orderMainId,
  119. 'state' => OrderMain::ORDER_STATE_UNPAY,
  120. 'tel' => $orderMain->tel,
  121. 'name' => $orderMain->name,
  122. 'address' => $orderMain->address,
  123. 'area' => $orderMain->area,
  124. 'time' => date("Y-m-d H:i:s"),
  125. 'note' => $item['note'] ?? '',
  126. 'delivery_time' => $orderMain->delivery_time,
  127. 'type' => $orderMain->type,
  128. 'lat' => $orderMain->lat,
  129. 'lng' => $orderMain->lng,
  130. 'pay_type' => $orderMain->pay_type,
  131. 'order_type' => $orderMain->order_type,
  132. 'money' => floatval($item['subtotal']),
  133. 'box_money' => floatval($item['box_money']),
  134. 'mj_money' => floatval($item['mj_money']),
  135. 'yhq_money' => floatval($item['yhq_money']),
  136. 'yhq_money2' => floatval($item['yhq_money2']),
  137. 'zk_money' => floatval($item['zk_money']),
  138. 'coupon_id' => $item['coupon_id'],
  139. 'coupon_id2' => $item['coupon_id2'],
  140. 'xyh_money' => floatval($item['xyh_money']),
  141. 'oid' => (isset($storeOrderCounts[$item['store_id']]) ? $item['store_id'] : 0) + 1,
  142. 'time_add' => date("Y-m-d H:i:s"),
  143. 'jj_note' => '',
  144. 'form_id' => '',
  145. 'form_id2' => '',
  146. 'code' => '',
  147. ];
  148. $orderChildId = Order::query()->insertGetId($dataChild);
  149. // 子订单内商品处理
  150. $goodsAmountTotal = 0;
  151. if (!is_array($item['good_list'])||empty($item['good_list'])) {
  152. Db::rollBack();
  153. return '订单商品异常';
  154. }
  155. foreach ($item['good_list'] as &$goods) {
  156. $goodsAmount = bcadd(floatval($goods['money']), floatval($goods['box_money']));
  157. $goodsAmount = bcmul($goodsAmount, $goods['num']);
  158. $goodsAmountTotal = bcadd($goodsAmountTotal, $goodsAmount);
  159. $orderGoods[$goods['id']] = $goods;
  160. $orderGoods[$goods['id']]['uniacid'] = $data['uniacid'];
  161. $orderGoods[$goods['id']]['order_id'] = $orderChildId;
  162. $orderGoods[$goods['id']]['user_id'] = $dataMain['user_id'];
  163. $orderGoods[$goods['id']]['store_id'] = $item['store_id'];
  164. }
  165. // 子订单优惠总额
  166. $discountAmountTotal = bcadd($dataChild['mj_money'], $dataChild['yhq_money']);
  167. $discountAmountTotal = bcadd($discountAmountTotal, $dataChild['yhq_money2']);
  168. $discountAmountTotal = bcadd($discountAmountTotal, $dataChild['zk_money']);
  169. $discountAmountTotal = bcadd($discountAmountTotal, $dataChild['xyh_money']);
  170. $goodsAmountTotal = bcsub($goodsAmountTotal, $discountAmountTotal, 2);
  171. $orderAmountTotal = bcadd($orderAmountTotal, $goodsAmountTotal, 2);
  172. // 校验子订单金额
  173. if ($goodsAmountTotal != $dataChild['money']) {
  174. Db::rollBack();
  175. return '店铺订单总金额错误';
  176. }
  177. }
  178. // 校验库存
  179. foreach ($orderGoods as $Key => &$goodsItem) {
  180. $goodsItem['combination_id'] = intval($goodsItem['combination_id']);
  181. // 存在规格,则去规格处查库存
  182. $goods = [];
  183. if ($goodsItem['combination_id'] > 0) {
  184. $combination = SpecCombination::query()
  185. ->select(['good_id AS id', 'number AS inventory'])
  186. ->where(['id' => $goodsItem['combination_id']])
  187. ->first()
  188. ->toArray();
  189. $goods = Goods::query()
  190. ->select(['id', 'name', 'is_max'])
  191. ->where(['id' => $combination['id']])
  192. ->first()
  193. ->toArray();
  194. $goods['inventory'] = $combination['inventory'];
  195. } else {
  196. $goods = Goods::query()
  197. ->select(['id', 'name', 'is_max', 'inventory'])
  198. ->where(['id' => $goodsItem['good_id']])
  199. ->first()
  200. ->toArray();
  201. }
  202. if (!$goods) {
  203. Db::rollBack();
  204. return '缺少商品';
  205. }
  206. if($goodsItem['num'] > $goods['inventory'] && $goods['is_max'] != Goods::INVENTORY_NOLIMIT){
  207. Db::rollBack();
  208. return '商品 '.$goods->name.' 库存不足!';
  209. }
  210. }
  211. // 校验总订单金额
  212. $deliveryAmount = 0; # 配送费用
  213. if($dataMain['order_type'] == OrderMain::ORDER_TYPE_ONLINE){
  214. $deliveryAmount = $dataMain['dada_fee'];
  215. }
  216. $orderAmountTotal = bcadd($orderAmountTotal, $deliveryAmount);
  217. # 总订单优惠总额
  218. $discountAmountTotal = bcadd($dataMain['mj_money'], $dataMain['yhq_money']);
  219. $discountAmountTotal = bcadd($discountAmountTotal, $dataMain['yhq_money2']);
  220. $discountAmountTotal = bcadd($discountAmountTotal, $dataMain['zk_money']);
  221. $discountAmountTotal = bcadd($discountAmountTotal, $dataMain['xyh_money']);
  222. $orderAmountTotal = bcsub($orderAmountTotal, $discountAmountTotal, 2);
  223. if ($orderAmountTotal != bcsub(bcadd($dataMain['money'], $deliveryAmount), $discountAmountTotal, 2)) {
  224. Db::rollBack();
  225. return '订单总金额错误';
  226. }
  227. // 添加订单商品
  228. $tempGoods = $orderGoods;
  229. $orderGoods = [];
  230. foreach ($tempGoods as $key => &$value) {
  231. $goodsTemp['good_id'] = $value['good_id'];
  232. $goodsTemp['img'] = $value['logo'];
  233. $goodsTemp['number'] = $value['num'];
  234. $goodsTemp['order_id'] = $value['order_id'];
  235. $goodsTemp['name'] = $value['name'];
  236. $goodsTemp['money'] = $value['money'];
  237. $goodsTemp['dishes_id'] = $value['dishes_id'];
  238. $goodsTemp['spec'] = $value['spec'];
  239. $goodsTemp['is_qg'] = $value['is_qg'];
  240. $goodsTemp['good_unit'] = $value['good_unit'];
  241. $goodsTemp['uniacid'] = $value['uniacid'];
  242. $goodsTemp['combination_id'] = $value['combination_id'];
  243. $orderGoods[] = $goodsTemp;
  244. }
  245. $addOrderGoods = OrderGoods::query()->insert($orderGoods);
  246. if (!$addOrderGoods) {
  247. Db::rollBack();
  248. return '订单商品异常';
  249. }
  250. //判断是否有购买特价商品
  251. $this->purchaseLimitService->ssdbPurchaseRecord($orderGoods,$data['user_id'],$dataMain['global_order_id']);
  252. // 修改总订单金额,金额是计算来的
  253. // TODO 这部分其实可以结合处理优化一下,循环前后关联处理太多
  254. $updateOrderMain = OrderMain::query()->where(['id' => $orderMainId])->update(['money' => $orderAmountTotal, 'total_money' => $dataMain['money']]);
  255. if (!$updateOrderMain) {
  256. Db::rollBack();
  257. return '订单总金额记录失败';
  258. }
  259. // 处理红包的使用
  260. $canUseCoupons = CouponRec::select(['id', 'user_id', 'number', 'number_remain', 'system_coupon_user_id'])
  261. ->whereIn('id', $receiveCouponIds)
  262. ->get()->toArray();
  263. if (is_array($canUseCoupons)&&!empty($canUseCoupons)) {
  264. # 使用记录、更新当前优惠券
  265. foreach ($canUseCoupons as $key => &$coupon) {
  266. $couponUse = [
  267. 'user_id' => $coupon['user_id'],
  268. 'user_receive_id' => $coupon['id'],
  269. 'system_coupon_id' => $coupon['system_coupon_user_id'],
  270. 'order_main_id' => $orderMainId,
  271. 'use_time' => $currentTime,
  272. 'return_time' => 0,
  273. 'number' => 1,
  274. 'status' => 1,
  275. 'update_time' => 0,
  276. ];
  277. var_dump('$couponUse',$couponUse);
  278. $insertRes = CouponUserUse::query()->insert($couponUse);
  279. if ($insertRes) {
  280. $numberRemain = $coupon['number_remain'] - 1;
  281. if ($numberRemain == 0) {
  282. $status = 2;
  283. } elseif ($numberRemain > 0 && $numberRemain < $coupon['number']) {
  284. $status = 1;
  285. } elseif ($numberRemain == $coupon['number']) {
  286. $status = 0;
  287. }
  288. $upRes = CouponRec::query()->where(['id' => $coupon['id']])->update(['number_remain' => $numberRemain, 'status' => $status]);
  289. if (!$upRes) {
  290. Db::rollBack();
  291. return '优惠券使用失败';
  292. }
  293. // 缓存使用记录
  294. $usedRes = $this->couponService->cacheTodayCouponUsed($coupon['user_id'], $coupon['system_coupon_user_id'], $coupon['id']);
  295. if (!$usedRes) {
  296. Db::rollBack();
  297. return '优惠券使用失败';
  298. }
  299. } else {
  300. Db::rollBack();
  301. return '优惠券使用失败';
  302. }
  303. }
  304. }
  305. Db::commit();
  306. return $orderMainId;
  307. } catch (Exception $e) {
  308. $this->log->event(
  309. LogLabel::ORDER_LOG,
  310. ['message' => $e->getMessage()]
  311. );
  312. Db::rollBack();
  313. return $e->getMessage();
  314. }
  315. }
  316. /**
  317. * @inheritDoc
  318. */
  319. public function addOfflineOrder($data)
  320. {
  321. Db::beginTransaction();
  322. try {
  323. // 主订单数据
  324. $dataMain = [];
  325. // 获取分布式全局ID
  326. $generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
  327. $globalRrderId = $generator->generate();
  328. // 主订单插入数据
  329. $currentTime = time();
  330. $dataMain = [
  331. 'delivery_no' => '',
  332. 'dada_fee' => 0,
  333. 'market_id' => 0,
  334. 'box_money' => 0,
  335. 'ps_money' => 0,
  336. 'mj_money' => 0,
  337. 'xyh_money' => 0,
  338. 'yhq_money' => 0,
  339. 'yhq_money2' => 0,
  340. 'zk_money' => 0,
  341. 'tel' => '',
  342. 'name' => '',
  343. 'address' => '',
  344. 'area' => '',
  345. 'lat' => '',
  346. 'lng' => '',
  347. 'note' => '',
  348. 'form_id' => '',
  349. 'form_id2' => '',
  350. 'delivery_time' => '',
  351. 'order_type' => 0,
  352. 'coupon_id' => 0,
  353. 'coupon_id2' => 0,
  354. 'store_list' => '',
  355. 'receive_coupon_ids' => '',
  356. 'type' => OrderMain::ORDER_TYPE_OFFLINE,
  357. 'time' => date('Y-m-d H:i:s', $currentTime),
  358. 'time_add' => $currentTime,
  359. 'pay_time' => '',
  360. 'pay_type' => OrderMain::ORDER_PAY_WX,
  361. 'state' => OrderMain::ORDER_STATE_UNPAY,
  362. 'dm_state' => OrderMain::ORDER_STATE_UNPAY,
  363. 'code' => $globalRrderId,
  364. 'jj_note' => '',
  365. 'uniacid' => 2,
  366. 'order_num' => 'dm'.date('YmdHis') . mt_rand(1000, 9999),
  367. 'money' => $data['money'],
  368. 'user_id' => $data['user_id'],
  369. 'store_ids' => $data['store_id'],
  370. 'global_order_id' => $globalRrderId,
  371. ];
  372. // 主订单模型保存
  373. $orderMain = OrderMain::create($dataMain);
  374. $orderMainId = $orderMain->id;
  375. // 子订单模型保存
  376. $dataChild = [
  377. 'uniacid' => 1,
  378. 'order_num' => 's'.date('YmdHis') . mt_rand(1000, 9999),
  379. 'user_id' => $orderMain->user_id,
  380. 'store_id' => $data['store_id'],
  381. 'order_main_id' => $orderMainId,
  382. 'state' => OrderMain::ORDER_STATE_UNPAY,
  383. 'dm_state' => OrderMain::ORDER_STATE_UNPAY,
  384. 'tel' => $orderMain->tel,
  385. 'name' => $orderMain->name,
  386. 'address' => $orderMain->address,
  387. 'area' => $orderMain->area,
  388. 'time' => date("Y-m-d H:i:s"),
  389. 'note' => '',
  390. 'delivery_time' => $orderMain->delivery_time,
  391. 'type' => $orderMain->type,
  392. 'lat' => $orderMain->lat,
  393. 'lng' => $orderMain->lng,
  394. 'pay_type' => $orderMain->pay_type,
  395. 'order_type' => $orderMain->order_type,
  396. 'money' => $data['money'],
  397. 'box_money' => 0,
  398. 'mj_money' => 0,
  399. 'yhq_money' => 0,
  400. 'yhq_money2' => 0,
  401. 'zk_money' => 0,
  402. 'coupon_id' => 0,
  403. 'coupon_id2' => 0,
  404. 'xyh_money' => 0,
  405. 'time_add' => date("Y-m-d H:i:s"),
  406. 'jj_note' => '',
  407. 'form_id' => '',
  408. 'form_id2' => '',
  409. 'code' => '',
  410. ];
  411. $orderChildId = Order::query()->insertGetId($dataChild);
  412. Db::commit();
  413. return $orderMainId;
  414. } catch (Exception $e) {
  415. $this->log->event(
  416. LogLabel::ORDER_LOG,
  417. ['message' => $e->getMessage()]
  418. );
  419. Db::rollBack();
  420. return '购买失败';
  421. }
  422. }
  423. /**
  424. * 计算和校验当前订单可用红包及金额
  425. * @param $couponIds
  426. * @param $orderAmount
  427. * @param $userId
  428. * @param $marketId
  429. * @return int|string
  430. * @throws Exception
  431. */
  432. protected function getCouponAmount($couponIds, $orderAmount, $userId, $marketId)
  433. {
  434. // 用户当前订单可用优惠券
  435. $couponsCanUse = $this->couponService->getOrderCanUseCoupons(
  436. $orderAmount,
  437. $marketId,
  438. $userId,
  439. [
  440. 'receive.id',
  441. 'receive.user_id',
  442. 'receive.number',
  443. 'receive.number_remain',
  444. 'receive.system_coupon_user_id',
  445. 'coupon.discounts',
  446. 'coupon.discount_type',
  447. ]
  448. );
  449. $couponCanUseIds = array_column($couponsCanUse, 'id');
  450. $couponCanUseIds = array_intersect($couponCanUseIds, $couponIds);
  451. $couponCannotUseIds = array_diff($couponIds, $couponCanUseIds);
  452. if (empty($couponCanUseIds)||!empty($couponCannotUseIds)) {
  453. throw new Exception('您的订单中有优惠券已经失效');
  454. }
  455. // 计算红包折扣金额
  456. $couponMoney = 0;
  457. foreach ($couponsCanUse as $key => $coupon) {
  458. if (!in_array($coupon->id, $couponIds)) {
  459. continue;
  460. }
  461. if ($coupon->discount_type == Coupon::DISCOUNT_TYPE_CASH) {
  462. $couponMoney = bcadd($couponMoney, $coupon->discounts, 2);
  463. } elseif ($coupon->discount_type == Coupon::DISCOUNT_TYPE_RATE) {
  464. $discountRate = bcdiv($coupon->discounts,10);
  465. $discountRate = bcsub(1,$discountRate);
  466. $discountMoney = bcmul($orderAmount, $discountRate);
  467. $couponMoney = bcadd($couponMoney, $discountMoney, 2);
  468. }
  469. }
  470. return $couponMoney;
  471. }
  472. /**
  473. * @inheritDoc
  474. */
  475. public function existsByGlobalOrderId($global_order_id)
  476. {
  477. return OrderMain::query()->where(['order_num' => $global_order_id])->value('id');
  478. }
  479. /**
  480. * @inheritDoc
  481. */
  482. public function onlineCompleted($global_order_id)
  483. {
  484. Db::beginTransaction();
  485. try {
  486. // 主订单状态更新
  487. $orderMain = OrderMain::query()
  488. ->where(['global_order_id' => $global_order_id, 'state' => OrderMain::ORDER_STATE_DELIVERY])
  489. ->first();
  490. if (empty($orderMain)) {
  491. Db::rollBack();
  492. return false;
  493. }
  494. $orderMain->state = OrderMain::ORDER_STATE_COMPLETE;
  495. $orderMain->save();
  496. // 子订单状态更新
  497. $upChild = Order::query()
  498. ->where(['order_main_id' => $orderMain->id])
  499. ->update(['state' => OrderMain::ORDER_STATE_COMPLETE]);
  500. Db::commit();
  501. return true;
  502. } catch (Exception $e) {
  503. $this->log->event(LogLabel::ONLINE_COMPLETE_LOG, ['exception' => $e->getMessage()]);
  504. Db::rollBack();
  505. return false;
  506. }
  507. }
  508. /**
  509. * @inheritDoc
  510. */
  511. public function onlinePaid($global_order_id)
  512. {
  513. Db::beginTransaction();
  514. try {
  515. // 查询订单
  516. $orderMain = OrderMain::query()
  517. ->where([
  518. 'global_order_id' => $global_order_id,
  519. 'type' => OrderMain::ORDER_TYPE_ONLINE
  520. ])
  521. ->first();
  522. // 修改订单、子订单状态
  523. $currentTime = time();
  524. $orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
  525. $orderMain->time_pay = $currentTime;
  526. $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
  527. $orderMain->save();
  528. $upOrder = Order::query()
  529. ->where(['order_main_id' => $orderMain->id])
  530. ->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]);
  531. // 更新商户销量
  532. $upStoreScore = Store::query()
  533. ->whereIn('id', explode(',', $orderMain->store_ids))
  534. ->update(['score' => Db::raw('score+1')]);
  535. // 更新商品库存和销量
  536. $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time'])
  537. ->where(['order_main_id' => $orderMain->id])
  538. ->get()
  539. ->toArray();
  540. $orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id'])
  541. ->whereIn('order_id', array_values(array_column($orders, 'id')))
  542. ->get()
  543. ->toArray();
  544. foreach ($orderGoods as $key => &$goodsItem) {
  545. $goods = Goods::find($goodsItem['id']);
  546. // 库存处理,有规格
  547. if ($goodsItem['combination_id']) {
  548. $combination = SpecCombination::find($goodsItem['combination_id']);
  549. $combination->number = $combination->number - $goodsItem['number'];
  550. $combination->save();
  551. } else {
  552. $goods->inventory = $goods->inventory - $goodsItem['number'];
  553. }
  554. $goods->sales = $goods->sales - $goodsItem['number'];
  555. $goods->save();
  556. }
  557. // 月销流水
  558. $statistics = [];
  559. foreach ($orders as $key => &$order) {
  560. $statistics[] = [
  561. 'money' => $order['money'],
  562. 'user_id' => $order['user_id'],
  563. 'store_id' => $order['store_id'],
  564. 'market_id' => $orderMain->market_id,
  565. 'order_id' => $order['id'],
  566. 'createtime' => strtotime($order['pay_time']),
  567. ];
  568. }
  569. if (is_array($statistics) && !empty($statistics)) {
  570. $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics);
  571. }
  572. Db::commit();
  573. return true;
  574. } catch (Exception $e) {
  575. $this->log->event(LogLabel::ONLINE_PAID_LOG, ['exception' => $e->getMessage()]);
  576. Db::rollBack();
  577. return false;
  578. }
  579. }
  580. /**
  581. * @inheritDoc
  582. */
  583. public function offlinePaid($global_order_id)
  584. {
  585. Db::beginTransaction();
  586. try {
  587. // 主订单状态更新
  588. $orderMain = OrderMain::query()
  589. ->where(['global_order_id' => $global_order_id, 'type' => OrderMain::ORDER_TYPE_OFFLINE])
  590. ->first();
  591. if (empty($orderMain)) {
  592. $this->log->event(
  593. LogLabel::PAY_NOTIFY_WXMINI,
  594. ['order_not_found' => $global_order_id]
  595. );
  596. Db::rollBack();
  597. return false;
  598. }
  599. $currentTime = time();
  600. $orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
  601. $orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE;
  602. $orderMain->time_pay = $currentTime;
  603. $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
  604. $orderMain->save();
  605. // 子订单状态更新
  606. $upOrder = Order::query()
  607. ->where(['order_main_id' => $orderMain->id])
  608. ->update([
  609. 'state' => OrderMain::ORDER_STATE_UNTAKE,
  610. 'dm_state' => OrderMain::ORDER_STATE_UNTAKE,
  611. 'pay_time' => date('Y-m-d H:i:s', $currentTime)
  612. ]);
  613. Db::commit();
  614. return true;
  615. } catch (Exception $e) {
  616. $this->log->event(LogLabel::OFFLINE_PAID_LOG, ['exception' => $e->getMessage()]);
  617. Db::rollBack();
  618. return false;
  619. }
  620. }
  621. /**
  622. * @inheritDoc
  623. */
  624. public function onlineCancel($order_id){
  625. OrderMain::where('id',$order_id)
  626. ->update(['state' => OrderMain::ORDER_STATE_CANCEL]);
  627. //撤销redis 用券记录
  628. $res = $this->couponService->refundOrderCoupons($order_id);
  629. //撤销特价商品购买记录
  630. $res = $this->purchaseLimitService->delSsdbPurchaseRecord($order_id);
  631. return $res;
  632. }
  633. /**
  634. * @inheritDoc
  635. */
  636. public function onlineRefund($global_order_id)
  637. {
  638. Db::beginTransaction();
  639. try {
  640. $time = time();
  641. // 主订单状态更新
  642. $orderMain = OrderMain::query()
  643. ->select('id','global_order_id','state','pay_type','user_id','money')
  644. ->where(['global_order_id' => $global_order_id, 'state' => OrderMain::ORDER_STATE_REFUNDING])
  645. ->first();
  646. if (empty($orderMain)) {
  647. Db::rollBack();
  648. return false;
  649. }
  650. $orderMain->state = OrderMain::ORDER_STATE_REFUNDED;
  651. if(!$orderMain->save()){
  652. Db::rollBack();
  653. return false;
  654. };
  655. // 子订单状态更新
  656. $upChild = Order::query()
  657. ->where('order_main_id' , $orderMain->id)
  658. ->where('state',OrderMain::ORDER_STATE_REFUNDING)
  659. ->update(['state' => OrderMain::ORDER_STATE_REFUNDED]);
  660. if(empty($upChild)){
  661. Db::rollBack();
  662. return false;
  663. }
  664. if($orderMain->pay_type == OrderMain::ORDER_PAY_WX){
  665. $data = [
  666. 'global_order_id' => $global_order_id,
  667. 'money' => $orderMain->money
  668. ];
  669. // 微信支付 微信退款
  670. $refundRes = $this->wxRefundService->wxPayRefund($data);
  671. var_dump($refundRes);
  672. if(
  673. empty($refundRes)
  674. || !isset($refundRes['result_code'])
  675. || $refundRes['result_code'] != 'SUCCESS'
  676. ){
  677. Db::rollBack();
  678. return false;
  679. };
  680. /* --- 退款成功 --- */
  681. $orderMain = $orderMain->fresh();
  682. if(empty($orderMain->refund_time)){
  683. // 添加退款时间
  684. $orderMain->refund_time = time();
  685. $orderMain->save();
  686. // 退款返还优惠券
  687. $this->couponService->orderRefundCoupons($orderMain->global_order_id);
  688. // 删除特价商品缓存
  689. $this->purchaseLimitService->delSsdbPurchaseRecord($orderMain->id);
  690. // 添加用户的流水
  691. $this->financialService->userByOLOrderRefund($orderMain->user_id, $orderMain->global_order_id, $orderMain->money);
  692. }
  693. }else if($orderMain->pay_type == OrderMain::ORDER_PAY_BALANCE){
  694. // 余额支付 退款到用户余额
  695. // if($this->userService->userWallet($orderMain->user_id,$orderMain->money,Users::WALLET_TYPE_INC)){
  696. // Db::rollBack();
  697. // return false;
  698. // };
  699. // 返还优惠券
  700. // $this->couponService->orderRefundCoupon($global_order_id);
  701. // 删除特价商品缓存
  702. // $this->orderService->clearTodayGoodPurchase($orderMain->user_id,1);
  703. // 添加用户流水
  704. // $this->financialService->userByOLOrderRefund($orderMain->user_id, $orderMain->global_order_id, $orderMain->money);
  705. }
  706. Db::commit();
  707. return true;
  708. } catch (\Exception $e) {
  709. $this->log->event(LogLabel::ORDER_LOG, ['msg'=> '订单退款','exception' => $e->getMessage()]);
  710. Db::rollBack();
  711. return false;
  712. }
  713. }
  714. /**
  715. * 订单退款失败
  716. * 回退订单状态
  717. */
  718. public function onlineRefundFail($global_order_id)
  719. {
  720. Db::beginTransaction();
  721. try {
  722. $time = time();
  723. // 主订单状态更新
  724. $orderMain = OrderMain::query()
  725. ->select('id','global_order_id','state','pay_type')
  726. ->where(['global_order_id' => $global_order_id, 'state' => OrderMain::ORDER_STATE_REFUNDED])
  727. ->first();
  728. if (empty($orderMain)) {
  729. Db::rollBack();
  730. return false;
  731. }
  732. $orderMain->state = OrderMain::ORDER_STATE_REFUNDING;
  733. $upOrderMain = $orderMain->save();
  734. // 子订单状态更新
  735. $upChild = Order::query()
  736. ->where('order_main_id' , $orderMain->id)
  737. ->where('state',OrderMain::ORDER_STATE_REFUNDED)
  738. ->update(['state' => OrderMain::ORDER_STATE_REFUNDING]);
  739. if(empty($upChild)){
  740. Db::rollBack();
  741. return false;
  742. }
  743. Db::commit();
  744. return true;
  745. } catch (Exception $e) {
  746. $this->log->event(LogLabel::ORDER_LOG, ['msg'=> '订单退款失败时处理状态9->8 ','exception' => $e->getMessage()]);
  747. Db::rollBack();
  748. return false;
  749. }
  750. }
  751. /**
  752. * 删除特价商品缓存
  753. */
  754. public function clearTodayGoodPurchase($userId, $goodId)
  755. {
  756. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  757. return $ssdb->exec('del', SsdbKeysPrefix::PURCHASE_RECORD. date('Ymd') .'_'.$userId, $goodId);
  758. }
  759. }