CashierOrderServices.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\order\cashier;
  12. use app\jobs\activity\StorePromotionsJob;
  13. use app\jobs\user\MicroPayOrderJob;
  14. use app\services\activity\collage\UserCollagePartakeServices;
  15. use app\services\activity\collage\UserCollageServices;
  16. use app\services\BaseServices;
  17. use app\services\activity\coupon\StoreCouponUserServices;
  18. use app\services\activity\coupon\StoreCouponIssueServices;
  19. use app\services\order\StoreCartServices;
  20. use app\services\order\StoreOrderCartInfoServices;
  21. use app\services\order\StoreOrderComputedServices;
  22. use app\services\order\StoreOrderCreateServices;
  23. use app\services\order\StoreOrderSuccessServices;
  24. use app\services\pay\PayServices;
  25. use app\services\pay\YuePayServices;
  26. use app\services\product\branch\StoreBranchProductServices;
  27. use app\services\product\product\StoreProductServices;
  28. use app\services\product\sku\StoreProductAttrValueServices;
  29. use app\services\store\SystemStoreStaffServices;
  30. use app\services\user\UserAddressServices;
  31. use app\services\user\UserServices;
  32. use crmeb\services\CacheService;
  33. use crmeb\traits\OptionTrait;
  34. use think\exception\ValidateException;
  35. /**
  36. * 收银台订单
  37. * Class CashierOrderServices
  38. * @package app\services\order\cashier
  39. */
  40. class CashierOrderServices extends BaseServices
  41. {
  42. use OptionTrait;
  43. //余额支付
  44. const YUE_PAY = 1;
  45. //线上支付
  46. const ONE_LINE_PAY = 2;
  47. //现金支付
  48. const CASH_PAY = 3;
  49. /**
  50. * 计算某个门店中收银台的金额
  51. * @param int $uid
  52. * @param int $storeId
  53. * @param array $cartIds
  54. * @param bool $integral
  55. * @param bool $coupon
  56. * @return array
  57. * @throws \think\db\exception\DataNotFoundException
  58. * @throws \think\db\exception\DbException
  59. * @throws \think\db\exception\ModelNotFoundException
  60. */
  61. public function computeOrder(int $uid, int $storeId, array $cartIds, bool $integral = false, bool $coupon = false, array $userInfo = [], int $coupon_id = 0, bool $new = false)
  62. {
  63. if (!$userInfo && $uid) {
  64. /** @var UserServices $userService */
  65. $userService = app()->make(UserServices::class);
  66. $userInfo = $userService->getUserInfo($uid);
  67. if (!$userInfo) {
  68. throw new ValidateException('用户不存在');
  69. }
  70. $userInfo = $userInfo->toArray();
  71. }
  72. /** @var StoreCartServices $cartServices */
  73. $cartServices = app()->make(StoreCartServices::class);
  74. //获取购物车信息
  75. $cartGroup = $cartServices->getUserProductCartListV1($uid, $cartIds, $new, [], 4, $storeId, $coupon_id);
  76. $cartInfo = array_merge($cartGroup['valid'], $cartGroup['giveCartList']);
  77. if (!$cartInfo) {
  78. throw new ValidateException('购物车暂无货物!');
  79. }
  80. $deduction = $cartGroup['deduction'];
  81. $promotionsDetail = [];
  82. $promotions = $cartGroup['promotions'] ?? [];
  83. if ($promotions) {
  84. foreach ($promotions as $key => $value) {
  85. if (isset($value['details']['sum_promotions_price']) && $value['details']['sum_promotions_price']) {
  86. $promotionsDetail[] = ['id' => $value['id'], 'name' => $value['name'], 'title' => $value['title'], 'desc' => $value['desc'], 'promotions_price' => $value['details']['sum_promotions_price'], 'promotions_type' => $value['promotions_type']];
  87. }
  88. }
  89. if ($promotionsDetail) {
  90. $typeArr = array_column($promotionsDetail, 'promotions_type');
  91. array_multisort($typeArr, SORT_ASC, $promotionsDetail);
  92. }
  93. }
  94. /** @var StoreOrderComputedServices $computeOrderService */
  95. $computeOrderService = app()->make(StoreOrderComputedServices::class);
  96. $sumPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'sum_price');//获取订单原总金额
  97. $totalPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'truePrice');//获取订单svip、用户等级优惠之后总金额
  98. $costPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'costPrice');//获取订单成本价
  99. $vipPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'vip_truePrice');//获取订单会员优惠金额
  100. $promotionsPrice = $computeOrderService->getOrderSumPrice($cartInfo, 'promotions_true_price');//优惠活动优惠
  101. $is_cashier_yue_pay_verify = (int)sys_config('is_cashier_yue_pay_verify'); // 收银台余额支付是否需要验证【是/否】
  102. $payPrice = (float)$totalPrice;
  103. $couponPrice = floatval($cartGroup['couponPrice'] ?? 0);
  104. if ($couponPrice < $payPrice) {
  105. $payPrice = (float)bcsub((string)$payPrice, (string)$couponPrice, 2);
  106. } else {
  107. $couponPrice = $payPrice;
  108. $payPrice = 0;
  109. }
  110. $SurplusIntegral = $usedIntegral = 0;
  111. $deductionPrice = '0';
  112. //使用积分
  113. if ($userInfo && $integral) {
  114. [
  115. $payPrice,
  116. $deductionPrice,
  117. $usedIntegral,
  118. $SurplusIntegral
  119. ] = $computeOrderService->useIntegral(true, $userInfo, $payPrice, [
  120. 'offlinePostage' => sys_config('offline_postage'),
  121. 'integralRatio' => sys_config('integral_ratio')
  122. ]);
  123. }
  124. return [
  125. 'payPrice' => floatval($payPrice),//支付金额
  126. 'vipPrice' => floatval($vipPrice),//会员优惠金额
  127. 'totalPrice' => floatval($totalPrice),//会员优惠后订单金额
  128. 'costPrice' => floatval($costPrice),//成本金额
  129. 'sumPrice' => floatval($sumPrice),//订单总金额
  130. 'couponPrice' => $couponPrice,//优惠券金额
  131. 'promotionsPrice' => floatval($promotionsPrice),//优惠活动金额
  132. 'promotionsDetail' => $promotionsDetail,//优惠
  133. 'deductionPrice' => floatval($deductionPrice),//积分抵扣多少钱
  134. 'surplusIntegral' => $SurplusIntegral,//抵扣了多少积分
  135. 'usedIntegral' => $usedIntegral,//使用了多少积分
  136. 'deduction' => $deduction,
  137. 'cartInfo' => $cartInfo,//购物列表
  138. 'is_cashier_yue_pay_verify' => $is_cashier_yue_pay_verify,//收银台余额支付验证 1 验证 0不验证
  139. 'cartGroup' => $cartGroup//计算结果
  140. ];
  141. }
  142. /**
  143. * 收银台用户优惠券
  144. * @param int $uid
  145. * @param int $storeId
  146. * @param array $cartIds
  147. * @return mixed
  148. * @throws \think\db\exception\DataNotFoundException
  149. * @throws \think\db\exception\DbException
  150. * @throws \think\db\exception\ModelNotFoundException
  151. */
  152. public function getCouponList(int $uid, int $storeId, array $cartIds)
  153. {
  154. /** @var StoreCartServices $cartService */
  155. $cartService = app()->make(StoreCartServices::class);
  156. $cart = $cartService->getUserCartList($uid, 1, $cartIds, $storeId, 0, 4, 0, 0, 0, false);
  157. $cartInfo = $cart['valid'];
  158. if (!$cartInfo) {
  159. throw new ValidateException('购物车暂无货物!');
  160. }
  161. /** @var StoreCouponissueServices $couponIssueServices */
  162. $couponIssueServices = app()->make(StoreCouponissueServices::class);
  163. return $couponIssueServices->getCanUseCoupon($uid, $cartInfo, $cart['promotions'] ?? [], $storeId, false);
  164. }
  165. /**
  166. * 二位数组冒泡排序
  167. * @param array $arr
  168. * @param string $key
  169. * @return array
  170. */
  171. protected function mpSort(array $arr, string $key)
  172. {
  173. for ($i = 0; $i < count($arr); $i++) {
  174. for ($j = $i; $j < count($arr); $j++) {
  175. if ($arr[$i][$key] > $arr[$j][$key]) {
  176. $temp = $arr[$i];
  177. $arr[$i] = $arr[$j];
  178. $arr[$j] = $temp;
  179. }
  180. }
  181. }
  182. return $arr;
  183. }
  184. /**
  185. * 自动解析扫描二维码
  186. * @param string $barCode
  187. * @param int $storeId
  188. * @param int $uid
  189. * @param int $staff_id
  190. * @param int $touristUid
  191. * @return array
  192. * @throws \think\db\exception\DataNotFoundException
  193. * @throws \think\db\exception\DbException
  194. * @throws \think\db\exception\ModelNotFoundException
  195. */
  196. public function getAnalysisCode(string $barCode, int $storeId, int $uid, int $staff_id, int $touristUid = 0)
  197. {
  198. /** @var UserServices $userService */
  199. $userService = app()->make(UserServices::class);
  200. $userInfo = $userService->get(['bar_code' => $barCode], ['uid', 'avatar', 'nickname', 'now_money', 'integral']);
  201. if ($userInfo) {
  202. return ['userInfo' => $userInfo->toArray()];
  203. } else {
  204. /** @var SystemStoreStaffServices $staffServices */
  205. $staffServices = app()->make(SystemStoreStaffServices::class);
  206. $staffServices->getStaffInfo($staff_id);
  207. /** @var StoreProductAttrValueServices $storeProductAttrService */
  208. $storeProductAttrService = app()->make(StoreProductAttrValueServices::class);
  209. $attProductInfo = $storeProductAttrService->getAttrByBarCode((string)$barCode);
  210. if (!$attProductInfo) {
  211. throw new ValidateException('没有扫描到商品');
  212. }
  213. /** @var StoreProductServices $productService */
  214. $productService = app()->make(StoreProductServices::class);
  215. $productInfo = $productService->get(['is_show' => 1, 'is_del' => 0, 'id' => $attProductInfo->product_id], [
  216. 'image', 'store_name', 'store_info', 'bar_code', 'price', 'id as product_id', 'id'
  217. ]);
  218. if (!$productInfo) {
  219. throw new ValidateException('商品未查到');
  220. }
  221. /** @var StoreBranchProductServices $storeProductService */
  222. $storeProductService = app()->make(StoreBranchProductServices::class);
  223. if (!$storeProductService->count(['store_id' => $storeId, 'product_id' => $attProductInfo->product_id])) {
  224. throw new ValidateException('该商品在此门店不存在');
  225. }
  226. /** @var StoreProductAttrValueServices $valueService */
  227. $valueService = app()->make(StoreProductAttrValueServices::class);
  228. $valueInfo = $valueService->getOne(['unique' => $attProductInfo->unique]);
  229. if (!$valueInfo) {
  230. throw new ValidateException('商品属性不存在');
  231. }
  232. $productInfo = $productInfo->toArray();
  233. $productInfo['attr_value'] = [
  234. 'ot_price' => $valueInfo->ot_price,
  235. 'price' => $valueInfo->price,
  236. 'sales' => $valueInfo->sales,
  237. 'vip_price' => $valueInfo->vip_price,
  238. 'stock' => $attProductInfo->stock,
  239. ];
  240. if ($uid || $touristUid) {
  241. /** @var StoreCartServices $cartService */
  242. $cartService = app()->make(StoreCartServices::class);
  243. $cartService->setItem('store_id', $storeId);
  244. $cartService->setItem('tourist_uid', $touristUid);
  245. $cartId = $cartService->addCashierCart($uid, $attProductInfo->product_id, 1, $attProductInfo->unique, $staff_id);
  246. $cartService->reset();
  247. if (!$cartId) {
  248. throw new ValidateException('自动添加购物车失败');
  249. }
  250. } else {
  251. $cartId = 0;
  252. }
  253. return ['productInfo' => $productInfo, 'cartId' => $cartId];
  254. }
  255. }
  256. /**
  257. * 生成订单
  258. * @param int $uid
  259. * @param int $storeId
  260. * @param int $staffId
  261. * @param array $cartIds
  262. * @param string $payType
  263. * @param bool $integral
  264. * @param bool $coupon
  265. * @param string $remarks
  266. * @return mixed
  267. * @throws \think\db\exception\DataNotFoundException
  268. * @throws \think\db\exception\DbException
  269. * @throws \think\db\exception\ModelNotFoundException
  270. */
  271. public function createOrder(int $uid, array $userInfo, array $computeData, int $storeId, int $staffId, array $cartIds, string $payType, bool $integral = false, bool $coupon = false, string $remarks = '', string $changePrice = '0', bool $isPrice = false, int $coupon_id = 0, int $seckillId = 0, $collate_code_id = 0)
  272. {
  273. /** @var SystemStoreStaffServices $staffService */
  274. $staffService = app()->make(SystemStoreStaffServices::class);
  275. if (!$staffInfo = $staffService->getOne(['store_id' => $storeId, 'id' => $staffId, 'is_del' => 0, 'status' => 1])) {
  276. throw new ValidateException('您选择的店员不存在');
  277. }
  278. $addressInfo = [];
  279. //兼容门店虚拟用户下单
  280. $field = ['real_name', 'phone', 'province', 'city', 'district', 'street', 'detail'];
  281. if ($uid) {
  282. /** @var UserAddressServices $addreService */
  283. $addreService = app()->make(UserAddressServices::class);
  284. $addressInfo = $addreService->getUserDefaultAddress($uid, implode(',', $field));
  285. if ($addressInfo) {
  286. $addressInfo = $addressInfo->toArray();
  287. }
  288. }
  289. if (!$addressInfo) {
  290. foreach ($field as $key) {
  291. $addressInfo[$key] = '';
  292. }
  293. }
  294. $cartGroup = $computeData['cartGroup'] ?? [];
  295. $cartInfo = $computeData['cartInfo'];
  296. $totalPrice = $computeData['totalPrice'];
  297. $couponId = $coupon_id;
  298. $couponPrice = $computeData['couponPrice'] ?? '0.00';
  299. $useIntegral = $computeData['usedIntegral'];
  300. $deduction = $computeData['deduction'];
  301. $gainIntegral = $totalNum = 0;
  302. $priceData = [
  303. 'coupon_id' => $couponId,
  304. 'coupon_price' => $couponPrice,
  305. 'usedIntegral' => $useIntegral,
  306. 'deduction_price' => $computeData['deductionPrice'] ?? '0.00',
  307. 'promotions_price' => $computeData['promotionsPrice'],
  308. 'pay_postage' => 0,
  309. 'pay_price' => $computeData['payPrice']
  310. ];
  311. $promotions_give = [
  312. 'give_integral' => $cartGroup['give_integral'] ?? 0,
  313. 'give_coupon' => $cartGroup['giveCoupon'] ?? [],
  314. 'give_product' => $cartGroup['giveProduct'] ?? [],
  315. 'promotions' => $cartGroup['promotions'] ?? []
  316. ];
  317. $type = (int)$deduction['type'] ?? 0;
  318. $seckillId = $seckillId ?: ($type == 1 ? ($deduction['activity_id'] ?? 0) : 0);
  319. foreach ($cartInfo as $cart) {
  320. $totalNum += $cart['cart_num'];
  321. $cartInfoGainIntegral = isset($cart['productInfo']['give_integral']) ? bcmul((string)$cart['cart_num'], (string)$cart['productInfo']['give_integral'], 0) : 0;
  322. $gainIntegral = bcadd((string)$gainIntegral, (string)$cartInfoGainIntegral, 0);
  323. if ($seckillId) {
  324. if (!isset($cart['product_attr_unique']) || !$cart['product_attr_unique']) continue;
  325. $type = $cart['type'];
  326. if (in_array($type, [1, 2, 3]) &&
  327. (
  328. !CacheService::checkStock($cart['product_attr_unique'], (int)$cart['cart_num'], $type) ||
  329. !CacheService::popStock($cart['product_attr_unique'], (int)$cart['cart_num'], $type)
  330. )
  331. ) {
  332. throw new ValidateException('您购买的商品库存已不足' . $cart['cart_num'] . $cart['productInfo']['unit_name']);
  333. }
  334. }
  335. }
  336. if ($collate_code_id) {
  337. $collateCodeId = (int)$deduction['collate_code_id'] ?? 0;
  338. if ($collateCodeId && $type == 10) {
  339. if ($collateCodeId != $collate_code_id) throw new ValidateException('拼单/桌码ID有误!');
  340. $seckillId = $collate_code_id;
  341. }
  342. }
  343. /** @var StoreOrderCreateServices $orderServices */
  344. $orderServices = app()->make(StoreOrderCreateServices::class);
  345. $key = md5(json_encode($cartIds) . uniqid() . time());
  346. $product_type = (int)$deduction['product_type'] ?? 0;
  347. $orderInfo = [
  348. 'uid' => $uid,
  349. 'type' => $type,
  350. 'order_id' => $orderServices->getNewOrderId(),
  351. 'real_name' => $addressInfo['real_name'] ? $addressInfo['real_name'] : $userInfo['nickname'] ?? '',
  352. 'user_phone' => $addressInfo['phone'] ? $addressInfo['phone'] : $userInfo['phone'] ?? '',
  353. 'user_address' => $addressInfo['province'] . ' ' . $addressInfo['city'] . ' ' . $addressInfo['district'] . ' ' . $addressInfo['street'] . ' ' . $addressInfo['detail'],
  354. 'cart_id' => $cartIds,
  355. 'clerk_id' => $staffInfo['uid'],
  356. 'store_id' => $storeId,
  357. 'staff_id' => $staffId,
  358. 'total_num' => $totalNum,
  359. 'total_price' => $computeData['sumPrice'] ?? $totalPrice,
  360. 'total_postage' => 0,
  361. 'coupon_id' => $couponId,
  362. 'coupon_price' => $couponPrice,
  363. 'promotions_price' => $priceData['promotions_price'],
  364. 'pay_price' => $isPrice ? $changePrice : $computeData['payPrice'],
  365. 'pay_postage' => 0,
  366. 'deduction_price' => $computeData['deductionPrice'],
  367. 'change_price' => $isPrice ? bcsub((string)$computeData['payPrice'],(string)$changePrice,2) : '0.00',
  368. 'paid' => 0,
  369. 'pay_type' => $payType == self::YUE_PAY ? 'yue' : '',
  370. 'use_integral' => $useIntegral,
  371. 'gain_integral' => $gainIntegral,
  372. 'mark' => htmlspecialchars($remarks),
  373. 'product_type' => $product_type,
  374. 'activity_id' => $seckillId,
  375. 'pink_id' => 0,
  376. 'cost' => $computeData['costPrice'],
  377. 'is_channel' => 2,
  378. 'add_time' => time(),
  379. 'unique' => $key,
  380. 'shipping_type' => 4,
  381. 'channel_type' => $userInfo['user_type'] ?? '',
  382. 'province' => '',
  383. 'spread_uid' => 0,
  384. 'spread_two_uid' => 0,
  385. 'promotions_give' => json_encode($promotions_give),
  386. 'give_integral' => $promotions_give['give_integral'] ?? 0,
  387. 'give_coupon' => implode(',', $promotions_give['give_coupon'] ?? []),
  388. ];
  389. if ($product_type == 4) {//次卡商品收银台购买
  390. $orderInfo['verify_code'] = $orderServices->getStoreCode();
  391. $orderInfo['shipping_type'] = 2;//修改门店自提
  392. }
  393. /** @var StoreOrderCartInfoServices $cartServices */
  394. $cartServices = app()->make(StoreOrderCartInfoServices::class);
  395. //$order = $this->transaction(function () use ($key, $storeId, $cartInfo, $type, $seckillId, $computeData, $orderInfo, $cartServices, $orderServices, $couponId, $userInfo, $useIntegral, $promotions_give, $payType) {
  396. $order = $orderServices->save($orderInfo);
  397. if (!$order) {
  398. throw new ValidateException('订单生成失败');
  399. }
  400. //使用优惠券
  401. if ($couponId) {
  402. /** @var StoreCouponUserServices $couponServices */
  403. $couponServices = app()->make(StoreCouponUserServices::class);
  404. $res1 = $couponServices->useCoupon($couponId, (int)($userInfo['uid'] ?? 0), $cartInfo, [], $storeId);
  405. if (!$res1) {
  406. throw new ValidateException('使用优惠劵失败!');
  407. }
  408. }
  409. //积分抵扣
  410. $orderServices->deductIntegral($userInfo, $useIntegral, [
  411. 'SurplusIntegral' => $computeData['surplusIntegral'],
  412. 'usedIntegral' => $computeData['usedIntegral'],
  413. 'deduction_price' => $computeData['deductionPrice'],
  414. ], (int)($userInfo['uid'] ?? 0), $key);
  415. //修改门店库存
  416. $orderServices->decGoodsStock($cartInfo, $type, $seckillId, $storeId);
  417. //保存购物车商品信息
  418. $cartServices->setCartInfo($order['id'], $cartInfo, $userInfo['uid'] ?? 0, $promotions_give['promotions'] ?? []);
  419. $order = $order->toArray();
  420. // return $order;
  421. // });
  422. if (in_array($type, [9, 10]) && $collate_code_id > 0 && $order) {
  423. //关联订单和拼单、桌码
  424. /** @var UserCollageServices $collageServices */
  425. $collageServices = app()->make(UserCollageServices::class);
  426. $collageServices->update($collate_code_id, ['oid' => $order['id'], 'status' => 2]);
  427. //清除未结算商品
  428. /** @var UserCollagePartakeServices $partakeService */
  429. $partakeService = app()->make(UserCollagePartakeServices::class);
  430. $partakeService->update(['collate_code_id' => $collate_code_id, 'is_settle' => 0], ['status' => 0]);
  431. }
  432. $news = false;
  433. $addressId = $type = $activity_id = 0;
  434. //订单创建事件
  435. if (in_array($payType, [PayServices::ALIAPY_PAY, PayServices::WEIXIN_PAY, PayServices::YUE_PAY])) {
  436. $delCart = false;
  437. } else {
  438. $delCart = true;
  439. }
  440. //扣除优惠活动赠品限量
  441. StorePromotionsJob::dispatchDo('changeGiveLimit', [$promotions_give]);
  442. event('order.create', [$order, $userInfo, compact('cartInfo', 'priceData', 'addressId', 'cartIds', 'news', 'delCart', 'changePrice'), compact('type', 'activity_id'), 0]);
  443. return $order;
  444. }
  445. /**
  446. * 收银台支付
  447. * @param string $orderId
  448. * @param string $payType
  449. * @param string $userCode
  450. * @param string $authCode
  451. * @return array
  452. * @throws \Psr\SimpleCache\InvalidArgumentException
  453. */
  454. public function paySuccess(string $orderId, string $payType, string $userCode, string $authCode = '')
  455. {
  456. /** @var StoreOrderSuccessServices $orderService */
  457. $orderService = app()->make(StoreOrderSuccessServices::class);
  458. $orderInfo = $orderService->get(['order_id' => $orderId]);
  459. if (!$orderInfo) {
  460. throw new ValidateException('没有查询到订单信息');
  461. }
  462. if ($orderInfo->paid) {
  463. throw new ValidateException('订单已支付');
  464. }
  465. if ($orderInfo->is_del) {
  466. throw new ValidateException('订单已取消');
  467. }
  468. switch ($payType) {
  469. case PayServices::YUE_PAY://余额支付
  470. $is_cashier_yue_pay_verify = (int)sys_config('is_cashier_yue_pay_verify'); // 收银台余额支付是否需要验证【是/否】
  471. if (!$orderInfo['uid']) {
  472. throw new ValidateException('余额支付用户信息不存在无法支付');
  473. }
  474. if (!$userCode && $is_cashier_yue_pay_verify) {
  475. throw new ValidateException('缺少扫码支付参数');
  476. }
  477. /** @var UserServices $userService */
  478. $userService = app()->make(UserServices::class);
  479. $userInfo = $userService->getUserInfo($orderInfo->uid, ['uid', 'rand_code']);
  480. //读取缓存用户code
  481. $rand_code = CacheService::redisHandler()->get('user_rand_code' . $orderInfo->uid);
  482. CacheService::redisHandler()->delete('user_rand_code' . $orderInfo->uid);
  483. if (!$userInfo) {
  484. throw new ValidateException('余额支付用户不存在');
  485. }
  486. if ($rand_code != $userCode && $is_cashier_yue_pay_verify) {
  487. throw new ValidateException('二维码已使用或不正确,请确认后重新扫码');
  488. }
  489. /** @var YuePayServices $payService */
  490. $payService = app()->make(YuePayServices::class);
  491. $pay = $payService->yueOrderPay($orderInfo->toArray(), $orderInfo->uid);
  492. if ($pay['status'] === true)
  493. return ['status' => 'SUCCESS'];
  494. else if ($pay['status'] === 'pay_deficiency') {
  495. throw new ValidateException($pay['msg']);
  496. } else {
  497. return ['status' => 'ERROR', 'message' => is_array($pay) ? $pay['msg'] ?? '余额支付失败' : $pay];
  498. }
  499. case PayServices::WEIXIN_PAY://微信支付
  500. case PayServices::ALIAPY_PAY://支付宝支付
  501. if (!$authCode) {
  502. throw new ValidateException('缺少支付付款二维码CODE');
  503. }
  504. $pay = new PayServices();
  505. $site_name = sys_config('site_name');
  506. /** @var StoreOrderCartInfoServices $orderInfoServices */
  507. $orderInfoServices = app()->make(StoreOrderCartInfoServices::class);
  508. $body = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo['id']);
  509. $body = substrUTf8($site_name . '--' . $body, 30);
  510. try {
  511. //扫码支付
  512. $response = $pay->setAuthCode($authCode)->pay($payType, '', $orderInfo->order_id, $orderInfo->pay_price, 'product', $body);
  513. } catch (\Throwable $e) {
  514. \think\facade\Log::error('收银端' . $payType . '扫码支付失败,原因:' . $e->getMessage());
  515. return ['status' => 'ERROR', 'message' => '支付失败,原因:' . $e->getMessage()];
  516. }
  517. //支付成功paid返回1
  518. if ($response['paid']) {
  519. if (!$orderService->paySuccess($orderInfo->toArray(), $payType, ['trade_no' => $response['payInfo']['transaction_id'] ?? ''])) {
  520. return ['status' => 'ERROR', 'message' => '支付失败'];
  521. }
  522. //支付成功刪除購物車
  523. /** @var StoreCartServices $cartServices */
  524. $cartServices = app()->make(StoreCartServices::class);
  525. $cartServices->deleteCartStatus($orderInfo['cart_id'] ?? []);
  526. return ['status' => 'SUCCESS'];
  527. } else {
  528. if ($payType === PayServices::WEIXIN_PAY) {
  529. if (isset($response['payInfo']['err_code']) && in_array($response['payInfo']['err_code'], ['AUTH_CODE_INVALID', 'NOTENOUGH'])) {
  530. return ['status' => 'ERROR', 'message' => '支付失败'];
  531. }
  532. //微信付款码支付需要同步更改状态
  533. $secs = 5;
  534. if (isset($order_info['payInfo']['err_code']) && $order_info['payInfo']['err_code'] === 'USERPAYING') {
  535. $secs = 10;
  536. }
  537. //放入队列执行
  538. MicroPayOrderJob::dispatchSece($secs, [$orderInfo['order_id'], 0]);
  539. }
  540. return ['status' => 'PAY_ING', 'message' => $response['message']];
  541. }
  542. break;
  543. case PayServices::CASH_PAY://收银台现金支付
  544. if (!$orderService->paySuccess($orderInfo->toArray(), $payType)) {
  545. return ['status' => 'ERROR', 'message' => '支付失败'];
  546. } else {
  547. return ['status' => 'SUCCESS'];
  548. }
  549. break;
  550. default:
  551. throw new ValidateException('暂无支付方式,无法支付');
  552. }
  553. }
  554. }