PointsOrderCreateRepository.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. <?php
  2. namespace app\common\repositories\store\order;
  3. use app\common\dao\store\order\StoreOrderDao;
  4. use app\common\repositories\store\coupon\StoreCouponUserRepository;
  5. use app\common\repositories\store\product\ProductAssistSkuRepository;
  6. use app\common\repositories\store\product\ProductAttrValueRepository;
  7. use app\common\repositories\store\product\ProductGroupSkuRepository;
  8. use app\common\repositories\store\product\ProductPresellSkuRepository;
  9. use app\common\repositories\store\product\ProductRepository;
  10. use app\common\repositories\store\product\StoreDiscountRepository;
  11. use app\common\repositories\system\merchant\MerchantRepository;
  12. use app\common\repositories\user\UserAddressRepository;
  13. use app\common\repositories\user\UserBillRepository;
  14. use app\common\repositories\user\UserMerchantRepository;
  15. use think\exception\ValidateException;
  16. use think\facade\Db;
  17. class PointsOrderCreateRepository
  18. {
  19. /**
  20. * 检查用户购物车信息、地址信息以及订单相关数据,并准备创建订单所需的数据。
  21. * 此函数主要用于在用户提交订单前,验证和整理所有必要的信息,包括购物车商品、收货地址、积分使用等。
  22. *
  23. * @param User $user 当前用户对象。
  24. * @param int $cartId 购物车ID,代表用户选中的购物车。
  25. * @param int $addressId 收货地址ID,代表用户选择的收货地址。
  26. * @param bool $useIntegral 是否使用积分,用于标记是否在本次订单中使用积分。
  27. * @param Order|null $createOrder 创建的订单对象,如果提供了订单对象,则表示在此基础上进行订单数据的填充和验证。
  28. * @return array 返回一个包含订单创建所需数据的数组,包括加密的key、订单类型、订单模型等。
  29. */
  30. public function check($user, $cartId, $addressId, $useIntegral , $createOrder = null)
  31. {
  32. // 生成一个唯一的key,用于标识此次订单请求,防止重复提交等安全问题。
  33. $key = md5(json_encode(compact('cartId', 'useIntegral', 'addressId'))) . $user->uid;
  34. // 验证并获取用户选择的收货地址详情。
  35. $address = $this->validateAddress($user,$addressId);
  36. // 验证购物车列表,同时获取订单模型、订单扩展信息和订单类型。
  37. [$merchantCartList,$order_model,$order_extend,$order_type] = $this->validateCartList($cartId,$user,$address);
  38. // 验证并处理商家列表,准备订单中商家信息的展示和处理。
  39. $successData = $this->validateMerchantList($merchantCartList);
  40. // 返回整理后的所有订单创建所需数据,包括用户积分、收货地址等。
  41. return $successData + [
  42. 'key' => $key,
  43. 'order_type' => $order_type,
  44. 'order_model' => $order_model,
  45. 'order_extend' => $order_extend,
  46. 'true_integral' => (int)$user->integral,
  47. 'address' => $address,
  48. ];
  49. }
  50. /**
  51. * 验证用户地址
  52. * @author Qinii
  53. * @day 2023/4/20
  54. */
  55. public function validateAddress($user,$addressId)
  56. {
  57. $address = null;
  58. //验证地址
  59. if ($addressId) {
  60. $addressRepository = app()->make(UserAddressRepository::class);
  61. $address = $addressRepository->getWhere(['uid' => $user->uid, 'address_id' => $addressId]);
  62. }
  63. return $address;
  64. }
  65. /**
  66. * 验证购物车商品
  67. * @author Qinii
  68. * @day 2023/4/20
  69. */
  70. public function validateCartList($cartId,$user,$address)
  71. {
  72. $storeCartRepository = app()->make(StoreCartRepository::class);
  73. $list = $storeCartRepository->cartIbByData($cartId, $user->uid, $address);
  74. $res = $storeCartRepository->checkCartList($list, $user, 0);
  75. $merchantCartList = $res['list'];
  76. $fail = $res['fail'];
  77. //检查购物车失效数据
  78. if (count($fail)) {
  79. if ($fail[0]['is_fail'])
  80. throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...');
  81. if (in_array($fail[0]['product_type'], [1, 2, 3]) && !$fail[0]['userPayCount']) {
  82. throw new ValidateException('[超出限购数]' . mb_substr($fail[0]['product']['store_name'],0,10).'...');
  83. }
  84. throw new ValidateException('[已失效]' . mb_substr($fail[0]['product']['store_name'],0,10).'...');
  85. }
  86. $order_type = null;
  87. $order_model = 2;
  88. $order_extend = '';
  89. //检查商品类型, 活动商品只能单独购买
  90. foreach ($merchantCartList as $merchantCart) {
  91. foreach ($merchantCart['list'] as $cart) {
  92. if (is_null($order_type)) $order_type = $cart['product_type'];
  93. if (count($merchantCart['list']) != 1 || count($merchantCartList) != 1) {
  94. throw new ValidateException('活动商品必须单独购买');
  95. }
  96. if ($cart['product']['pay_limit'] == 2){
  97. //如果长期限购
  98. //已购买数量
  99. $count = app()->make(StoreOrderRepository::class)->getMaxCountNumber($cart['uid'],$cart['product_id']);
  100. if (($cart['cart_num'] + $count) > $cart['product']['once_max_count'])
  101. throw new ValidateException('[超出限购总数:'. $cart['product']['once_max_count'].']'.mb_substr($cart['product']['store_name'],0,10).'...');
  102. }
  103. if ($cart['product']['extend']) {
  104. $order_extend = json_decode($cart['product']['extend'], true);
  105. }
  106. }
  107. }
  108. return [$merchantCartList,$order_model,$order_extend,$order_type];
  109. }
  110. /**
  111. * 计算订单金额
  112. * @return array
  113. * @author Qinii
  114. * @day 2023/4/20
  115. */
  116. public function validateMerchantList($merchantCartList)
  117. {
  118. $deliveryStatus = true;
  119. $order_total_num = 0;
  120. $order_total_price = 0;
  121. $order_total_integral = 0;
  122. $order_total_cost = 0;
  123. $order_pay_price = 0;
  124. foreach ($merchantCartList as &$merchantCart) {
  125. //每个商户的订单金额等
  126. //合计支付金额
  127. $total_price = 0;
  128. //合计商品数量
  129. $total_num = 0;
  130. //合计运费
  131. $postage_price = 0;
  132. //合计使用积分
  133. $total_integral = 0;
  134. //合计出厂价
  135. $total_cost = 0;
  136. //合计实际支付金额
  137. $pay_price = 0;
  138. //每个商户的商品列表,计算
  139. foreach ($merchantCart['list'] as $cart) {
  140. if ($cart['cart_num'] <= 0) throw new ValidateException('购买商品数必须大于0');
  141. $price = bcmul($cart['cart_num'], $cart['productAttr']['price'], 2);
  142. $integral = bcmul($cart['cart_num'], $cart['productAttr']['ot_price'], 2);
  143. $cost = bcmul($cart['cart_num'], $cart['productAttr']['cost'], 2);
  144. $total_num += $cart['cart_num'];
  145. $total_price = bcadd($total_price, $price, 2);
  146. $total_integral = bcadd($total_integral, $integral, 2);
  147. $total_cost = bcadd($total_cost, $cost, 2);
  148. $pay_price = bcadd($pay_price, $price, 2);
  149. $cart['true_price'] = $price;
  150. $cart['total_price'] = $price;
  151. $cart['postage_price'] = 0;
  152. $cart['integral'] = (int)$integral;
  153. $cart['extension_one'] = 0;
  154. $cart['extension_two'] = 0;
  155. $cart['cost'] = $total_cost;
  156. }
  157. unset($cart);
  158. if (count($merchantCartList) > 1 || count($merchantCart['list']) > 1) {
  159. $orderDeliveryStatus = $orderDeliveryStatus && $deliveryStatus;
  160. }
  161. $order_total_num += $total_num;
  162. $order_total_price = bcadd($order_total_price,$total_price, 2);
  163. $order_total_cost = bcadd($order_total_cost,$total_cost,2);
  164. $order_pay_price = bcadd($order_pay_price,$pay_price, 2);
  165. $order_total_integral = bcadd($order_total_integral,$total_integral,2);
  166. $merchantCart['order'] = [
  167. 'total_num' => $total_num,
  168. 'total_price'=> $total_price,
  169. 'total_cost' => $total_cost,
  170. 'pay_price' => $pay_price,
  171. 'total_integral'=> $total_integral,
  172. 'postage_price' => $postage_price,
  173. ];
  174. }
  175. unset($merchantCart);
  176. return [
  177. 'order_total_num' => $order_total_num,
  178. 'order_pay_price' => $order_pay_price,
  179. 'order_total_price' => $order_total_price,
  180. 'order_total_integral' => (int)$order_total_integral,
  181. 'order_total_cost' => $order_total_cost,
  182. 'order_delivery_status' => $deliveryStatus,
  183. 'order' => $merchantCartList
  184. ];
  185. }
  186. /**
  187. * 循环处理子订单
  188. * @param $merchantCartList
  189. * @param $pay_type
  190. * @param $user_address
  191. * @return array
  192. * @author Qinii
  193. * @day 2023/4/21
  194. */
  195. public function merOrderList($user, $merchantCartList, $pay_type, $user_address, $address, $order_type, $order_model, $mark = '', $extend = [])
  196. {
  197. $totalPostage = 0;
  198. $totalCost = 0;
  199. $totalNum = 0;
  200. $totalPrice = 0;
  201. $totalIntegral = 0;
  202. $make = app()->make(StoreOrderRepository::class);
  203. foreach ($merchantCartList as $k => $merchantCart) {
  204. //整理订单数据
  205. $_order = [
  206. 'cartInfo' => $merchantCart,
  207. 'activity_type' => $order_type,
  208. 'commission_rate' => 0,
  209. 'order_type' => $order_type,
  210. 'is_virtual' => $order_model,
  211. 'extension_one' => $total_extension_one ?? 0,
  212. 'extension_two' => $total_extension_two ?? 0,
  213. 'order_sn' => $make->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . ($k + 1),
  214. 'uid' => $user->uid,
  215. 'spread_uid' => $spreadUid ?? 0,
  216. 'top_uid' => $topUid ?? 0,
  217. 'is_selfbuy' => $isSelfBuy ?? 0,
  218. 'real_name' => $address['real_name'] ?? '',
  219. 'user_phone' => $address['phone'] ?? '',
  220. 'user_address' => $user_address,
  221. 'cart_id' => implode(',', array_column($merchantCart['list'], 'cart_id')),
  222. 'total_num' => $merchantCart['order']['total_num'],
  223. 'total_price' => $merchantCart['order']['total_price'],
  224. 'total_postage' => 0,
  225. 'pay_postage' => 0,
  226. 'svip_discount' => 0,
  227. 'pay_price' => $merchantCart['order']['pay_price'],
  228. 'integral' => $merchantCart['order']['total_integral'],
  229. 'integral_price' => 0,
  230. 'give_integral' => 0,
  231. 'mer_id' => $merchantCart['mer_id'],
  232. 'cost' => $merchantCart['order']['total_cost'],
  233. 'order_extend' => count($extend) ? json_encode($extend, JSON_UNESCAPED_UNICODE) : '',
  234. 'coupon_id' => '',
  235. 'mark' => $mark,
  236. 'coupon_price' => 0,
  237. 'platform_coupon_price' => 0,
  238. 'pay_type' => $pay_type
  239. ];
  240. $orderList[] = $_order;
  241. $totalCost = bcadd($totalCost, $_order['cost'], 2);
  242. $totalPrice = bcadd($totalPrice, $_order['total_price'], 2);
  243. $totalIntegral = bcadd($totalIntegral, $_order['integral'], 2);
  244. $totalPostage = bcadd($totalPostage, $_order['total_postage'], 2);
  245. $totalNum += $merchantCart['order']['total_num'];
  246. }
  247. return compact('totalPrice','totalPostage','totalCost','totalNum','totalIntegral','orderList');
  248. }
  249. /**
  250. * 创建订单
  251. * @param $params
  252. * @author Qinii
  253. * @day 2023/4/20
  254. */
  255. public function createOrder($user,$cartId,$addressId,$useIntegral,$mark,$pay_type)
  256. {
  257. $orderInfo = $this->check($user,$cartId,$addressId,$useIntegral, true);
  258. if (!$orderInfo['address']) throw new ValidateException('请选择收货地址');
  259. if (!$orderInfo['address']['province_id']) throw new ValidateException('请完善收货地址信息');
  260. if (!$orderInfo['order_delivery_status']) throw new ValidateException('部分商品配送方式不一致,请单独下单');
  261. if ($orderInfo['order_total_price'] > 1000000) throw new ValidateException('支付金额超出最大限制');
  262. if ($orderInfo['order_total_integral'] > $user->integral) throw new ValidateException('积分不足');
  263. $merchantCartList = $orderInfo['order'];
  264. $address =$orderInfo['address'];
  265. $user_address = isset($address) ? ($address['province'] . $address['city'] . $address['district'] . $address['street'] . $address['detail']) : '';
  266. $orderList = $this->merOrderList($user,$merchantCartList, $pay_type, $user_address, $address,$orderInfo['order_type'],$orderInfo['order_model'],$mark);
  267. $storeOrderRepository = app()->make(StoreOrderRepository::class);
  268. $groupOrder = [
  269. 'uid' => $user->uid,
  270. 'group_order_sn' => count($orderList) === 1 ? $orderList['orderList'][0]['order_sn'] : ($storeOrderRepository->getNewOrderId(StoreOrderRepository::TYPE_SN_ORDER) . '20'),
  271. 'total_postage' => $orderList['totalPostage'],
  272. 'total_price' => $orderList['totalPrice'],
  273. 'total_num' => $orderList['totalNum'],
  274. 'real_name' => $address['real_name'] ?? '',
  275. 'user_phone' => $address['phone'] ?? '',
  276. 'user_address' => $user_address,
  277. 'pay_price' => $orderList['totalPrice'],
  278. 'coupon_price' => 0,
  279. 'pay_postage' => $orderList['totalPostage'],
  280. 'cost' => $orderList['totalCost'],
  281. 'coupon_id' => '',
  282. 'pay_type' => $pay_type,
  283. 'give_coupon_ids' => 0,
  284. 'integral' => $orderList['totalIntegral'],
  285. 'integral_price' => $orderList['totalIntegral'],
  286. 'give_integral' => 0,
  287. 'is_combine' => 0,
  288. 'activity_type' => $orderInfo['order_type'],
  289. ];
  290. //订单记录
  291. $storeGroupOrderRepository = app()->make(StoreGroupOrderRepository::class);
  292. $storeCartRepository = app()->make(StoreCartRepository::class);
  293. $attrValueRepository = app()->make(ProductAttrValueRepository::class);
  294. $productRepository = app()->make(ProductRepository::class);
  295. $storeOrderProductRepository = app()->make(StoreOrderProductRepository::class);
  296. $storeOrderStatusRepository = app()->make(StoreOrderStatusRepository::class);
  297. $userMerchantRepository = app()->make(UserMerchantRepository::class);
  298. $userBillRepository = app()->make(UserBillRepository::class);
  299. $_orderList = $orderList['orderList'];
  300. return Db::transaction(function () use (
  301. $user,
  302. $cartId,
  303. $groupOrder,
  304. $_orderList,
  305. $orderInfo,
  306. $attrValueRepository,
  307. $productRepository,
  308. $storeCartRepository,
  309. $storeGroupOrderRepository,
  310. $storeOrderStatusRepository,
  311. $userMerchantRepository,
  312. $storeOrderProductRepository,
  313. $storeOrderRepository,
  314. $userBillRepository
  315. ) {
  316. //减库存
  317. foreach ($_orderList as $order) {
  318. foreach ($order['cartInfo']['list'] as $cart) {
  319. if (!isset($uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']]))
  320. $uniqueList[$cart['productAttr']['product_id'] . $cart['productAttr']['unique']] = true;
  321. else
  322. throw new ValidateException('购物车商品信息重复');
  323. try {
  324. $attrValueRepository->descStock($cart['productAttr']['product_id'], $cart['productAttr']['unique'], $cart['cart_num']);
  325. $productRepository->descStock($cart['product']['product_id'], $cart['cart_num']);
  326. $productRepository->incIntegral($cart['product']['product_id'], $cart['integral'], $cart['integral']);
  327. } catch (\Exception $e) {
  328. throw new ValidateException('库存不足');
  329. }
  330. }
  331. }
  332. //修改购物车状态
  333. $storeCartRepository->updates($cartId, ['is_pay' => 1]);
  334. //创建订单
  335. $groupOrder = $storeGroupOrderRepository->create($groupOrder);
  336. if ($groupOrder['integral'] > 0) {
  337. $user->integral = bcsub($user->integral, $groupOrder['integral'], 0);
  338. $userBillRepository->decBill(
  339. $user['uid'],
  340. 'integral',
  341. 'points_order',
  342. [
  343. 'link_id' => $groupOrder['group_order_id'],
  344. 'status' => 1,
  345. 'title' => '积分商城兑换商品',
  346. 'number' => $groupOrder['integral'],
  347. 'mark' => '积分商城兑换商品使用积分' . floatval($groupOrder['integral']) ,
  348. 'balance' => $user->integral
  349. ]
  350. );
  351. $user->save();
  352. }
  353. foreach ($_orderList as $k => $order) {
  354. $_orderList[$k]['group_order_id'] = $groupOrder->group_order_id;
  355. }
  356. $orderProduct = [];
  357. $orderStatus = [];
  358. foreach ($_orderList as $order) {
  359. $cartInfo = $order['cartInfo'];
  360. unset($order['cartInfo']);
  361. //创建子订单
  362. $_order = $storeOrderRepository->create($order);
  363. foreach ($cartInfo['list'] as $cart) {
  364. $productPrice = $cart['true_price'];
  365. $order_cart = [
  366. 'product' => $cart['product'],
  367. 'productAttr' => $cart['productAttr'],
  368. 'product_type' => $cart['product_type']
  369. ];
  370. $orderProduct[] = [
  371. 'order_id' => $_order->order_id,
  372. 'cart_id' => $cart['cart_id'],
  373. 'uid' => $user->uid,
  374. 'product_id' => $cart['product_id'],
  375. 'activity_id' => $cart['source'] >= 2 ? $cart['source_id'] : $cart['product_id'],
  376. 'total_price' => $cart['total_price'],
  377. 'product_price' => $productPrice,
  378. 'extension_one' => 0,
  379. 'extension_two' => 0,
  380. 'postage_price' => 0,
  381. 'svip_discount' => 0,
  382. 'cost' => $cart['cost'],
  383. 'coupon_price' => 0,
  384. 'platform_coupon_price' => 0,
  385. 'product_sku' => $cart['productAttr']['unique'],
  386. 'product_num' => $cart['cart_num'],
  387. 'refund_num' => $cart['cart_num'],
  388. 'integral_price' => 0,
  389. 'integral' => $cart['integral'] ,
  390. 'integral_total' => $cart['integral'] ,
  391. 'product_type' => $cart['product_type'],
  392. 'cart_info' => json_encode($order_cart)
  393. ];
  394. }
  395. $userMerchantRepository->getInfo($user->uid, $order['mer_id']);
  396. //订单记录
  397. $orderStatus[] = [
  398. 'order_id' => $_order->order_id,
  399. 'order_sn' => $_order->order_sn,
  400. 'type' => $storeOrderStatusRepository::TYPE_ORDER,
  401. 'change_message' => '积分兑换订单生成',
  402. 'change_type' => $storeOrderStatusRepository::ORDER_STATUS_CREATE,
  403. 'uid' => $user->uid,
  404. 'nickname' => $user->nickname,
  405. 'user_type' => $storeOrderStatusRepository::U_TYPE_USER,
  406. ];
  407. }
  408. $storeOrderStatusRepository->batchCreateLog($orderStatus);
  409. $storeOrderProductRepository->insertAll($orderProduct);
  410. event('order.create', compact('groupOrder'));
  411. return $groupOrder;
  412. });
  413. }
  414. }