50], [['cover_pic','goods_name','token', 'remark'], 'string', 'max' => 255], [['mobile'], 'string', 'max' => 11], [['zip'], 'string', 'max' => 20], [['address', 'region_name'], 'string', 'max' => 200], ]; } /** * {@inheritdoc} */ public function attributeLabels(): array { return [ 'id' => 'ID', 'mall_id' => 'Mall ID', 'user_id' => 'User ID', 'order_id' => '主订订单id', 'order_no' => '订单编号', 'bargain_active_id' => '砍价活动id', 'cover_pic' => 'cover_pic', 'goods_name' => 'goods_name', 'token' => 'Token', 'price' => '售价', 'min_price' => '最低价', 'time' => '砍价时间', 'order_status' => '状态 0--进行中 1--成功 2--失败', 'is_pay' => '是否支付:0否;1:是', 'bargain_goods_data' => '砍价设置', 'mobile' => '收货人的手机号码', 'receiver_name' => '收货人姓名', 'province' => '收货人所在省', 'city' => '收货人所在城市', 'area' => '收货人所在街道', 'zip' => '收货人邮编', 'address' => '详细地址', 'region_name' => '地区名称(省市区[乡/镇])', 'bargain_price' => '砍后商品价格', 'reduce_price' => '减少价格', 'num' => '购买数量', 'payment_type' => '支付方式:1.在线支付 2.货到付款 3.余额支付', 'pay_time' => '支付时间', 'shipping_type' => '订单配送方式【1物流配送 2买家自提 3货到付款 4本地配送】', 'shipping_money' => '运费', 'total_pay_price' => '实际支付总费用(含运费)', 'remark' => '用户订单备注', 'status' => '状态[-1:删除;0:禁用;1启用]', 'created_at' => 'Created At', 'updated_at' => 'Updated At', ]; } public function getUser(): \yii\db\ActiveQuery { return $this->hasOne(User::class, ['id' => 'user_id']); } public function getActive(): \yii\db\ActiveQuery { return $this->hasOne(BargainActive::class, ['id' => 'bargain_active_id']); } public function getUserJoinOrder(): \yii\db\ActiveQuery { return $this->hasMany(BargainUserOrder::class, ['bargain_order_id' => 'id'])->where(['status' => StatusEnum::ENABLED]); } /** * @desc:发布砍价 * @Author: hua * @Date: 2022/1/3 * @Time: 15:16 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @return BargainOrder|false */ public static function release($params) { $stock_locks = []; $t = Yii::$app->db->beginTransaction(); try { $lock_key = RedisKeyEnum::LOCK_BARGAIN_ACTIVE . $params['active_id']; $identification = uniqid(); $stock_locks[$lock_key] = $identification; if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多'); $active = BargainActive::findOne(['mall_id' => $params['mall_id'], 'id' => $params['active_id'], 'active_status' => BargainEnum::ACTIVE_HANDING]); if (!$active) throw new \Exception('砍价商品不存在'); if ($active->begin_time >= time()) throw new \Exception('砍价活动尚未开始'); if ($active->end_time <= time()) throw new \Exception('砍价活动已结束'); if ($active->stock <= 0) throw new \Exception('砍价活动商品库存不足'); $bargain_order = BargainOrder::findOne(['mall_id' => $params['mall_id'], 'bargain_active_id' => $active['id'], 'user_id' => $params['user_id'], 'order_status' => BargainEnum::ORDER_HANDING,'status'=>StatusEnum::ENABLED]); if (!empty($bargain_order)) throw new \Exception('已存在进行中的砍价'); //检查用户等级能否参与 self::checkUserLevel($params, $active); //检查用户参与次数 self::checkUserJoinTime($params, $active); $token = \Yii::$app->security->generateRandomString(); $mode_data = json_decode($active->mode_data, JSON_UNESCAPED_UNICODE); $goods = $active->goods; $bargain_order = new BargainOrder(); $bargain_order->loadDefaultValues(); $bargain_order->mall_id = $params['mall_id']; $bargain_order->user_id = $params['user_id']; $bargain_order->bargain_active_id = $active->id; $bargain_order->token = $token; $bargain_order->price = $active->goods->price; $bargain_order->min_price = $active->min_price; $bargain_order->time = $active->time; $bargain_order->goods_name = $goods->goods_name; $bargain_order->cover_pic = $goods->cover_pic; $bargain_order->bargain_goods_data = json_encode(array_merge([ 'min_price' => $active->min_price, 'begin_time' => $active->begin_time, 'end_time' => $active->end_time, 'time' => $active->time, 'type' => $active->type, 'stock' => $active->stock, 'id' => $active->id, 'price' => $active->goods->price ], $mode_data), JSON_UNESCAPED_UNICODE); if (!$bargain_order->save()) throw new \Exception($bargain_order->getErrorMessage()); if ($active->type != 1) { //选择允许中途下单,在下单后才减少库存 $active->stock -= 1; } $active->initiator += 1; $active->underway += 1; if (!$active->save()) throw new \Exception(BargainActive::getStaticError()); $t->commit(); LockHelper::batchUlock($stock_locks); return $bargain_order; } catch (\Exception $e) { LockHelper::batchUlock($stock_locks); $t->rollback(); self::$static_error = $e->getMessage(); return false; } } public static function checkUserLevel($params, $active) { $join_limit_user_level = empty($active->join_limit_user_level) ? [] : $active->join_limit_user_level; if (empty($join_limit_user_level)) { return true; } $user = User::find() ->where(['id' => $params['user_id'], 'status' => StatusEnum::ENABLED]) ->select('id,level') ->asArray() ->one(); if (empty($user)) { throw new \Exception('用户信息不存在'); } $mall_level_info = UserLevel::find() ->where([ 'mall_id' => $params['mall_id'], 'status' => StatusEnum::ENABLED ]) ->andWhere(['in', 'id', $join_limit_user_level]) ->select('id,level') ->asArray() ->all(); $join_level = $mall_level_info ? array_column($mall_level_info, 'level') : []; if (in_array(0, $join_limit_user_level)) { $join_level[] = 0; } if (!in_array($user['level'], $join_level)) { throw new \Exception('很抱歉!您暂时无法发起这个活动~'); } } public static function checkUserJoinTime($params, $active) { $active_release_count = self::find() ->where([ 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'bargain_active_id' => $active->id, 'status' => StatusEnum::ENABLED ]) ->count(); if ($active->join_time && $active->join_time <= $active_release_count) { throw new \Exception('您的发起次数不足,去发起其它活动吧~'); } } /** * @desc:生成订单 * @Author: hua * @Date: 2022/1/4 * @Time: 17:07 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $form * @return array|false */ public static function createOrder($form) { $trans = Yii::$app->db->beginTransaction(); try { $group_order_goods = $form['group_order_goods']; $data = is_array($form->data) ? $form->data : Json::decode($form->data, true); $order_trade_info = []; //只有一个订单 foreach ($group_order_goods as $mch_order) { $mch_order_info = $mch_order['mch_order_info']; $bargain_order = BargainOrder::findOne(['mall_id' => $form->mall_id, 'user_id' => $form->user_id, 'bargain_active_id' => $data['active_id'], 'order_status' => BargainEnum::ORDER_HANDING]); if (empty($bargain_order)) throw new \Exception('砍价订单不存在'); $bargain_order->load($mch_order_info, ''); $bargain_order->order_status = OrderStatusEnum::NOT_PAY; $bargain_order->remark = $data['remark']; $bargain_order->total_pay_price = $mch_order_info['pay_money']; $bargain_order->order_no = StringHelper::generateOrderNo('br'); $res = $bargain_order->save(); if ($res == false) throw new \Exception(BargainOrder::getStaticError()); $order_trade_info[] = [ 'order_no' => $bargain_order->order_no, 'amount' => $bargain_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' => BargainEnum::NOTIFY_CLASS, 'order_type' => PaymentTradeOrderEnum::BARGAIN_ORDER, ]; } //中途下单的 创建订单才扣活动库存 $bargain_active = BargainActive::findOne(['id' => $data['active_id'], 'mall_id' => $form->mall_id]); if ($bargain_active && $bargain_active['type'] == 1) { $goods = Goods::getOne([ ['mall_id' => $form->mall_id], ['id' => $bargain_active['goods_id']], ['status' => StatusEnum::ENABLED] ], true, [], null, 'goods_name'); if ($bargain_active['stock'] <= 0) throw new \Exception($goods['goods_name'] . '商品已售罄,暂时无法购买哦~'); $bargain_active->stock -= 1; if (!$bargain_active->save()) throw new \Exception(BargainActive::getStaticError()); } $trans->commit(); //生成支付流水 $res = \Yii::$app->services->pay->createTrade($form['mall_id'], $form['user_id'], $order_trade_info); if ($res == false) throw new \Exception('生成支付流水失败'); $arr['transaction'] = $res; $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: 2022/1/5 * @Time: 14:23 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @param $payment_type * @param $out_trade_no * @return BargainOrder|false */ public static function pay($params, $payment_type, $out_trade_no = '') { $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 = BargainEnum::ORDER_SUCCESS; $model->payment_type = $payment_type; $model->pay_time = time(); $res = $model->save(); if ($res === false) throw new \Exception('修改订单失败:' . $model->getErrorMessage()); $trans->commit(); \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, ['id' => $params['id'], 'out_trade_no' => $out_trade_no], self::class, 'handleSyncAddMainOrder'); return $model; } catch (\Exception $e) { if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * @desc:添加主订单,异步调用 * @Author: hua * @Date: 2022/1/5 * @Time: 14:48 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $data */ public static function handleSyncAddMainOrder($data) { $out_trade_no = $data['out_trade_no']; $bargain_order = BargainOrder::findOne($data['id']); $active = BargainActive::findOne(['mall_id' => $bargain_order->mall_id, 'id' => $bargain_order->bargain_active_id]); $t = Yii::$app->db->beginTransaction(); try { $goods = Goods::findOne(['id' => $active->goods_id]); $goods_attr = GoodsAttr::findOne(['id' => $active->attr_id]); $marketing_type = BargainEnum::ADDONS_NAME; //成功砍价,往主订单写入数据 $order_id = self::createMallOrder($bargain_order, $marketing_type, $goods, $goods_attr, $out_trade_no); $bargain_order->order_id = $order_id; $bargain_order->order_status = BargainEnum::ORDER_SUCCESS; $res = $bargain_order->save(); if ($res == false) throw new \Exception('砍价成功回写主订id失败'); $active->success += 1; $res = $active->save(); if ($res == false) throw new \Exception('更新砍价活动失败'); $t->commit(); $mode_data = json_decode($active->mode_data, true); if (!empty($mode_data['commission_type'])){ $list = \Yii::$app->services->setting->addons->get($bargain_order->mall_id, BargainEnum::ADDONS_NAME, 'basic'); if(empty($list['grant_type'])||$list['grant_type']==1) self::giveReward(BargainOrder::tableName(), $data['id'], $active); } // 触发订单支付事件,事务提交完成后触发 $user = User::findOne(['id' => $bargain_order->user_id]); $event = new \common\events\order\OrderPaidEvent($bargain_order->mall_id); $order['id'] = $order_id; $order['operator_id'] = $user['id']??0; $order['operator_name'] = $user['nickname'] ?? ''; Yii::$app->services->events->dispatch($event, $order, $event->listeners); } catch (\Exception $e) { $t->rollBack(); $exception = FormatHelper::exception($e, "订单支付触发砍价事件"); echo $exception; Yii::error($exception); } } /** * @desc:生成主订单 * @Author: hua * @Date: 2022/1/5 * @Time: 14:49 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $bargain_order * @param $marketing_type * @param $goods * @param $goods_attr * @param $out_trade_no * @return int * @throws \Exception */ public static function createMallOrder($bargain_order, $marketing_type, $goods, $goods_attr, $out_trade_no = ''): int { $order = new Order(); $order->loadDefaultValues(); $order->load($bargain_order->toArray(), ''); $order->mch_id = $goods->mch_id; $order->order_status = OrderStatusEnum::PAY; $order->marketing_id = $bargain_order->bargain_active_id; $order->marketing_type = $marketing_type; $order->goods_price = $bargain_order->bargain_price; $order->pay_money = $bargain_order->total_pay_price; $order->shipping_money = $bargain_order->shipping_money; $order->shipping_type = $bargain_order->shipping_type; $order->original_goods_price = $goods_attr->original_price; $order->pay_status = 1; $order->out_trade_no = $out_trade_no ?? ''; $res = $order->save(); if ($res == false) throw new \Exception('砍价成功生成主订单失败'); self::createOrderDetail($bargain_order, $order->id, $goods, $goods_attr, $marketing_type); return $order->id; } /** * @desc:生成主订单详情 * @Author: hua * @Date: 2022/1/5 * @Time: 14:49 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $bargain_order * @param $order_id * @param $goods * @param $goods_attr * @param $marketing_type * @throws \Exception */ public static function createOrderDetail($bargain_order, $order_id, $goods, $goods_attr, $marketing_type) { // 订单详情 $order_detail = new OrderDetail(); $order_detail->loadDefaultValues(); $order_detail->user_id = $bargain_order->user_id; $order_detail->mall_id = $bargain_order->mall_id; $order_detail->mch_id = $goods->mch_id; $order_detail->order_id = $order_id; $order_detail->goods_id = $goods->id; $order_detail->goods_attr_id = $goods_attr->id; $order_detail->goods_name = $goods->goods_name; $order_detail->goods_attr_name = $goods_attr->name; $order_detail->price = $bargain_order->price; $order_detail->cost_price = $goods_attr->cost_price; $order_detail->original_goods_price = floatval($goods_attr->original_price)?$goods_attr->original_price*$bargain_order->num:$bargain_order->price*$bargain_order->num; $order_detail->goods_price = $bargain_order->bargain_price; $order_detail->num = $bargain_order->num; $order_detail->pic_url = $goods->cover_pic; $order_detail->marketing_id = $bargain_order->bargain_active_id; $order_detail->marketing_type = $marketing_type; $order_detail->order_status = OrderStatusEnum::PAY; $order_detail->remark = $bargain_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/5 * @Time: 17:16 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $source_table * @param $bargain_order_id * @param $active * @throws \Exception */ public static function giveReward($source_table, $bargain_order_id, $active) { $insert_wallet = []; $list = BargainUserOrder::lists(['where' => [['bargain_order_id' => $bargain_order_id], ['status' => StatusEnum::ENABLED]]]); foreach ($list as $item) { if ($item['price']) { $item['price'] = bcmul($item['price'],1,2); $user_id = $item['user_id']; $desc = '用户(' . $user_id . '),获得砍价订单(' . $bargain_order_id . ')奖励,奖励类型:佣金,数量:' . $item['price']; $insert_wallet [] = ['mall_id' => $active->mall_id, 'user_id' => $user_id, 'is_frozen' => false, 'wallet_type' => 'commission', 'money' => $item['price'], 'desc' => $desc, 'source_table' => $source_table, 'source_table_id' => $bargain_order_id, 'from_type' => UserWalletEnum::FROM_BARGAIN, 'capital_type' => UserWalletEnum::GIVE, ]; } } if (!empty($insert_wallet)) { UserWalletService::batchHandleByQueue($insert_wallet); } } /** * @desc:砍价时间到,结束 * @Author: hua * @Date: 2022/1/5 * @Time: 17:21 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @param false $force * @return BargainOrder|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('订单不存在或已删除'); $active = BargainActive::findOne(['id' => $model['bargain_active_id']]); // 订单结束时间取活动结束时间 或者砍价最大时间 $end_time = min($model->created_at + $active->time * 3600, $active->end_time); if($end_time > time()){ throw new \Exception('还没到过期时间'); } // 判断订单是否已经被关闭 if ($model->order_status == BargainEnum::ORDER_FAILURE) throw new \Exception('订单已经关闭'); // 判断是否是未支付的订单 if ($force == false && $model->is_pay != 0) throw new \Exception('订单已经被处理'); $model->order_status = BargainEnum::ORDER_FAILURE; if (!$model->save()) throw new \Exception($model->getErrorMessage()); self::rollBackStock($model, $stock_locks);//回退库存 $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: 2022/1/5 * @Time: 17:28 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $model * @param $stock_locks * @throws \Exception */ public static function rollBackStock($model, &$stock_locks) { $lock_key = RedisKeyEnum::LOCK_BARGAIN_ACTIVE . $model->bargain_active_id; $identification = uniqid(); if (!LockHelper::lock($lock_key, $identification, 30, 60)) throw new \Exception('当前访问人数过多'); $stock_locks[$lock_key] = $identification; //操作商品库存-回退 $res = BargainActive::handleStock($model->mall_id, $model->bargain_active_id, $model->num); if (!$res) throw new \Exception(Goods::getStaticError()); } /** * @desc:分享详情 * @Author: hua * @Date: 2022/1/5 * @Time: 16:39 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $bargain_order_id * @param $mall_id * @return array */ public static function getShareDetail($bargain_order_id, $mall_id): array { $order = self::getOne([['id' => $bargain_order_id, 'mall_id' => $mall_id]], true, ['active' => function ($query) { $query->with(['goods']); }]); $data['item_id'] = $order['id']; $data['price'] = $order['price']; $data['min_price'] = $order['active']['min_price']; $data['share_title'] = $order['active']['goods']['goods_name']; $data['share_img'] = $order['active']['goods']['cover_pic']; $data['active_id'] = $order['bargain_active_id']; return $data; } public static function check($params): bool { $order_no_arr = $params['order_no_arr']; $payment_order_list = $params['payment_order_list']; $counts = BargainOrder::find()->where(['order_no' => $order_no_arr, 'is_pay' => 0])->count(); if ($counts != count($payment_order_list)) { self::$static_error = '砍价订单不一致'; return false; } return true; } }