50], [['remark', 'goods_name', 'goods_attr_name', 'pic_url'], 'string', 'max' => 255], [['mobile'], 'string', 'max' => 11], [['receiver_name'], 'string', 'max' => 50], [['zip'], 'string', 'max' => 20], [['address', 'region_name'], 'string', 'max' => 200], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => 'id', 'mall_id' => '商城ID', 'mch_id' => '商户id', 'user_id' => '用户ID', 'order_id' => '主订单表id', 'order_no' => '订单编号', 'out_trade_no' => '外部交易号', 'final_out_trade_no' => '外部交易号(尾款)', 'deposit_presale_active_id' => '定金预售活动id', 'open_group_id' => '开团id', 'commander_id' => '定金预售长id', 'is_commander' => '是否团长 0:否:1:是', 'goods_id' => '商品id', 'goods_attr_id' => '商品规格id', 'pic_url' => '商品图片', 'order_status' => '定金预售状态 0待支付 1参团中 2定金预售成功 3定金预售失败', 'price' => '商品原销售价格', 'deposit_presale_price' => '定金预售商品价格', 'actual_deposit_paid' => '实际支付的定金', 'deposit_payable' => '应付定金(活动创建设定的)', 'num' => '购买数量', 'win_time' => '拼中时间', 'payment_type' => '支付方式:1.在线支付 2.货到付款 3.余额支付', 'pay_time' => '支付时间', 'final_payment_time' => '尾款支付时间', 'total_pay_price' => '实际支付总费用(含运费)', 'remark' => '用户订单备注', 'is_pay' => '是否支付:0.未支付|1.已支付', 'status' => '状态[-1:删除;0:禁用;1启用]', 'created_at' => '创建时间', 'updated_at' => '更新时间', 'mobile' => '收货人的手机号码', 'receiver_name' => '收货人姓名', 'province' => '收货人所在省', 'city' => '收货人所在城市', 'area' => '收货人所在街道', 'zip' => '收货人邮编', 'address' => '详细地址', 'region_name' => '地区名称(省市区[乡/镇])', ]; } // 关联模型 public function getUser() { return $this->hasOne(User::class, ['id' => 'user_id']); } public function getDepositPresaleActive() { return $this->hasOne(DepositPresaleActive::class, ['id' => 'deposit_presale_active_id']); } public function getMainOrder() { return $this->hasOne(Order::class, ['id' => 'order_id']); } /** * @desc:生成订单 * @Author: hua * @Date: 2021/12/15 * @Time: 15:14 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $form * @return array|false */ public static function createOrder($form) { $stock_locks = []; try { $group_order_goods = $form['group_order_goods']; $data = is_array($form->data) ? $form->data : Json::decode($form->data, true); $trans = Yii::$app->db->beginTransaction(); // 生成主商城订单 $order_ids = self::generateMainOrder($group_order_goods, $form, $data); $order_trade_info = []; $goods_stock_arr = []; $open_group_id = 0; //只有一个订单 $order_id_arr = []; // 生成活动订单 foreach ($group_order_goods as $mch_order) { $mch_order_info = $mch_order['mch_order_info']; $order = new DepositPresaleOrder(); $order->loadDefaultValues(); $order->load($mch_order_info, ''); $order->remark = $data['remark']; $order->order_status = OrderStatusEnum::NOT_PAY; $order->total_pay_price = $mch_order_info['pay_money']; $order->actual_deposit_paid = $mch_order_info['pay_money']; $order->order_no = StringHelper::generateOrderNo('dp'); $order->order_id = $order_ids[0]; $res = $order->save(); if ($res === false) throw new \Exception($order->getErrorMessage()); $order_id_arr[] = $order->id; if (empty($mch_order_info['open_group_id'])) { $order->open_group_id = $order->id; $order->save(); } $open_group_id = $order->open_group_id; // 总商品库存维护 $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR, $mch_order_info['goods_attr_id']); $identification = uniqid(); if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多'); $stock_locks[$lock_key] = $identification; //操作商品库存-减 DepositPresaleActiveGoodsAttr::handleStock($form['mall_id'], $mch_order_info['deposit_presale_active_id'], $mch_order_info['goods_attr_id'], $mch_order_info['num'] * -1); if (!isset($goods_stock_arr[$mch_order_info['goods_id']])) { $goods_stock_arr[$mch_order_info['goods_id']] = $mch_order_info['num']; } else { $goods_stock_arr[$mch_order_info['goods_id']] += $mch_order_info['num']; } $order_trade_info[] = [ 'order_no' => $order->order_no, 'amount' => $order->total_pay_price, 'title' => mb_strlen($mch_order_info['goods_name']) > 32 ? mb_substr($mch_order_info['goods_name'], 0, 32) : $mch_order_info['goods_name'], 'notify_class' => DepositPresaleEnum::NOTIFY_CLASS, 'order_type' => DepositPresaleEnum::ADDONS_NAME, ]; foreach ($goods_stock_arr as $goods_id => $num) { $active_model = DepositPresaleActive::findOne(['mall_id' => $form['mall_id'], 'id' => $data['active_id'], 'goods_id' => $goods_id]); $active_model->goods_stock -= $num; $active_model->save(); } } // if($order){ // OrderAction::create("手机号为:{$order->mobile}用户订单创建成功", $order_ids[0], 0, $order->user_id, $order->receiver_name); // } $trans->commit(); LockHelper::batchUlock($stock_locks); //生成支付流水 $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info); if ($res == false) throw new \Exception('生成支付流水失败'); DepositPresaleOrder::updateAll(['out_trade_no' => $res['trade_no']], ['id' => $order_id_arr]); $deposit_event = new DepositOrderCreateEvent($form['mall_id']); Yii::$app->services->events->dispatch($deposit_event, ['id' => $order_id_arr[0]], $deposit_event->listeners); Order::updateAll(['out_trade_no' => $res['trade_no']], ['id' => $order_ids]); // 触发订单添加事件,事务提交完成后触发 $event = new OrderCreateEvent($form['mall_id']); Yii::$app->services->events->dispatch($event, ['order_ids' => $order_ids], $event->listeners); $arr['transaction'] = $res; $arr['open_group_id'] = $open_group_id; $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link'); // 支付成功后跳转的地址 return $arr; } catch (\Exception $e) { LockHelper::batchUlock($stock_locks); if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * @Description: 生成主商城订单 * @Author: observer3 * @DateTime 2022-05-23 21:22:24 * @param [type] $group_order_goods * @param [type] $form * @return array */ public static function generateMainOrder($group_order_goods, $form, $data) { $order_ids = []; $activity_model = null; foreach ($group_order_goods as $mch_order) { $mch_order_info = $mch_order['mch_order_info']; $main_order = new Order(); $main_order->loadDefaultValues(); $main_order->load($mch_order_info, ''); $main_order->order_status = OrderStatusEnum::NOT_PAY; $main_order->marketing_type = DepositPresaleEnum::ADDONS_NAME; $main_order->remark = $data['remark'] ?? ''; empty($main_order->order_no) && $main_order->order_no = Order::generateOrderNo('s'); $res = $main_order->save(); if ($res === false) throw new Exception($main_order->getErrorMessage()); if (!$activity_model) { $activity_model = DepositPresaleActive::findOne(['mall_id' => $form['mall_id'], 'id' => $mch_order_info['deposit_presale_active_id']]); } // 设置为支付尾款的结束时间,防止主商城自动关闭订单 if ($activity_model) { $main_order->created_at = $activity_model->final_payment_end_at; $res = $main_order->save(); if ($res === false) throw new Exception($main_order->getErrorMessage()); } $order_id = $main_order->id; $order_ids[] = $main_order->id; //$region_statistics[] = ['mall_id' => $order->mall_id, 'province_id' => $order->province, 'city_id' => $order->city, 'order' => $order->pay_money]; // 总商品库存维护 $goods_stock_arr = []; // 遍历商户商品 // $goods_ids = array_keys($mch_order['goods']); foreach ($mch_order['goods'] as $goods_id => $goods) { !isset($goods_name) && $goods_name = $goods['goods_name']; foreach ($goods['goods_details'] as $goods_detail) { // $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR, $goods_detail['goods_attr_id']); // $identification = uniqid(); // if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多'); // $stock_locks[$lock_key] = $identification; //操作商品库存-减 // GoodsAttr::handleStock($goods_detail['goods_attr_id'], $goods_detail['num'] * -1); if (!isset($goods_stock_arr[$goods_id])) { $goods_stock_arr[$goods_id] = $goods_detail['num']; } else { $goods_stock_arr[$goods_id] += $goods_detail['num']; } // 订单详情 $order_detail = new OrderDetail(); $order_detail->loadDefaultValues(); $order_detail->load($goods_detail, ''); $order_detail->order_id = $order_id; // $goods_statistics[] = ['goods_id' => $goods_detail['goods_id'], 'order_num' => 1, 'sales_num' => $goods_detail['num']]; $res = $order_detail->save(); if ($res === false) throw new Exception($order_detail->getErrorMessage()); $attr[$goods_detail['goods_attr_id']] = $goods_detail['num']; // 订单营销 if (!empty($goods_detail['marketing'])) { $order_marketing = new OrderMarketing(); $order_marketing->loadDefaultValues(); $order_marketing->load($goods_detail['marketing'], ''); $order_marketing->order_detail_id = $order_detail->id; $res = $order_marketing->save(); if ($res === false) throw new Exception($order_marketing->getErrorMessage()); } } } $data = is_array($form->data) ? $form->data : Json::decode($form->data, true); if (!empty($data['user_coupon_ids'])) { $user_coupon_id = $data['user_coupon_ids']; $res = AddonsCouponUserRelate::updateAll(['is_use' => 1], ['id' => $user_coupon_id]); if ($res === false) throw new Exception($main_order->getErrorMessage()); } } return $order_ids; } /** * @Description: 生成支付尾款的交易号 * @Author: code farmer 3 * @DateTime 2022-04-23 18:15:06 * @param array $form * @return bool|array */ public static function generateFinalPaymentTradeNo($form) { try { /** @var DepositPresaleOrder $order */ $order = $form['deposit_presale_order']; $order_trade_info = []; $total_pay_price = bcsub($order->deposit_presale_price, $order->deposit_price, 2); $order_trade_info[] = [ 'order_no' => $order->order_no, 'amount' => $total_pay_price, 'title' => mb_strlen($order->goods_name) > 32 ? mb_substr($order->goods_name, 0, 32) : $order->goods_name, 'notify_class' => DepositPresaleEnum::FINAL_NOTIFY_CLASS, 'order_type' => DepositPresaleEnum::ADDONS_NAME, ]; $trans = Yii::$app->db->beginTransaction(); if (!$order->final_out_trade_no) { //生成支付流水 $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info); if ($res == false) throw new \Exception('生成支付流水失败'); } else { $trade_model = \Yii::$app->services->pay->getByTradeNo($order->final_out_trade_no); if (!$trade_model) throw new \Exception('支付流水号异常'); $res = []; $res['trade_id'] = $trade_model->id; $res['trade_no'] = $trade_model->out_trade_no; } if (!$order->final_out_trade_no) { $update_res = DepositPresaleOrder::updateAll(['final_out_trade_no' => $res['trade_no']], ['id' => $order->id]); if ($update_res == false) throw new \Exception('保存支付流水号失败'); } $trans->commit(); $arr = []; $arr['transaction'] = $res; $arr['open_group_id'] = $order->id; $arr['total_pay_money'] = $total_pay_price; $arr['pay_success_page'] = Yii::$app->services->setting->mall->get($form['mall_id'], 'order.pay_after_link'); // 支付成功后跳转的地址 return $arr; } catch (\Exception $e) { if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * @desc:取消定金预售订单 * @Author: hua * @Date: 2021/12/15 * @Time: 17:19 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @param false $force * @return DepositPresaleOrder|false * @throws \yii\db\Exception */ public static function close($params, $force = false) { $trans = Yii::$app->db->beginTransaction(); $stock_locks = []; try { $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]]; isset($params['user_id']) && $cond['user_id'] = $params['user_id']; $model = self::findOne($cond); if (empty($model)) throw new \Exception('订单不存在或已删除'); // 判断订单是否已经被关闭 if ($model->order_status == DepositPresaleEnum::GROUP_CLOSE) throw new Exception('订单已经关闭'); // 判断是否是未支付的订单 if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理'); $model->order_status = DepositPresaleEnum::GROUP_CLOSE; if (!$model->save()) throw new Exception($model->getErrorMessage()); self::rollBackStock($model, $stock_locks); //回退库存 $params['id'] = $model->order_id; $params['created_at'] = $model->created_at; $res = self::mainOrderClose($params); if ($res === false) throw new Exception(self::getStaticError()); $trans->commit(); LockHelper::batchUlock($stock_locks); $event = new OrderCloseEvent($params['mall_id']); $order_data['id'] = $params['id']; $order_data['operator_id'] = $params['operator_id'] ?? 0; $order_data['operator_name'] = $params['operator_name'] ?? '系统'; Yii::$app->services->events->dispatch($event, $order_data, $event->listeners); return $model; } catch (Exception $e) { $trans->rollback(); LockHelper::batchUlock($stock_locks); self::$static_error = $e->getMessage(); return false; } } /** * 取消订单 * @Author bing * @DateTime 2021-09-14 15:43:18 * @copyright: Copyright (c) 2020 广东七件事集团 * @param [type] $params * @return order */ public static function mainOrderClose($params, $force = false) { // $trans = Yii::$app->db->beginTransaction(); $stock_locks = []; $close_lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS, $params['id']); try { // 加锁 $close_identification = uniqid(); $stock_locks[$close_lock_key] = $close_identification; if (!LockHelper::lock($close_lock_key, $close_identification, 30, 60)) throw new \Exception('正在关闭订单'); $cond = ['mall_id' => $params['mall_id'], 'id' => $params['id'], 'status' => [StatusEnum::ENABLED]]; isset($params['user_id']) && $cond['user_id'] = $params['user_id']; $model = Order::findOne($cond); if (empty($model)) throw new Exception('订单不存在或已删除'); // 判断订单是否已经被关闭 if ($model->order_status == OrderStatusEnum::REPEAL) throw new Exception('订单已经关闭'); // 判断是否是未支付的订单 if ($force == false && $model->order_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理'); $model->close_time = time(); $model->order_status = OrderStatusEnum::REPEAL; if (!empty($params['created_at']) && $params['created_at'] != $model->created_at) { $model->created_at = $params['created_at']; } if (!$model->save()) throw new Exception($model->getErrorMessage()); // $goods_attr_arr = array_column($model->detail,'num','goods_attr_id'); //操作规格库存-回退 // foreach ($goods_attr_arr as $goods_attr_id=>$num){ // $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GOODS_ATTR , $goods_attr_id); // $identification = uniqid(); // if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多'); // $stock_locks[$lock_key] = $identification; // //操作商品库存-回退 // GoodsAttr::handleStock($goods_attr_id,$num); // } // 订单营销扣减返还 $order_detail_id_arr = array_column($model->detail, 'id'); $res = OrderMarketing::deductBack($model->id, $order_detail_id_arr, $order_detail_id_arr, $model->mall_id, $model->user_id, '交易关闭返还'); if ($res == false) throw new Exception(OrderMarketing::getStaticError()); // $trans->commit(); // 解锁 LockHelper::batchUlock($stock_locks); return $model; } catch (Exception $e) { // $trans->rollback(); // 解锁 LockHelper::batchUlock($stock_locks); self::$static_error = $e->getMessage(); return false; } } /** * @desc:回退库存 * @Author: hua * @Date: 2021/12/15 * @Time: 17:34 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $model * @param $stock_locks * @throws Exception */ public static function rollBackStock($model, &$stock_locks) { $goods_attr_arr[$model->goods_attr_id] = $model->num; //操作规格库存-回退 $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_GOODS_ATTR, $model->goods_attr_id); $identification = uniqid(); if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多'); $stock_locks[$lock_key] = $identification; //操作商品库存-回退 DepositPresaleActiveGoodsAttr::handleStock($model->mall_id, $model->deposit_presale_active_id, $model->goods_attr_id, $model->num); $stock = DepositPresaleActiveGoodsAttr::find()->where(['mall_id' => $model->mall_id, 'deposit_presale_active_id' => $model->deposit_presale_active_id, 'goods_id' => $model->goods_id])->sum('stock'); $stock = $stock ?? 0; $res = DepositPresaleActive::updateAll(['goods_stock' => $stock], ['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id, 'goods_id' => $model->goods_id]); if (!$res) throw new \Exception(Goods::getStaticError()); } /** * @desc:结束定金预售 * @Author: hua * @Date: 2021/12/15 * @Time: 11:43 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $mall_id * @param $open_group_id * @return bool */ public static function finishDepositPresaleOrder($mall_id, $open_group_id) { Yii::$app->db->close(); $t = Yii::$app->db->beginTransaction(); $stock_locks = []; try { $deposit_presale_order = self::findOne(['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => DepositPresaleEnum::JOINING]); $order_id = 0; $user_id = 0; $config = Yii::$app->services->setting->addons->get($mall_id, DepositPresaleEnum::ADDONS_NAME, 'basic.general_settings'); if (!empty($config)) { $config = json_decode($config, true); } $is_refund = isset($config['is_refund_deposit']) ? (!empty($config['is_refund_deposit']['value']) ? 1 : 0) : 0; $created_at = 0; $order_id = $deposit_presale_order->order_id; $user_id = $deposit_presale_order->user_id; //归还库存 self::rollBackStock($deposit_presale_order, $stock_locks); if (!$created_at) $created_at = $deposit_presale_order->created_at; //拼团失败 $res = self::updateAll(['order_status' => DepositPresaleEnum::GROUP_FAILURE], ['mall_id' => $mall_id, 'open_group_id' => $open_group_id, 'order_status' => DepositPresaleEnum::JOINING]); if ($res == false) { throw new \Exception(self::getStaticError()); } $params = [ 'mall_id' => $mall_id, 'user_id' => $user_id, 'id' => $order_id, 'created_at' => $created_at, ]; $res = self::mainOrderClose($params); if ($res === false) { throw new Exception(self::getStaticError()); } if ($is_refund) { //退款逻辑 $payment_order = PaymentTradeOrder::findOne(['order_no' => $deposit_presale_order->order_no, 'is_pay' => StatusEnum::ENABLED]); $payment_trade = PaymentTrade::findOne(['id' => $payment_order->trade_id]); $desc = '用户(' . $deposit_presale_order->user_id . '),预定失败,订单(' . $deposit_presale_order->id . ')退款:,金额:' . $payment_trade->pay_fee; $res = Yii::$app->services->pay->refund($payment_trade->pay_fee, $payment_trade->pay_fee, $payment_trade->out_trade_no, $deposit_presale_order, $desc, DepositPresaleEnum::ADDONS_NAME, UserWalletEnum::REFUND_ORDER); if ($res == false) throw new \Exception('退款失败'); } LockHelper::batchUlock($stock_locks); $t->commit(); // 触发订单取消事件 $event = new OrderCloseEvent($mall_id); $order_data['id'] = $params['id']; $order_data['operator_id'] = $params['operator_id'] ?? 0; $order_data['operator_name'] = $params['operator_name'] ?? '系统'; Yii::$app->services->events->dispatch($event, $order_data, $event->listeners); return true; } catch (Exception $e) { $t->rollback(); LockHelper::batchUlock($stock_locks); self::$static_error = $e->getMessage(); return false; } } public static function finishDepositPresaleOrderSync($data) { self::finishDepositPresaleOrder($data['mall_id'], $data['open_group_id']); } /** * @desc:支付 * @Author: hua * @Date: 2021/12/15 * @Time: 15:15 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @param $peyment_type * @return DepositPresaleOrder|false */ public static function pay($params, $peyment_type) { $trans = Yii::$app->db->beginTransaction(); try { $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]); if (empty($model)) throw new \Exception('订单不存在或已删除'); if ($model->is_pay != OrderStatusEnum::NOT_PAY) throw new \Exception('订单已经被处理,无法进行支付'); if ($model->is_pay == StatusEnum::ENABLED) throw new \Exception('订单已支付,请不要重复支付'); $model->is_pay = OrderStatusEnum::PAY; $model->order_status = DepositPresaleEnum::JOINING; $model->payment_type = $peyment_type; $model->pay_time = time(); $active_model = DepositPresaleActive::findOne($model->deposit_presale_active_id); if (empty($active_model)) throw new \Exception('预售活动不存在或已删除'); $num = 1; $order_detail = OrderDetail::findOne(['mall_id' => $model->mall_id, 'order_id' => $model->order_id]); if ($order_detail) $num = $order_detail->num; $active_model->presale_total = $active_model->presale_total + $num; $active_res = $active_model->save(); if ($active_res === false) throw new \Exception('更新预定人数失败:' . $active_model->getErrorMessage()); // $result = DepositPresaleActive::updateDiyGoods(['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id, 'presale_total' => $active_model->presale_total]); // if($result === false) throw new \Exception('更新装修页预定人数失败:'. DepositPresaleActive::getStaticError()); $res = $model->save(); if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage()); OrderAction::create("手机号为:{$order_detail->order->mobile}用户订单支付定金成功", $model->order_id, 0, $model->user_id, $order_detail->order->receiver_name); $trans->commit(); // 触发订单支付事件,事务提交完成后触发 // $event = new OrderPaidEvent($model->mall_id); // $order['id'] = $model['id']; // $order['operator_id'] = $params['operator_id'] ?? ''; // $order['operator_name'] = $params['operator_name'] ?? ''; // Yii::$app->services->events->dispatch($event, $order, $event->listeners); if ($model->mainOrder) { $sms = new Sms($model->mall_id); $sms->createOrder($model->mobile, ['order_no' => $model->mainOrder->order_no, 'date' => date('Y-m-d H:i:s', $active_model->final_payment_start_at)]); self::sendTemplateMessage(1, $model->mainOrder, $active_model->final_payment_start_at); } return $model; } catch (\Exception $e) { if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * @Description: 支付尾款 * @Author: code farmer 3 * @DateTime 2022-04-23 17:28:50 * @param array $params * @param int $peyment_type * @return bool|DepositPresaleOrder */ public static function payFinalPayment($params, $peyment_type) { $trans = Yii::$app->db->beginTransaction(); try { $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]); if (empty($model)) throw new \Exception('订单不存在或已删除'); if ($model->is_pay != OrderStatusEnum::PAY) throw new \Exception('订单没有支付定金,无法进行尾款支付'); if ($model->order_status == DepositPresaleEnum::GROUP_SUCCESS) throw new \Exception('订单已支付尾款,请不要重复支付'); $model->order_status = DepositPresaleEnum::GROUP_SUCCESS; $model->payment_type = $peyment_type; $model->final_payment_time = time(); $trade_payment = PaymentTrade::find()->where(['out_trade_no' => $model->final_out_trade_no])->select(['pay_fee'])->one(); $model->total_pay_price = bcadd($model->total_pay_price, $trade_payment->pay_fee ?? 0, 2); $res = $model->save(); if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage()); $active_model = DepositPresaleActive::findOne(['mall_id' => $model->mall_id, 'id' => $model->deposit_presale_active_id]); $num = 1; $order_detail = OrderDetail::findOne(['mall_id' => $model->mall_id, 'order_id' => $model->order_id]); if ($order_detail) $num = $order_detail->num; $active_model->sales_num = $active_model->sales_num + $num; $result = $active_model->save(); if ($result === false) throw new \Exception('销量更新失败:' . $active_model->getErrorMessage()); OrderAction::create("手机号为:{$order_detail->order->mobile}用户订单支付尾款成功", $model->order_id, 1, $model->user_id, $order_detail->order->receiver_name); $trans->commit(); if ($model->depositPresaleActive) { if ($model->depositPresaleActive->delivery_time_way == 0) { $send_goods_start_at = $model->depositPresaleActive->send_goods_start_at; } else { $send_goods_start_at = $model->depositPresaleActive->final_payment_end_at + $model->depositPresaleActive->shipping_days * 86400; } } if ($model->mainOrder) { $sms = new Sms($model->mall_id); $sms->shipOrder($model->mobile, ['order_no' => $model->mainOrder->order_no, 'date' => date('Y-m-d H:i:s', $send_goods_start_at)]); self::sendTemplateMessage(2, $model->mainOrder, $send_goods_start_at); } return $model; } catch (\Exception $e) { if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * @desc:延时队列,执行自动关闭拼团订单 * @Author: hua * @Date: 2022/1/4 * @Time: 10:38 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $data */ public static function autoFinish($data) { $lock_key = RedisKeyEnum::suffix(RedisKeyEnum::LOCK_GROUP_BUY_OPEN_GROUP_ID, $data['open_group_id']); $identification = uniqid(); try { if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new Exception('当前访问人数过多:order_id:' . $data['id']); $deposit_presale_order = self::findOne(['id' => $data['order_id'], 'open_group_id' => $data['open_group_id'], 'is_pay' => 1, 'order_status' => DepositPresaleEnum::JOINING]); if (empty($deposit_presale_order)) throw new Exception('该订单不存在'); $active = DepositPresaleActive::findOne(['mall_id' => $deposit_presale_order->mall_id, 'id' => $deposit_presale_order->deposit_presale_active_id]); $where = [ ['mall_id' => $deposit_presale_order->mall_id], ['deposit_presale_active_id' => $deposit_presale_order->deposit_presale_active_id], ['open_group_id' => $deposit_presale_order->open_group_id], ['is_pay' => 1], ['order_status' => DepositPresaleEnum::JOINING], ]; $limit = $active->gt_group_size ? $active->gt_group_size : $active->group_size; $list = DepositPresaleOrder::lists(['where' => $where, 'order' => 'pay_time asc,id asc', 'limit' => $limit], false); $counts = count($list); if ($counts >= $active->group_size) { //拼团成功(虚拟和非虚拟) $res = DepositPresaleOrder::addMainOrder($deposit_presale_order, $list, $active, $counts); if ($res == false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['id']); } else { if ($active->is_virtual && $active->virtual_group_type == 2 && $counts >= $active->gt_group_size) { //虚拟拼团成功 $res = DepositPresaleOrder::addMainOrder($deposit_presale_order, $list, $active, $counts); if ($res == false) throw new \Exception('生成主订单错误,触发:order_id:' . $data['id']); } else { foreach ($list as $item) { $res = self::finishDepositPresaleOrder($item->mall_id, $item->open_group_id); if ($res == false) { throw new Exception(' 拼团订单[ID:' . $item->id . ']过期,执行拼团结束失败, errmsg: ' . DepositPresaleOrder::getStaticError() . PHP_EOL); } } } } LockHelper::uLock($lock_key, $identification); } catch (Exception $e) { LockHelper::uLock($lock_key, $identification); } } /** * @desc:生成主订单 * @Author: hua * @Date: 2022/1/4 * @Time: 10:33 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $last_order * @param $list * @param $active * @param $counts */ public static function addMainOrder($last_order, $list, $active, $counts) { $t = Yii::$app->db->beginTransaction(); try { $goods = Goods::findOne(['id' => $last_order->goods_id]); $goods_attr = GoodsAttr::findOne(['id' => $last_order->goods_attr_id]); $marketing_type = DepositPresaleEnum::ADDONS_NAME; $total_num = $total_orders_price = 0; //成功开团,往主订单写入数据 $main_order_id_arr = []; foreach ($list as $deposit_presale_order) { $order_id = self::createMallOrder($deposit_presale_order, $marketing_type, $goods, $goods_attr); $deposit_presale_order->order_id = $order_id; $main_order_id_arr[$deposit_presale_order->user_id] = $order_id; $deposit_presale_order->order_status = DepositPresaleEnum::GROUP_SUCCESS; $deposit_presale_order->win_time = $last_order->created_at; $res = $deposit_presale_order->save(); if ($res == false) throw new \Exception('开团成功回写主订id失败'); $total_num += $deposit_presale_order['num']; $total_orders_price += $deposit_presale_order['deposit_presale_price'] * $deposit_presale_order['num']; } $active->total_num += $total_num + ($active->group_size - $counts); $active->total_orders += $counts; $active->total_orders_price += $total_orders_price; $res = $active->save(); if ($res == false) throw new \Exception('更新拼团活动失败'); $t->commit(); self::giveReward($last_order->commander_id, DepositPresaleOrder::tableName(), $last_order->open_group_id, $active); // 触发订单支付事件,事务提交完成后触发 $user_id_arr = array_keys($main_order_id_arr); $user_list = User::lists(['where' => [['id' => $user_id_arr]], 'index' => 'id']); foreach ($main_order_id_arr as $user_id => $order_id) { $event = new \common\events\order\OrderPaidEvent($last_order->mall_id); $order['id'] = $order_id; $order['operator_id'] = $user_id; $order['operator_name'] = $user_list[$user_id]['nickname'] ?? ''; Yii::$app->services->events->dispatch($event, $order, $event->listeners); } return true; } catch (Exception $e) { $t->rollBack(); $exception = FormatHelper::exception($e, "订单支付触发拼团事件"); echo $exception; Yii::error($exception); return false; } } /** * @desc:生成主订单 * @Author: hua * @Date: 2021/12/16 * @Time: 14:32 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $deposit_presale_order * @param $marketing_type * @param $goods * @param $goods_attr * @return int * @throws Exception */ public static function createMallOrder($deposit_presale_order, $marketing_type, $goods, $goods_attr) { $order = new Order(); $order->loadDefaultValues(); $order->load($deposit_presale_order->toArray(), ''); $order->order_status = OrderStatusEnum::PAY; $order->marketing_id = $deposit_presale_order->deposit_presale_active_id; $order->marketing_type = $marketing_type; $order->goods_price = $deposit_presale_order->deposit_presale_price; $order->pay_money = $deposit_presale_order->total_pay_price; $order->shipping_money = $deposit_presale_order->shipping_money; $order->shipping_type = $deposit_presale_order->shipping_type; $order->original_goods_price = $goods_attr->original_price; $order->pay_status = 1; $res = $order->save(); if ($res == false) throw new \Exception('开团成功生成主订单失败'); self::createMallOrderDetail($deposit_presale_order, $order->id, $goods, $goods_attr, $marketing_type); return $order->id; } /** * @desc:生成主订单详情 * @Author: hua * @Date: 2021/12/16 * @Time: 14:32 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $deposit_presale_order * @param $order_id * @param $goods * @param $goods_attr * @param $marketing_type * @throws Exception */ public static function createMallOrderDetail($deposit_presale_order, $order_id, $goods, $goods_attr, $marketing_type) { // 订单详情 $order_detail = new OrderDetail(); $order_detail->loadDefaultValues(); $order_detail->user_id = $deposit_presale_order->user_id; $order_detail->mall_id = $deposit_presale_order->mall_id; $order_detail->mch_id = $deposit_presale_order->mch_id; $order_detail->order_id = $order_id; $order_detail->goods_id = $deposit_presale_order->goods_id; $order_detail->goods_attr_id = $deposit_presale_order->goods_attr_id; $order_detail->goods_name = $deposit_presale_order->goods_name; $order_detail->goods_attr_name = $deposit_presale_order->goods_attr_name; $order_detail->price = $deposit_presale_order->price; $order_detail->cost_price = $goods_attr->cost_price; $order_detail->original_goods_price = $goods_attr->original_price; $order_detail->goods_price = $deposit_presale_order->deposit_presale_price; $order_detail->num = $deposit_presale_order->num; $order_detail->pic_url = $deposit_presale_order->pic_url; $order_detail->marketing_id = $deposit_presale_order->deposit_presale_active_id; $order_detail->marketing_type = $marketing_type; $order_detail->order_status = OrderStatusEnum::PAY; $order_detail->remark = $deposit_presale_order->remark; //$order_detail->is_virtual = $goods->goods_type; $order_detail->is_virtual = $goods->goods_type == GoodsTypeEnum::GoodsTypeVirtual ? 1 : 0; $res = $order_detail->save(); if ($res == false) throw new \Exception('开团成功生成订单详情失败'); } /** * @desc:拼团奖励 * @Author: hua * @Date: 2022/1/4 * @Time: 10:35 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $user_id * @param $source_table * @param $open_group_id * @param $active * @throws Exception */ public static function giveReward($user_id, $source_table, $open_group_id, $active) { $insert_wallet = []; $give_arr = ['balance' => ['numbers' => $active->give_balance, 'name' => '余额'], 'score' => ['numbers' => $active->give_score, 'name' => '积分']]; foreach ($give_arr as $code => $item) { if ($item['numbers']) { $desc = '用户(' . $user_id . '),获得开团(' . $open_group_id . ')奖励,奖励类型:' . $item['name'] . ',数量:' . $item['numbers']; $insert_wallet[] = [ 'mall_id' => $active->mall_id, 'user_id' => $user_id, 'is_frozen' => false, 'wallet_type' => $code, 'money' => $item['numbers'], 'desc' => $desc, 'source_table' => $source_table, 'source_table_id' => $open_group_id, 'from_type' => UserWalletEnum::FROM_GROUP_BUY, 'capital_type' => UserWalletEnum::GIVE, ]; } } if (!empty($insert_wallet)) { UserWalletService::batchHandleByQueue($insert_wallet); } } /** * @Description: 订单收货 * @Author: code farmer 3 * @DateTime 2022-04-28 18:42:50 * @param array $data * @return bool */ public static function orderReceipt($data) { try { $order = self::findOne($data['id']); if (!$order) throw new Exception('订单不存在'); if (!$order->is_pay) throw new Exception('订单尚未支付定金'); if (!$order->final_payment_time) throw new Exception('订单尚未支付尾款'); // 活动订单收货 $order->order_status = DepositPresaleEnum::ORDER_RECEIPT; $res = $order->save(); if (!$res) throw new Exception($order->getErrorMessage()); $params = [ 'id' => $order->order_id, 'mall_id' => $order->mall_id, 'user_id' => $order->user_id, 'operator_id' => $data['operator_id'], 'operator_name' => $data['operator_name'] ]; // 主订单收货 $result = Order::takeDelivery($params); if ($result === false) throw new Exception(Order::getStaticError()); return true; } catch (Exception $e) { self::$static_error = $e->getMessage(); return false; } } public static function check($params): bool { $order_no_arr = $params['order_no_arr']; $payment_order_list = $params['payment_order_list']; $counts = DepositPresaleOrder::find()->where([ 'order_no' => $order_no_arr, // 'is_pay'=>0 ])->count(); if ($counts != count($payment_order_list)) { self::$static_error = '预售订单不一致'; return false; } return true; } public function appendFieldsToDetail($params) { if (!isset($params['order']) || !isset($params['order']['id'])) { return $params['order']; } // 追加预售订单信息部分 $data = $params['order']; $presale_order = DepositPresaleOrder::find()->where(['order_id' => $params['order']['id']])->select(['id', 'order_id', 'created_at', 'pay_time', 'final_payment_time'])->one(); if ($presale_order) { $data['created_at'] = $presale_order->created_at; $data['deposite_pay_time'] = $presale_order->pay_time ?: 0; $data['final_payment_time'] = $presale_order->final_payment_time ?: 0; isset($params['order']['pay_time']) && empty($params['order']['pay_time']) && $data['pay_time'] = -1; } $data['presale_info'] = [ 'is_presale' => $presale_order ? 1 : 0, 'presale_order_id' => $presale_order ? $presale_order->id : 0, 'created_at' => $presale_order ? $presale_order->created_at : 0, ]; return $data; } /** * @Description: 向主商城订单列表接口返回数据中追加字段 * @Author: Observer3 * @DateTime 2022-05-07 10:07:49 * @param array $params * @return array */ public function appendFieldsToList($params) { if (!isset($params['order']) || !is_array($params['order'])) return []; foreach ($params['order'] as &$item) { // 追加预售订单信息部分 $item['presale_info'] = [ 'is_presale' => 0, 'presale_order_id' => 0, 'is_pay_final_payment' => 0 ]; $presale_order = DepositPresaleOrder::find()->where([ 'and', ['order_id' => $item['id']], ['mall_id' => $item['mall_id']] ]) ->select(['id', 'order_id', 'is_pay', 'deposit_price', 'deposit_presale_price']) ->limit(1) ->one(); if ($presale_order) { // 是否为预售订单 $item['presale_info']['is_presale'] = 1; $item['presale_info']['presale_order_id'] = $presale_order->id; $item['presale_info']['is_pay_final_payment'] = $presale_order->is_pay ? 1 : 0; $item['presale_info']['deposit_price'] = $presale_order->deposit_price; $item['presale_info']['final_payment'] = bcsub($presale_order->deposit_presale_price, $presale_order->deposit_price, 2); } } return $params['order']; } /** * @Description: 修改预售订单对应的主商城订单创建时间 * @DateTime 2022-09-20 17:11:06 * @param array $params * @return array */ public function modifiedFieldsOfBackendList($params) { if (!isset($params['order']) || !is_array($params['order'])) return []; foreach ($params['order'] as &$item) { if (!isset($item['marketing_type']) || $item['marketing_type'] != DepositPresaleEnum::ADDONS_NAME) { continue; } $presale_order = DepositPresaleOrder::find()->where([ 'and', ['order_id' => $item['id']], ['mall_id' => $item['mall_id']] ]) ->select(['id', 'created_at']) ->limit(1) ->one(); if ($presale_order) { $item['created_at'] = $presale_order->created_at; } } return $params['order']; } /** * @Description: 执行控制台具体订单调用 * @Author: observer3 * @DateTime 2022-06-10 20:04:14 * @param [type] $params * @return array */ public function getAddonExpected($params) { if (!isset($params['order'])) return []; if (!isset($params['action'])) return []; $action_arr = ['close' => false]; $action_keys = array_keys($action_arr); $addons = [ DepositPresaleEnum::ADDONS_NAME => [ $params['action'] => in_array($params['action'], $action_keys) ? $action_arr[$params['action']] : 0 ] ]; return $addons; } /** * @Description: * @Author: observer3 * @DateTime 2022-05-13 19:33:30 * @param [type] $type * @param Order $order * @param [type] $time * @return void */ public static function sendTemplateMessage($type, $order, $time) { $order_detail = OrderDetail::findOne(['order_id' => $order->id]); $data = [ 'mall_id' => $order->mall_id, 'user_id' => $order->user_id, 'order_id' => $order->id, 'order_no' => $order->order_no, 'goods_name' => $order_detail ? $order_detail->goods_name : '', 'time' => $time, ]; switch ($type) { case 1: //支付定金后 self::sendDepositWechatTemplate($data); break; case 2: //支付尾款后 self::sendFinalWechatTemplate($data); break; } } /** * @Description: 支付定金发送模板消息 * @Author: observer3 * @DateTime 2022-05-13 17:25:36 * @param array $param * @return void|null */ public static function sendDepositWechatTemplate($param) { $wechat = new WechatTemplate($param['mall_id']); //插件是否开启推送模板消息 if ($wechat->is_logging() === false) { return; } //是否公众号用户 if ($wechat->is_platform_wechat($param['user_id']) === false) { return; } $platform = $wechat->getPlatForm(); $url = "/pages/order/detail?order_id=" . $param['order_id']; $h5_url = \Yii::$app->params['web_url'] . "/h5/#" . $url; $send_data = [ 'first' => '您好,您的订单已支付定金', 'keyword1' => date("Y-m-d H:i:s", time()), 'keyword2' => $param['goods_name'], 'keyword3' => $param['order_no'], 'remark' => '请留意在' . date("Y-m-d H:i:s", $param['time']) . '开始支付尾款' ]; $temp_key = WechatTemplate::ORDER_DEPOSIT; $wechat->sendTemplate($param['user_id'], $temp_key, $h5_url, $send_data, $platform, $url); } /** * @Description: 支付尾款发送模板消息 * @Author: observer3 * @DateTime 2022-05-13 17:26:20 * @param array $param * @return void|null */ public static function sendFinalWechatTemplate($param) { $wechat = new WechatTemplate($param['mall_id']); //插件是否开启推送模板消息 if ($wechat->is_logging() === false) { return; } //是否公众号用户 if ($wechat->is_platform_wechat($param['user_id']) === false) { return; } $platform = $wechat->getPlatForm(); $url = "/pages/order/detail?order_id=" . $param['order_id']; $h5_url = \Yii::$app->params['web_url'] . "/h5/#" . $url; $send_data = [ 'first' => '您好,您的订单已支付尾款', 'keyword1' => date("Y-m-d H:i:s", time()), 'keyword2' => $param['goods_name'], 'keyword3' => $param['order_no'], 'remark' => '将在' . date("Y-m-d H:i:s", $param['time']) . '开始发货' ]; $temp_key = WechatTemplate::ORDER_FINAL_PAYMENT; $wechat->sendTemplate($param['user_id'], $temp_key, $h5_url, $send_data, $platform, $url); } /** * 预售订单状态统计 */ public static function getOrderStatistics($mall_id) { $all_order_number = 0; $not_pay_order = 0; $just_pay_deposit = 0; $order_success = 0; $order_fail = 0; $data = self::find()->where([ 'and', ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED] ])->select('id, order_status, status') ->asArray() ->all(); foreach ($data as $item) { $all_order_number += 1; if ($item['order_status'] == 0) { $not_pay_order += 1; } if ($item['order_status'] == 1) { $just_pay_deposit += 1; } if ($item['order_status'] == 2) { $order_success += 1; } if ($item['order_status'] == 3) { $order_fail += 1; } } return compact('order_success', 'order_fail', 'just_pay_deposit', 'not_pay_order', 'all_order_number'); } /** * 获取订单详情订单状态 */ public static function getOrderStatus($main_order_detail, $order) { $status_text = ''; if (!$main_order_detail || !$order) { return $status_text; } switch ($order->order_status) { case DepositPresaleEnum::NOT_PAY: $status_text = '待付定金'; break; case DepositPresaleEnum::JOINING: $status_text = '待付尾款'; break; // case DepositPresaleEnum::GROUP_SUCCESS: // $status_text = '待发货'; // break; case DepositPresaleEnum::GROUP_FAILURE: $status_text = '预售失败'; break; case DepositPresaleEnum::GROUP_CLOSE: $status_text = '订单关闭'; break; } if (!$status_text) { $main_order_status_map = DepositPresaleEnum::getMainOrderStatusMap(); if (!isset($main_order_detail['detail'][0])) { return $status_text; } $status_text = $main_order_status_map[$main_order_detail['detail'][0]['order_status']] ?? $status_text; } return $status_text; } /** * @param array $order_ids * @return array */ public static function getMallOrderByOrderIds(array $order_ids) { return static::find() ->where(['order_id' => $order_ids]) ->select('id, order_id') ->asArray() ->all(); } }