128], [['mobile'], 'string', 'max' => 45], [['name'], 'string', 'max' => 125], [['remark','order_no','trade_no', 'seller_remark'], 'string', 'max' => 225], [['list'], 'string'], [['pay_money'], 'number'], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => 'ID', 'mall_id' => '商城id', 'user_id' => '用户id', 'goods_id' => '商品ID', 'num' => '商品数量', 'address' => '收货人地址', 'express_no' => '发货单号', 'express_code' => '物流公司编号', 'send_status' => '0待发货;1已发货;2已完成;', 'mobile' => '收货人手机号码', 'name' => '收货人名称', 'status' => '状态[-1:删除;0:禁用;1启用]', 'created_at' => 'Created At', 'updated_at' => 'Updated At', 'province_id' => '省', 'city_id' => '市', 'district_id' => '区', 'town_id' => '镇', 'remark' => '用户备注', 'list' => '物流信息', 'table_express_status' => '物流状态0/未完成 1/已完成', 'express_status' => '当前物流状态(物流公司状态)', 'seller_remark' => '卖家备注', 'cancel_admin_id' => '取消自提的管理员id', 'is_shipping_refunded' => '是否已经退了运费', 'is_delivery_address_modified' => '是否已经修改过收货地址', ]; } public function getUser() { return $this->hasOne(User::class, ['id' => 'user_id'])->select(['id', 'nickname', 'avatar_url', 'mobile']); } public function getGoods() { return $this->hasOne(Goods::class, ['id' => 'goods_id'])->select(['id', 'goods_name', 'cover_pic']); } public function getDetails() { return $this->hasMany(CloudStockAgentOrderDetails::class, ['order_id' => 'id']); } public static function setData(int $mall_id, array $data, array $express = null) { try { if (!empty($data['id'])) { $model = self::findOne(['mall_id' => $mall_id, 'status' => StatusEnum::ENABLED, 'id' => $data['id']]); if (empty($model)) { self::$static_error = '数据异常'; return false; } } else { $model = new self(); $model->loadDefaultValues(); $model->mall_id = $mall_id; } foreach ($data as $key => $val) { $model->$key = $val; } if (!$model->save()) { self::$static_error = '保存数据失败:' . $model->getErrorMessage(); return false; } if (!empty($express) && empty(OrderExpress::getOne([ ['cs_order_id' => $model->id] ]))) { // 发货 $flag = OrderExpress::delivery([ 'mall_id' => $model->mall_id, 'cs_order_id' => $model->id, 'buyer_id' => $model->user_id, 'buyer_name' => User::find()->where(['id' => $model->user_id])->select('nickname')->scalar() ?? '', 'operator_name' => '来自旺店通的发货', 'shipping_type' => ShippingTypeEnum::LOGISTICS, 'express_id' => $express['express_id'], 'express_name' => $express['express_name'] ?? '', 'express_no' => $model->express_no, 'memo' => '', 'order_detail_ids' => [], 'shipping_change' => '', 'customer_name' => '旺店通', 'order_id' => 0, ], false); } $cloudStockAgentOrderInfo = self::findOne(['mall_id' => $mall_id, 'id' => $data['id'], 'express_code' => $data['express_code'], 'express_no' => $data['express_no']]); if(!empty($cloudStockAgentOrderInfo)){ $flag = OrderExpress::delivery([ 'mall_id' => $model->mall_id, 'cs_order_id' => $model->id, 'buyer_id' => $model->user_id, 'buyer_name' => User::find()->where(['id' => $model->user_id])->select('nickname')->scalar() ?? '', 'operator_name' => '', 'shipping_type' => ShippingTypeEnum::LOGISTICS, 'express_no' => $model->express_no, 'memo' => '', 'order_detail_ids' => [], 'shipping_change' => '', 'customer_name' => '', 'order_id' => 0, ], false); } return $model; } catch (\Exception $e) { self::$static_error = '异常保存数据失败:' . $e->getMessage(); return false; } } /** * 批量发货功能 * * 该函数用于处理订单的批量发货操作 */ public static function asyncBatchDelivery($params) { if (empty($params)) { Yii::error('发货失败,内容为空'); return null; } Yii::$app->db->close(); $trans = Yii::$app->db->beginTransaction(); try { $model = CloudStockOrderBatchDelivery::findOne(['id' => $params['id']]); if (empty($model)) throw new \Exception("批量发货id={$params['id']}数据查询为空"); $express=Express::getOne([['id'=>$model->express_id]]); if (empty($express)) throw new \Exception("系统中没有该物流公司信息"); // 读取csv文件内容 $file = fopen($model->delivery_file,'r'); while ($data = fgetcsv($file)) { //每次读取CSV里面的一行内容 $file_list[] = $data; } fclose($file); $time = time(); $delivery_num = $success_delivery_num = 0;// 已处理的订单数量、处理成功数量 foreach ($file_list as $key => $item) { if ($key == 0) continue; $order_no = trim($item[0]); $express_no = ltrim(trim($item[1]),"'"); $delivery_num++; $success_status = true; $error_string = ''; $error = ['mall_id' => $model->mall_id, 'batch_delivery_id' => $model->id, 'order_no'=>$order_no, 'express_no'=>$express_no]; if (empty($order_no)) $error_string .= '订单号不能为空 '; if (empty($express_no)) $error_string .= '物流单号不能为空 '; if ($error_string) { $error['content'] = $error_string; CloudStockOrderBatchDeliveryError::setData($error); continue; } $order = self::getOne([['mall_id' => $model->mall_id,'order_no' => $order_no, 'status'=>[StatusEnum::ENABLED]]]); if (empty($order)) { $error['content'] = '查无此订单'; CloudStockOrderBatchDeliveryError::setData($error); continue; } $flag = OrderExpress::delivery([ 'mall_id' => $order->mall_id, 'cs_order_id' =>$order->id, 'buyer_id' => $order->user_id, 'buyer_name' => $order->name, 'operator_name' => $model->operator_name, 'shipping_type' => ShippingTypeEnum::LOGISTICS, 'express_id' => $model->express_id, 'express_name' => $model->express_name ?? '', 'express_no' => (string)$express_no, 'memo' => '', 'order_detail_ids' => [], 'shipping_change' => '', 'customer_name' => '旺店通', 'order_id' => 0, ], false); if ($flag === false) { $error['content'] = CloudStockOrderBatchDeliveryError::getStaticError(); CloudStockOrderBatchDeliveryError::setData($error); $success_status = false; } $order->send_status=CloudStockEnum::SEND_STATUS_1; $order->express_no = $express_no; $order->express_code = $express->code; $orderResult=$order->save(); if ($orderResult === false) { $error['content'] = CloudStockAgentOrder::getStaticError(); CloudStockOrderBatchDeliveryError::setData($error); $success_status = false; } $success_status && $success_delivery_num++; } // 修改数据 $model->delivery_num = $delivery_num; $model->success_delivery_num = $success_delivery_num; $model->delivery_status = StatusEnum::ENABLED; if (!$model->save()) throw new \Exception($model->getErrorMessage()); $trans->commit(); return true; } catch (\Exception $e) { $trans->rollBack(); $exception = FormatHelper::exception($e, "订单批量发货事件"); echo $exception; Yii::error($exception); return false; } } /** * @name: * @msg: 提货到线下 * @param {int} $mall_id * @param {array} $data user_id:会员id;addr_id:收货地址id;goods_id:商品id;number:提货数量 * @return {*} */ public static function pickOffline(int $mall_id, array $data) { $addr = UserAddress::findOne(['user_id' => $data['user_id'], 'id' => $data['addr_id'], 'status' => StatusEnum::ENABLED]); if (empty($addr)) { self::$static_error = '收货地址不存在'; return false; } // 数据验证 $addr_full = $addr->province . $addr->city . $addr->district . $addr->town . $addr->detail; $order_no = StringHelper::generateOrderNo('CSP'); $order_params = [ 'mall_id' => $mall_id, 'user_id' => $data['user_id'], 'goods_id' => 0, 'num' => 0, 'address' => $addr_full, 'express_no' => '', 'express_code' => '', 'send_status' => CloudStockEnum::PICK_ORDER_STATUS0, 'mobile' => $addr->mobile, 'name' => $addr->name, 'province_id' => $addr->province_id, 'city_id' => $addr->city_id, 'district_id' => $addr->district_id, 'town_id' => $addr->town_id, 'status' => StatusEnum::ENABLED, 'remark' => $data['remark'] ?? '', 'order_no' => $order_no, 'order_type' => !empty($data['order_type']) ? $data['order_type'] : 1, 'pay_time' => !empty($data['pay_time']) ? $data['pay_time'] : 0, 'payment_type' => !empty($data['payment_type']) ? $data['payment_type'] : 0, ]; $baseParams = ['mall_id' => $mall_id, 'user_id' => $data['user_id'], 'stock_agent' => $data['stock_agent']]; $goodsService = new CloudStockAgentGoodsService($baseParams); $cartService = new CloudStockAgentCartService($baseParams); $orderService = new CloudStockAgentOrderService($baseParams); $levelService = new CloudStockLevelService($baseParams); // 订单详情数据 $orderDetailsData = []; $isCart = false; // 单件自提 if (!empty($data['goods_id']) && !empty($data['number'])) { $orderDetailsData[] = [ 'user_id' => $data['user_id'], 'mall_id' => $mall_id, 'goods_id' => $data['goods_id'], 'order_id' => 0, 'num' => $data['number'] ]; } else { // 购物车自提 // 查询购物车数据 $cartList = $cartService->getCartList(); if (empty($cartList)) { self::setStaticError("未选择提货商品"); return false; } foreach ($cartList as $cartItem) { if (empty($cartItem['goods_id']) || empty($cartItem['num'])) { continue; } $orderDetailsData[] = [ 'user_id' => $data['user_id'], 'mall_id' => $mall_id, 'goods_id' => $cartItem['goods_id'], 'order_id' => 0, 'num' => $cartItem['num'] ]; } if (empty($orderDetailsData)) { self::setStaticError("提货商品异常"); return false; } $isCart = true; } // 参数验证 if (!$orderService->checkLimit($cartService, $levelService, $goodsService, $orderDetailsData)) { self::setStaticError($orderService->getError()); return false; } // 获取设置 $configs = \Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_CLOUD_STOCK, 'basic'); //开启运费 if(!empty($configs['is_enable_freight_charges'])){ if ($order_params['order_type'] == 1) { $order_params['send_status'] = CloudStockEnum::PICK_ORDER_STATUS3; } // 得到运费 try { $freight = $orderService->getFreight($goodsService, $mall_id, $data['user_id'], $data['addr_id'], $orderDetailsData); }catch (\Exception $e) { self::setStaticError($e->getMessage()); return false; } $order_params['pay_money'] = $freight; } $transaction = \Yii::$app->db->beginTransaction(); $res_order = self::setData($mall_id, $order_params); if (false === $res_order) { $transaction->rollBack(); return false; } foreach ($orderDetailsData as &$orderDetail) { $orderDetail['order_id'] = $res_order->id; $orderDetail['created_at'] = $orderDetail['updated_at'] = time(); } unset($orderDetail); try { \Yii::$app->db->createCommand()->batchInsert( CloudStockAgentOrderDetails::tableName(), array_keys($orderDetailsData[0]), $orderDetailsData )->execute(); }catch (\Exception $e) { \Yii::$app->custom->logs(FormatHelper::exception($e, '云库存订单details写入失败'), $orderDetailsData); $transaction->rollBack(); return false; } $isCart && $cartService->delAll($res_order->id); $stock_params = [ 'order_info' => $orderDetailsData, 'user_id' => $data['user_id'], 'order_id' => $res_order->id, 'order_type' => CloudStockEnum::STOCK_ORDER_TYPE_REPLENISH, ]; $res_handle_stock = CloudStockGoodsStockLog::stockHandleV2($mall_id, $stock_params, CloudStockEnum::STOCK_CHANGE_TYPE203); if (false === $res_handle_stock) { $transaction->rollBack(); self::$static_error = CloudStockGoodsStockLog::getStaticError(); return false; } $agent_user = CloudStockAgent::find() ->where(['mall_id' => $mall_id, 'user_id' => $data['user_id'], 'status' => StatusEnum::ENABLED]) ->one(); $agent_user->total_order += 1; $res_agent_user = $agent_user->save(); if (false === $res_agent_user) { $transaction->rollBack(); self::$static_error = $agent_user->getErrorMessage(); return false; } $transaction->commit(); CloudStockAgent::fixStock($mall_id,$data['user_id']); // 发起自提事件 if($res_order->send_status != CloudStockEnum::PICK_ORDER_STATUS3){ $event = new FillOrderPickEvent($mall_id); $post_data = ['id' => $res_order->id]; if (MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_WANG_DIAN_TONG)) { // 如果有安装旺店通插件,那么就将发货事件添加进来 $event->listeners[] = 'addons\CloudStock\common\listeners\order\WangDianTongSyncListener'; } \Yii::$app->services->events->dispatch($event, $post_data, $event->listeners); $sync_params = [ 'mall_id' => $mall_id, 'user_id' => $data['user_id'], 'goods_id' => array_column($orderDetailsData, 'goods_id') ]; \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK, RabbitMqEnum::TASK_QUEUE, $sync_params, self::class, 'handleSync'); } return $res_order; } /** * @name: * @msg: 提货到线下赠送优惠券,异步任务处理 * @param {array} $params * @return {*} */ public static function handleSync(array $params = null) { try { $is_install = MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_COUPON); if (!$is_install) { \Yii::error(AddonsEnum::ADDONS_NAME_WECHATLIVE . ' 应用未安装'); \Yii::getLogger()->flush(true); return true; } if (is_array($params['goods_id'])) { foreach ($params['goods_id'] as $goodsId) { $res = AddonsCouponUserRelate::buyGoodsGiveCoupon($params['mall_id'], $goodsId, $params['user_id']); } } else { $res = AddonsCouponUserRelate::buyGoodsGiveCoupon($params['mall_id'], $params['goods_id'], $params['user_id']); } return true; } catch (\Exception $e) { var_dump("giveCoupon:" . $e->getMessage()); return true; } } /** * 导出字段数组 * @Author: hua * @DateTime: 2021/10/11 18:06 * @Copyright: copyright (c) 2021 广东七件事集团 * @return \string[][] */ public static function fieldsLists($field = null){ $fields = [ 'order' => '订单ID', 'user_id' => '代理商用户id', 'nickname' => '代理商昵称', 'user_mobile' => '手机号', 'created_at' => '自提时间', 'goods_name' => '商品', 'num' => '商品数量', 'name' => '收货人名字', 'mobile' => '收货人手机号码', 'address' => '收货地址', 'express_name' => '快递公司', 'express_code' => '快递编码', 'express_no' => '快递单号', 'pay_money' => '运费', 'order_no' => '订单号', 'trade_no' => '支付流水号', 'out_trade_no' => '交易流水号', 'payment_type' => '支付方式', 'pay_time' => '支付时间', 'remark' => '买家备注', 'seller_remark' => '卖家备注', 'send_status' => '状态', 'order_type' => '自提类型', ]; if ($field === null) return $fields; $temp = []; foreach ($field as $val) { if (isset($fields[$val])) $temp[$val] = $fields[$val]; } return $temp; } /** * 导出 */ public static function exportOrder(array $data) { ini_set('memory_limit', '1024M'); $download_id = $data['download_id'] ?? 0; $download = Download::findOne(['id' => $download_id]); if ($download) { try { $params = json_decode($download->params, true); $filename = $download->name; $type = $download->type; $fields = $params['fields'] ?? null; $exportField = self::fieldsLists($fields); $where[] = ['mall_id' => $params['mall_id'], 'status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]; if (!empty($params['keyword'])) { $user_list = User::find()->where(['or', ['id' => $params['keyword']], ['like', 'mobile', $params['keyword']], ['like', 'nickname', $params['keyword']]])->select('id')->asArray()->all(); $user_id_arr = array_column($user_list, 'id'); $where[] = ['user_id' => $user_id_arr]; } if ($params['status'] != '' || !empty($params['express_no']) || !empty($params['out_trade_no']) || !empty($params['order_no'])) { if ($params['status'] != '') { if (abs($params['status']) == CloudStockEnum::PICK_ORDER_STATUS4) { $where[] = ['=', 'send_status', CloudStockEnum::PICK_ORDER_STATUS4]; $where[] = [$params['status'] > 0 ? '=' : '>', 'cancel_admin_id', 0]; } else { $where[] = ['=', 'send_status', $params['status']]; } } if (!empty($params['express_no'])) { $where[] = ['=', 'express_no', $params['express_no']]; } if (!empty($params['out_trade_no'])) { $where[] = ['=', 'trade_no', $params['out_trade_no']]; } if (!empty($params['order_no'])) { $where[] = ['=', 'order_no', $params['order_no']]; } if (!empty($params['order_type'])) { $where[] = ['order_type' => $params['order_type']]; } } if (!empty($params['created_at'])) { $where[] = ['between', 'created_at', strtotime(reset($params['created_at'])), strtotime(end($params['created_at']))]; } if (isset($params['receiving_info']) && $params['receiving_info'] !== '') { $where[] = [ 'or', ['like', 'mobile', $params['receiving_info']], ['like', 'name', $params['receiving_info']] ]; } if (!empty($params['areaIds'])) { $where[] = [ 'or', ['province_id' => $params['areaIds']], ['city_id' => $params['areaIds']], ['district_id' => $params['areaIds']] ]; } $wheres['order'] = 'id desc'; $wheres['with'] = [ 'user', 'details' => function ($query) { $query ->with(['goods' => function ($query) { $query->select('id, cover_pic, goods_name'); }]); } ]; $wheres['where'] = $where; $model = self::find(); self::paramPack($wheres, $model); $exportList = []; $exportHeader = array_values($exportField); $send_status_map = CloudStockEnum::getAgentOrdetStatusMap(); $express_list = Express::getExpresses(); // 快递 $payment_list = PayTypeEnum::getMap(); // 支付类型 if (!empty($express_list)) $express_list = array_column($express_list, 'name', 'code'); $firstList = []; foreach ($model->asArray()->batch(1000) as $batch) { $fieldsMap = array_keys($exportField); foreach ($batch as $item) { $exportItem = []; $userFieldMap = ['nickname', 'user_mobile']; $goodsFieldMap = ['goods_name', 'num']; foreach ($fieldsMap as $fieldName) { if (in_array($fieldName, $userFieldMap)) { self::handleUserField($exportItem, $item, $fieldName); } else { if ($fieldName === 'created_at' || $fieldName === 'pay_time') { $exportItem[$fieldName] = !empty($item[$fieldName]) ? date('Y-m-d H:i:s', $item[$fieldName]) : ''; } elseif ($fieldName === 'send_status') { $exportItem[$fieldName] = $item[$fieldName] == CloudStockEnum::PICK_ORDER_STATUS4 && $item['cancel_admin_id'] > 0 ? '取消自取' : self::getFieldValue($send_status_map, $item[$fieldName]); } elseif ($fieldName == 'payment_type') { $exportItem[$fieldName] = self::getFieldValue($payment_list, $item['payment_type']); } elseif ($fieldName == 'express_name') { $exportItem[$fieldName] = self::getFieldValue($express_list, $item['express_code']); } elseif ($fieldName == 'order') { $exportItem[$fieldName] = self::getFieldValue($item, 'id'); } elseif ($fieldName == 'order_type') { $exportItem[$fieldName] = $item[$fieldName] == 1 ? '云仓自提' : '价差礼包自提'; } else { $exportItem[$fieldName] = self::getFieldValue($item, $fieldName); } } } if (!empty($item['details'])) { foreach ($item['details'] as $detail) { foreach ($fieldsMap as $fieldName) { if (in_array($fieldName, $goodsFieldMap)) { self::handleGoodsField($exportItem, $detail, $fieldName); } elseif ($fieldName == 'pay_money') { if (!isset($firstList[$item['id']])) { $exportItem[$fieldName] = self::getFieldValue($item, $fieldName); $firstList[$item['id']] = true; } else { $exportItem[$fieldName] = ''; } } } $exportList[] = $exportItem; } } else { $exportList[] = $exportItem; } } } if (!empty($exportList)) { $csv = new CsvTool(); $csv->filename = $filename; $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($type); $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC; $csv->header = $exportHeader; $csv->data = $exportList; $csv->export(); $csv->updateDown($download, $params['mall_id']); } return true; } catch (\Exception $e) { $download->status = 3; $res = $download->save(); self::setStaticError($e->getMessage()); Yii::$app->custom->logs('云库存自提订单导出失败'. $e->getLine() . $e->getMessage(), $download_id); return $e->getMessage(); } } } protected static function getFieldValue($array, $key, $default = '') { return $array[$key] ?? $default; } protected static function handleUserField(&$exportItem, $item, $fieldName) { $userFieldMap = ['nickname', 'user_mobile']; if (in_array($fieldName, $userFieldMap)) { if (empty($item['user'])) { $exportItem[$fieldName] = $fieldName == 'nickname' ? '代理商不存在' : ''; } else { $userMobile = $fieldName == 'user_mobile' ? 'mobile' : $fieldName; $exportItem[$fieldName] = self::getFieldValue($item['user'], $userMobile); } } } protected static function handleGoodsField(&$exportItem, $detail, $fieldName) { $goodsFieldMap = ['goods_name', 'num']; if (in_array($fieldName, $goodsFieldMap)) { if ($fieldName == 'num') { $exportItem[$fieldName] = self::getFieldValue($detail, $fieldName); } else { $exportItem[$fieldName] = self::getFieldValue($detail['goods'], $fieldName); } } } public static function viewLogistics($id,$mall_id){ $agent_order = CloudStockAgentOrder::findOne(['id'=>$id,'mall_id'=>$mall_id]); if(empty($agent_order)) throw new \Exception('自提订单不存在'); $traces = []; $time = time(); $hour = Yii::$app->services->setting->mall->get($mall_id, 'logistics.update');// 获取更新物流时间设置 if (($agent_order['table_express_status'] == StatusEnum::DISABLED && $agent_order['updated_at'] + $hour * 3600 < $time)||(empty($agent_order['list']))) { $res = self::getExpressBird($agent_order); if (!empty($res['list'])) { $logistics = json_decode($res['list'], true); if (isset($logistics['Traces'])) { $traces = $logistics['Traces']; } $agent_order->list = $res['list']; if(isset($res['table_express_status']))$agent_order->table_express_status = $res['table_express_status']; $agent_order->express_status = $res['express_status']; } $agent_order->save(); }else{ $logistics = json_decode($agent_order['list'],true); if(isset($logistics['Traces'])){ $traces = $logistics['Traces']; } } return $traces; } public static function getExpressBird($agent_order){ $express_config = Yii::$app->services->setting->mall->get($agent_order['mall_id'],'logistics'); $express['id'] =$agent_order['id']; $express['express_no'] = $agent_order['express_no']; $express['express_code'] = $agent_order['express_code']; $express['customer_name'] = mb_substr($agent_order['mobile'], 0 - 4); if(empty($express_config['kdniao_mch_id'])){ $express_config = Yii::$app->services->setting->mall->get($agent_order['mall_id'],'logistics'); $phone = mb_substr($agent_order['mobile'], 0 - 4); $new_express = LogisticsSearch::getExpressAliyun([ 'mall_id' => $agent_order['mall_id'], 'type' => 'ZTO', 'no' => $express['express_no'] . (!empty($phone) ? ":{$phone}" : ''), 'id' => $express['id'] ]); return $new_express; }else{ return LogisticsSearch::getExpressBird($express, $express_config); } } }