GroupBuyOrder.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. <?php
  2. namespace addons\GroupBuy\common\models;
  3. use addons\GroupBuy\common\enums\GroupBuyEnum;
  4. use addons\GroupBuy\common\listeners\order\OrderPaidListener;
  5. use common\enums\GoodsTypeEnum;
  6. use common\enums\RedisKeyEnum;
  7. use common\enums\OrderStatusEnum;
  8. use common\enums\PaymentTradeOrderEnum;
  9. use common\enums\PayTypeEnum;
  10. use common\enums\StatusEnum;
  11. use addons\GroupBuy\common\events\order\OrderPaidEvent;
  12. use common\enums\AddonsEnum;
  13. use common\enums\UserWalletEnum;
  14. use common\helpers\FormatHelper;
  15. use common\helpers\LockHelper;
  16. use common\helpers\StringHelper;
  17. use common\models\base\BaseActiveRecord;
  18. use common\models\common\PaymentTrade;
  19. use common\models\common\PaymentTradeOrder;
  20. use common\models\common\PaymentTransfer;
  21. use common\models\goods\Goods;
  22. use common\models\goods\GoodsAttr;
  23. use common\models\order\Order;
  24. use common\models\order\OrderDetail;
  25. use common\models\user\User;
  26. use services\common\UserWalletService;
  27. use Yii;
  28. use yii\helpers\Json;
  29. use Exception;
  30. /**
  31. * This is the model class for table "qimall_addons_group_buy_order".
  32. *
  33. * @property int $id id
  34. * @property int $mall_id 商城ID
  35. * @property int $mch_id 商户ID
  36. * @property int $user_id 用户ID
  37. * @property int $order_id 主订单表id
  38. * @property string $order_no 订单编号
  39. * @property string $out_trade_no 外部交易号
  40. * @property int $group_buy_active_id 拼团活动id
  41. * @property int $open_group_id 开团id
  42. * @property int $commander_id 拼团长id
  43. * @property int $is_commander 是否团长 0:否:1:是
  44. * @property int $goods_id 商品id
  45. * @property int $goods_name 商品名称
  46. * @property int $goods_attr_name 商品规格名称
  47. * @property string $pic_url 商品图片
  48. * @property int $goods_attr_id 商品规格id
  49. * @property int $order_status 拼团状态 0待支付 1参团中 2拼团成功 3拼团失败
  50. * @property int $shipping_type 快递方式
  51. * @property float $shipping_money 运费
  52. * @property float $price 商品原销售价格
  53. * @property float $group_buy_price 拼团商品价格
  54. * @property int $num 购买数量
  55. * @property int $win_time 拼中时间
  56. * @property int $payment_type 支付方式:1.在线支付 2.货到付款 3.余额支付
  57. * @property int $pay_time 支付时间
  58. * @property float $total_pay_price 实际支付总费用(含运费)
  59. * @property string $remark 用户订单备注
  60. * @property int $is_pay 是否支付:0.未支付|1.已支付
  61. * @property int $status 状态[-1:删除;0:禁用;1启用]
  62. * @property int $created_at 创建时间
  63. * @property int $updated_at 更新时间
  64. * @property string|null $mobile 收货人的手机号码
  65. * @property string|null $receiver_name 收货人姓名
  66. * @property int|null $province 收货人所在省
  67. * @property int|null $city 收货人所在城市
  68. * @property int|null $area 收货人所在街道
  69. * @property string|null $zip 收货人邮编
  70. * @property string|null $address 详细地址
  71. * @property string|null $region_name 地区名称(省市区[乡/镇])
  72. * @property array|null $marketing 拼团营销优惠
  73. * @property int $is_free 是否免费开团
  74. */
  75. class GroupBuyOrder extends BaseActiveRecord
  76. {
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public static function tableName()
  81. {
  82. return '{{%addons_group_buy_order}}';
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. public function rules()
  88. {
  89. return [
  90. [['mch_id', 'mall_id', 'user_id', 'order_id', 'group_buy_active_id', 'open_group_id', 'commander_id', 'is_commander', 'goods_id', 'goods_attr_id', 'order_status', 'num', 'win_time', 'payment_type', 'pay_time', 'shipping_type', 'is_pay', 'status', 'created_at', 'updated_at', 'province', 'city', 'area', 'is_free'], 'integer'],
  91. [['order_no'], 'required'],
  92. [['shipping_money', 'price', 'group_buy_price', 'total_pay_price'], 'number'],
  93. [['order_no','out_trade_no'], 'string', 'max' => 50],
  94. [['remark', 'goods_name', 'goods_attr_name','pic_url'], 'string', 'max' => 255],
  95. [['mobile'], 'string', 'max' => 11],
  96. [['receiver_name'], 'string', 'max' => 50],
  97. [['zip'], 'string', 'max' => 20],
  98. [['address', 'region_name'], 'string', 'max' => 200],
  99. [['marketing'], 'safe'],
  100. ];
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function attributeLabels()
  106. {
  107. return [
  108. 'id' => 'id',
  109. 'mall_id' => '商城ID',
  110. 'mch_id' => '商户id',
  111. 'user_id' => '用户ID',
  112. 'order_id' => '主订单表id',
  113. 'order_no' => '订单编号',
  114. 'out_trade_no' => '外部交易号',
  115. 'group_buy_active_id' => '拼团活动id',
  116. 'open_group_id' => '开团id',
  117. 'commander_id' => '拼团长id',
  118. 'is_commander' => '是否团长 0:否:1:是',
  119. 'goods_id' => '商品id',
  120. 'goods_attr_id' => '商品规格id',
  121. 'pic_url' => '商品图片',
  122. 'order_status' => '拼团状态 0待支付 1参团中 2拼团成功 3拼团失败',
  123. 'price' => '商品原销售价格',
  124. 'group_buy_price' => '拼团商品价格',
  125. 'num' => '购买数量',
  126. 'win_time' => '拼中时间',
  127. 'payment_type' => '支付方式:1.在线支付 2.货到付款 3.余额支付',
  128. 'pay_time' => '支付时间',
  129. 'total_pay_price' => '实际支付总费用(含运费)',
  130. 'remark' => '用户订单备注',
  131. 'is_pay' => '是否支付:0.未支付|1.已支付',
  132. 'status' => '状态[-1:删除;0:禁用;1启用]',
  133. 'created_at' => '创建时间',
  134. 'updated_at' => '更新时间',
  135. 'mobile' => '收货人的手机号码',
  136. 'receiver_name' => '收货人姓名',
  137. 'province' => '收货人所在省',
  138. 'city' => '收货人所在城市',
  139. 'area' => '收货人所在街道',
  140. 'zip' => '收货人邮编',
  141. 'address' => '详细地址',
  142. 'region_name' => '地区名称(省市区[乡/镇])',
  143. 'marketing' => '拼团营销优惠',
  144. 'is_free' => '是否免费开团',
  145. ];
  146. }
  147. // 关联模型
  148. public function getUser()
  149. {
  150. return $this->hasOne(User::class, ['id' => 'user_id']);
  151. }
  152. public function getGroupBuyActive()
  153. {
  154. return $this->hasOne(GroupBuyActive::class, ['id' => 'group_buy_active_id']);
  155. }
  156. // 获取当团下的所有订单
  157. public function getCurrentGroup()
  158. {
  159. return $this->hasMany(GroupBuyOrder::class, ['open_group_id' => 'open_group_id']);
  160. }
  161. /**
  162. * @desc:生成订单
  163. * @Author: hua
  164. * @Date: 2021/12/15
  165. * @Time: 15:14
  166. * @Copyright: copyright (c) 2021 广东七件事集团
  167. * @param $form
  168. * @return array|false
  169. */
  170. public static function createOrder($form)
  171. {
  172. $stock_locks = [];
  173. try {
  174. $group_order_goods = $form['group_order_goods'];
  175. $data = is_array($form->data) ? $form->data : Json::decode($form->data, true);
  176. $trans = Yii::$app->db->beginTransaction();
  177. $order_trade_info = [];
  178. $goods_stock_arr = [];
  179. $open_group_id = 0;
  180. //只有一个订单
  181. $order_id_arr = [];
  182. foreach ($group_order_goods as $mch_order) {
  183. $mch_order_info = $mch_order['mch_order_info'];
  184. $order = new GroupBuyOrder();
  185. $order->loadDefaultValues();
  186. $order->load($mch_order_info, '');
  187. $order->remark = $data['remark'];
  188. $order->order_status = OrderStatusEnum::NOT_PAY;
  189. $order->total_pay_price = $mch_order_info['pay_money'];
  190. $order->order_no = StringHelper::generateOrderNo('gy');
  191. $marketing = [];
  192. if (isset($form->marketing['deduct']['shipping_fee'])) {
  193. $marketing['shipping_fee'] = $form->marketing['deduct']['shipping_fee'];
  194. }
  195. if (isset($form->marketing['deduct']['is_free_open_group'])) {
  196. $marketing['is_free_open_group'] = $form->marketing['deduct']['is_free_open_group'];
  197. }
  198. $order->marketing = $marketing;
  199. $res = $order->save();
  200. if ($res === false) throw new \Exception($order->getErrorMessage());
  201. $order_id_arr[]=$order->id;
  202. if (empty($mch_order_info['open_group_id'])) {
  203. $order->open_group_id = $order->id;
  204. $order->save();
  205. }
  206. $open_group_id = $order->open_group_id;
  207. // 总商品库存维护
  208. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR , $mch_order_info['goods_attr_id']);
  209. $identification = uniqid();
  210. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多');
  211. $stock_locks[$lock_key] = $identification;
  212. //操作商品库存-减
  213. GroupBuyActiveGoodsAttr::handleStock($form['mall_id'], $mch_order_info['group_buy_active_id'], $mch_order_info['goods_attr_id'], $mch_order_info['num'] * -1);
  214. if (!isset($goods_stock_arr[$mch_order_info['goods_id']])) {
  215. $goods_stock_arr[$mch_order_info['goods_id']] = $mch_order_info['num'];
  216. } else {
  217. $goods_stock_arr[$mch_order_info['goods_id']] += $mch_order_info['num'];
  218. }
  219. $order_trade_info[] = [
  220. 'order_id' => $order->id,
  221. 'order_no' => $order->order_no,
  222. 'amount' => $order->total_pay_price,
  223. 'title' => mb_strlen($mch_order_info['goods_name']) > 32 ? mb_substr($mch_order_info['goods_name'], 0, 32) : $mch_order_info['goods_name'],
  224. 'notify_class' => GroupBuyEnum::NOTIFY_CLASS,
  225. 'order_type' => PaymentTradeOrderEnum::GROUP_BUY_ORDER,
  226. ];
  227. foreach ($goods_stock_arr as $goods_id => $num) {
  228. $active_model = GroupBuyActive::findOne(['mall_id' => $form['mall_id'], 'id' => $data['active_id'], 'goods_id' => $goods_id]);
  229. $active_model->goods_stock -= $num;
  230. $active_model->save();
  231. }
  232. }
  233. $trans->commit();
  234. LockHelper::batchUlock($stock_locks);
  235. //生成支付流水
  236. $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info);
  237. if ($res == false) throw new \Exception('生成支付流水失败');
  238. // 更新订单金额
  239. $payment = PaymentTrade::findOne(['id' => $res['trade_id']]);
  240. GroupBuyOrder::updateAll(['out_trade_no'=>$res['trade_no'], 'total_pay_price' => $payment->pay_fee],['id'=>$order_id_arr]);
  241. $arr['transaction'] = $res;
  242. $arr['open_group_id'] = $open_group_id;
  243. $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link');// 支付成功后跳转的地址
  244. return $arr;
  245. } catch (\Exception $e) {
  246. LockHelper::batchUlock($stock_locks);
  247. if (isset($trans)) $trans->rollback();
  248. self::$static_error = $e->getMessage();
  249. return false;
  250. }
  251. }
  252. /**
  253. * @desc:取消拼团订单
  254. * @Author: hua
  255. * @Date: 2021/12/15
  256. * @Time: 17:19
  257. * @Copyright: copyright (c) 2021 广东七件事集团
  258. * @param $params
  259. * @param false $force
  260. * @return GroupBuyOrder|false
  261. * @throws \yii\db\Exception
  262. */
  263. public static function close($params, $force = false)
  264. {
  265. $trans = Yii::$app->db->beginTransaction();
  266. $stock_locks = [];
  267. try {
  268. $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]];
  269. isset($params['user_id']) && $cond['user_id'] = $params['user_id'];
  270. $model = self::findOne($cond);
  271. if (empty($model)) throw new \Exception('订单不存在或已删除');
  272. // 判断订单是否已经被关闭
  273. if ($model->order_status == GroupBuyEnum::GROUP_CLOSE) throw new Exception('订单已经关闭');
  274. // 判断是否是未支付的订单
  275. if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理');
  276. $model->order_status = GroupBuyEnum::GROUP_CLOSE;
  277. if (!$model->save()) throw new Exception($model->getErrorMessage());
  278. self::rollBackStock($model, $stock_locks);//回退库存
  279. $trans->commit();
  280. LockHelper::batchUlock($stock_locks);
  281. return $model;
  282. } catch (Exception $e) {
  283. $trans->rollback();
  284. LockHelper::batchUlock($stock_locks);
  285. self::$static_error = $e->getMessage();
  286. return false;
  287. }
  288. }
  289. /**
  290. * @desc:回退库存
  291. * @Author: hua
  292. * @Date: 2021/12/15
  293. * @Time: 17:34
  294. * @Copyright: copyright (c) 2021 广东七件事集团
  295. * @param $model
  296. * @param $stock_locks
  297. * @throws Exception
  298. */
  299. public static function rollBackStock($model, &$stock_locks)
  300. {
  301. $goods_attr_arr[$model->goods_attr_id] = $model->num;
  302. //操作规格库存-回退
  303. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR , $model->goods_attr_id);
  304. $identification = uniqid();
  305. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多');
  306. $stock_locks[$lock_key] = $identification;
  307. //操作商品库存-回退
  308. GroupBuyActiveGoodsAttr::handleStock($model->mall_id, $model->group_buy_active_id, $model->goods_attr_id, $model->num);
  309. $stock = GroupBuyActiveGoodsAttr::find()->where(['mall_id' => $model->mall_id, 'group_buy_active_id' => $model->group_buy_active_id, 'goods_id' => $model->goods_id])->sum('stock');
  310. $stock = $stock ?? 0;
  311. $res = GroupBuyActive::updateAll(['goods_stock' => $stock], ['mall_id' => $model->mall_id, 'id' => $model->group_buy_active_id, 'goods_id' => $model->goods_id]);
  312. if (!$res) throw new \Exception(Goods::getStaticError());
  313. }
  314. /**
  315. * @desc:结束拼团
  316. * @Author: hua
  317. * @Date: 2021/12/15
  318. * @Time: 11:43
  319. * @Copyright: copyright (c) 2021 广东七件事集团
  320. * @param $mall_id
  321. * @param $open_group_id
  322. * @return bool
  323. */
  324. public static function finishGroupBuyOrder($mall_id, $open_group_id)
  325. {
  326. // 避免并发
  327. $finishGroupBuyOrderLockKey = RedisKeyEnum::suffix('GroupBuy:finishGroupBuyOrder:', $open_group_id);
  328. $identification = uniqid('', true);
  329. if (!LockHelper::lock($finishGroupBuyOrderLockKey, $identification, 60, 60)) throw new Exception('当前访问太频繁');
  330. Yii::$app->db->close();
  331. $t = Yii::$app->db->beginTransaction();
  332. $stock_locks = [];
  333. try {
  334. $list = self::findAll(['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => GroupBuyEnum::JOINING]);
  335. foreach ($list as $group_buy_order) {
  336. //退款逻辑
  337. $desc = '用户(' . $group_buy_order->user_id . '),拼团失败,订单(' . $group_buy_order->id . ')退款:,金额:' . $group_buy_order->total_pay_price;
  338. $payment_order = PaymentTradeOrder::findOne(['order_no'=>$group_buy_order->order_no]);
  339. $payment_trade = PaymentTrade::findOne(['id'=>$payment_order->trade_id]);
  340. try {
  341. $res = Yii::$app->services->pay->refund($payment_trade->pay_fee,$payment_trade->pay_fee, $payment_trade->out_trade_no, $group_buy_order,$desc, UserWalletEnum::FROM_GROUP_BUY, UserWalletEnum::REFUND_ORDER);
  342. if ($res == false) throw new \Exception('退款失败');
  343. }catch (Exception $e){
  344. var_dump('finishGroupBuyOrder:::'.$e->getMessage());
  345. continue;
  346. }
  347. //归还库存
  348. self::rollBackStock($group_buy_order, $stock_locks);
  349. }
  350. //拼团失败
  351. $res = self::updateAll(['order_status' => GroupBuyEnum::GROUP_FAILURE], ['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => GroupBuyEnum::JOINING]);
  352. if ($res == false) throw new \Exception(self::getStaticError());
  353. LockHelper::uLock($finishGroupBuyOrderLockKey, $identification);
  354. LockHelper::batchUlock($stock_locks);
  355. $t->commit();
  356. return true;
  357. } catch (Exception $e) {
  358. $t->rollback();
  359. LockHelper::uLock($finishGroupBuyOrderLockKey, $identification);
  360. LockHelper::batchUlock($stock_locks);
  361. self::$static_error = $e->getMessage();
  362. return false;
  363. }
  364. }
  365. public static function finishGroupBuyOrderSync($data){
  366. self::finishGroupBuyOrder($data['mall_id'],$data['open_group_id']);
  367. }
  368. /**
  369. * @desc:支付
  370. * @Author: hua
  371. * @Date: 2021/12/15
  372. * @Time: 15:15
  373. * @Copyright: copyright (c) 2021 广东七件事集团
  374. * @param $params
  375. * @param $peyment_type
  376. * @return GroupBuyOrder|false
  377. */
  378. public static function pay($params, $peyment_type)
  379. {
  380. $trans = Yii::$app->db->beginTransaction();
  381. try {
  382. $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]);
  383. if (empty($model)) throw new \Exception('订单不存在或已删除');
  384. if ($model->is_pay != OrderStatusEnum::NOT_PAY) throw new \Exception('订单已经被处理,无法进行支付');
  385. if ($model->is_pay == StatusEnum::ENABLED) throw new \Exception('订单已支付,请不要重复支付');
  386. $model->is_pay = OrderStatusEnum::PAY;
  387. $model->order_status = GroupBuyEnum::JOINING;
  388. $model->payment_type = $peyment_type;
  389. $model->pay_time = time();
  390. $res = $model->save();
  391. if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage());
  392. $trans->commit();
  393. // 触发订单支付事件,事务提交完成后触发
  394. $event = new OrderPaidEvent($model->mall_id);
  395. $order['id'] = $model['id'];
  396. $order['operator_id'] = $params['operator_id'] ?? '';
  397. $order['operator_name'] = $params['operator_name'] ?? '';
  398. Yii::$app->services->events->dispatch($event, $order, $event->listeners);
  399. return $model;
  400. } catch (\Exception $e) {
  401. if (isset($trans)) $trans->rollback();
  402. self::$static_error = $e->getMessage();
  403. return false;
  404. }
  405. }
  406. /**
  407. * @desc:延时队列,执行自动关闭拼团订单
  408. * @Author: hua
  409. * @Date: 2022/1/4
  410. * @Time: 10:38
  411. * @Copyright: copyright (c) 2021 广东七件事集团
  412. * @param $data
  413. */
  414. public static function autoFinish($data){
  415. $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_OPEN_GROUP_ID , $data['open_group_id']);
  416. $identification = uniqid();
  417. try {
  418. if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多:order_id:' . $data['order_id']);
  419. $group_buy_order = self::findOne( ['id' => $data['order_id'],'open_group_id'=>$data['open_group_id'],'is_pay'=>1,'order_status' => GroupBuyEnum::JOINING]);
  420. if(empty($group_buy_order)) throw new Exception('该订单不存在');
  421. $active = GroupBuyActive::findOne(['mall_id' => $group_buy_order->mall_id, 'id' => $group_buy_order->group_buy_active_id]);
  422. $where = [
  423. ['mall_id' => $group_buy_order->mall_id],
  424. ['group_buy_active_id' => $group_buy_order->group_buy_active_id],
  425. ['open_group_id' => $group_buy_order->open_group_id],
  426. ['is_pay' => 1],
  427. ['order_status' => GroupBuyEnum::JOINING],
  428. ];
  429. $limit = $active->gt_group_size?$active->gt_group_size:$active->group_size;
  430. $list = GroupBuyOrder::lists(['where' => $where, 'order' => 'pay_time asc,id asc', 'limit' => $limit], false);
  431. $counts = count($list);
  432. if ($counts>=$active->group_size){
  433. //拼团成功(虚拟和非虚拟)
  434. $res = GroupBuyOrder::addMainOrder($group_buy_order,$list,$active,$counts);
  435. if($res==false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['order_id']);
  436. }else{
  437. if ($active->is_virtual && $active->virtual_group_type == 2 && $counts >= $active->gt_group_size) {
  438. //虚拟拼团成功
  439. $res = GroupBuyOrder::addMainOrder($group_buy_order,$list,$active,$counts);
  440. if($res==false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['order_id']);
  441. }else{
  442. $res = self::finishGroupBuyOrder($group_buy_order->mall_id,$group_buy_order->open_group_id);
  443. if ($res == false) {
  444. throw new Exception(' 开团id[ID:' . $group_buy_order->open_group_id . ']过期,执行拼团结束失败, errmsg: ' . GroupBuyOrder::getStaticError() . PHP_EOL);
  445. }
  446. }
  447. }
  448. LockHelper::uLock($lock_key, $identification);
  449. }catch (Exception $e){
  450. $e->getMessage();
  451. LockHelper::uLock($lock_key, $identification);
  452. }
  453. }
  454. /**
  455. * @desc:生成主订单
  456. * @Author: hua
  457. * @Date: 2022/1/4
  458. * @Time: 10:33
  459. * @Copyright: copyright (c) 2021 广东七件事集团
  460. * @param $last_order
  461. * @param $list
  462. * @param $active
  463. * @param $counts
  464. */
  465. public static function addMainOrder($last_order,$list,$active,$counts){
  466. $t = Yii::$app->db->beginTransaction();
  467. try {
  468. $goods = Goods::findOne(['id' => $last_order->goods_id]);
  469. $goods_attr = GoodsAttr::findOne(['id' => $last_order->goods_attr_id]);
  470. $marketing_type = GroupBuyEnum::ADDONS_NAME;
  471. $total_num = $total_orders_price = 0;
  472. //成功开团,往主订单写入数据
  473. $main_order_id_arr = [];
  474. foreach ($list as $group_buy_order) {
  475. $order_id = self::createMallOrder($group_buy_order, $marketing_type, $goods, $goods_attr);
  476. $group_buy_order->order_id = $order_id;
  477. $main_order_id_arr[$group_buy_order->user_id] = $order_id;
  478. $group_buy_order->order_status = GroupBuyEnum::GROUP_SUCCESS;
  479. $group_buy_order->win_time = $last_order->created_at;
  480. $res = $group_buy_order->save();
  481. if ($res == false) throw new \Exception('开团成功回写主订id失败');
  482. $total_num += $group_buy_order['num'];
  483. $total_orders_price += $group_buy_order['group_buy_price'] * $group_buy_order['num'];
  484. }
  485. $active->total_num += $total_num +($active->group_size-$counts);
  486. $active->total_orders += $counts;
  487. $active->total_orders_price += $total_orders_price;
  488. $res = $active->save();
  489. if ($res == false) throw new \Exception('更新拼团活动失败');
  490. $t->commit();
  491. self::giveReward($last_order->commander_id, GroupBuyOrder::tableName(), $last_order->open_group_id, $active);
  492. // 触发订单支付事件,事务提交完成后触发
  493. $user_id_arr = array_keys($main_order_id_arr);
  494. $user_list = User::lists(['where' => [['id' => $user_id_arr]], 'index' => 'id']);
  495. foreach ($main_order_id_arr as $user_id => $order_id) {
  496. $event = new \common\events\order\OrderPaidEvent($last_order->mall_id);
  497. $order['id'] = $order_id;
  498. $order['operator_id'] = $user_id;
  499. $order['operator_name'] = $user_list[$user_id]['nickname'] ?? '';
  500. Yii::$app->services->events->dispatch($event, $order, $event->listeners);
  501. }
  502. return true;
  503. }catch (Exception $e){
  504. $t->rollBack();
  505. $exception = FormatHelper::exception($e, "订单支付触发拼团事件");
  506. echo $exception;
  507. Yii::error($exception);
  508. return false;
  509. }
  510. }
  511. /**
  512. * @desc:生成主订单
  513. * @Author: hua
  514. * @Date: 2021/12/16
  515. * @Time: 14:32
  516. * @Copyright: copyright (c) 2021 广东七件事集团
  517. * @param $group_buy_order
  518. * @param $marketing_type
  519. * @param $goods
  520. * @param $goods_attr
  521. * @return int
  522. * @throws Exception
  523. */
  524. public static function createMallOrder($group_buy_order, $marketing_type, $goods, $goods_attr)
  525. {
  526. $order = new Order();
  527. $order->loadDefaultValues();
  528. $order->load($group_buy_order->toArray(), '');
  529. $order->order_status = OrderStatusEnum::PAY;
  530. $order->marketing_id = $group_buy_order->group_buy_active_id;
  531. $order->marketing_type = $marketing_type;
  532. $order->goods_price = $group_buy_order->group_buy_price;
  533. $order->pay_money = $group_buy_order->total_pay_price;
  534. $order->shipping_money = $group_buy_order->shipping_money;
  535. $order->shipping_type = $group_buy_order->shipping_type;
  536. $order->original_goods_price = $goods_attr->original_price;
  537. $order->pay_status = 1;
  538. $res = $order->save();
  539. if ($res == false) throw new \Exception('开团成功生成主订单失败');
  540. self::createMallOrderDetail($group_buy_order, $order->id, $goods, $goods_attr, $marketing_type);
  541. return $order->id;
  542. }
  543. /**
  544. * @desc:生成主订单详情
  545. * @Author: hua
  546. * @Date: 2021/12/16
  547. * @Time: 14:32
  548. * @Copyright: copyright (c) 2021 广东七件事集团
  549. * @param $group_buy_order
  550. * @param $order_id
  551. * @param $goods
  552. * @param $goods_attr
  553. * @param $marketing_type
  554. * @throws Exception
  555. */
  556. public static function createMallOrderDetail($group_buy_order, $order_id, $goods, $goods_attr, $marketing_type)
  557. {
  558. // 订单详情
  559. $order_detail = new OrderDetail();
  560. $order_detail->loadDefaultValues();
  561. $order_detail->user_id = $group_buy_order->user_id;
  562. $order_detail->mall_id = $group_buy_order->mall_id;
  563. $order_detail->mch_id = $group_buy_order->mch_id;
  564. $order_detail->order_id = $order_id;
  565. $order_detail->goods_id = $group_buy_order->goods_id;
  566. $order_detail->goods_attr_id = $group_buy_order->goods_attr_id;
  567. $order_detail->goods_name = $group_buy_order->goods_name;
  568. $order_detail->goods_attr_name = $group_buy_order->goods_attr_name;
  569. $order_detail->price = $group_buy_order->price;
  570. $order_detail->cost_price = $goods_attr->cost_price;
  571. $order_detail->original_goods_price = bcmul($goods_attr->price, $group_buy_order->num, 2);
  572. $order_detail->goods_price = $group_buy_order->group_buy_price;
  573. $order_detail->num = $group_buy_order->num;
  574. $order_detail->pic_url = $group_buy_order->pic_url;
  575. $order_detail->marketing_id = $group_buy_order->group_buy_active_id;
  576. $order_detail->marketing_type = $marketing_type;
  577. $order_detail->order_status = OrderStatusEnum::PAY;
  578. $order_detail->remark = $group_buy_order->remark;
  579. //$order_detail->is_virtual = $goods->goods_type;
  580. $order_detail->is_virtual = $goods->goods_type == GoodsTypeEnum::GoodsTypeVirtual ? 1 : 0;
  581. $res = $order_detail->save();
  582. if ($res == false) throw new \Exception('开团成功生成订单详情失败');
  583. }
  584. /**
  585. * @desc:拼团奖励
  586. * @Author: hua
  587. * @Date: 2022/1/4
  588. * @Time: 10:35
  589. * @Copyright: copyright (c) 2021 广东七件事集团
  590. * @param $user_id
  591. * @param $source_table
  592. * @param $open_group_id
  593. * @param $active
  594. * @throws Exception
  595. */
  596. public static function giveReward($user_id, $source_table, $open_group_id, $active)
  597. {
  598. $insert_wallet = [];
  599. $give_arr = ['balance' => ['numbers' => $active->give_balance, 'name' => '余额'], 'score' => ['numbers' => $active->give_score, 'name' => '积分']];
  600. foreach ($give_arr as $code => $item) {
  601. if ($item['numbers']) {
  602. $desc = '用户(' . $user_id . '),获得开团(' . $open_group_id . ')奖励,奖励类型:' . $item['name'] . ',数量:' . $item['numbers'];
  603. $insert_wallet [] = ['mall_id' => $active->mall_id, 'user_id' => $user_id,
  604. 'is_frozen' => false, 'wallet_type' => $code, 'money' => $item['numbers'],
  605. 'desc' => $desc,
  606. 'source_table' => $source_table,
  607. 'source_table_id' => $open_group_id,
  608. 'from_type' => UserWalletEnum::FROM_GROUP_BUY,
  609. 'capital_type' => UserWalletEnum::GIVE,
  610. ];
  611. }
  612. }
  613. if (!empty($insert_wallet)) {
  614. UserWalletService::batchHandleByQueue($insert_wallet);
  615. }
  616. }
  617. public static function check($params): bool
  618. {
  619. $order_no_arr = $params['order_no_arr'];
  620. $payment_order_list = $params['payment_order_list'];
  621. $counts = GroupBuyOrder::find()->where(['order_no'=>$order_no_arr,'is_pay'=>0])->count();
  622. if ($counts != count($payment_order_list)) {
  623. self::$static_error = '拼团订单不一致';
  624. return false;
  625. }
  626. return true;
  627. }
  628. }