request->post(); $ProductOrder = ProductOrder::find()->where([ 'user_id' => \Yii::$app->user->identity->getId(), // 'store_id' => $post['store_id'] ?? 11001 ])->orderBy('created_at DESC'); switch ($post['type']) { case 'unpaid'://未支付 $ProductOrder->andWhere([ 'status' => ProductOrderEnum::UNPAY ])->all(); break; case 'wait_send'://待发货 $ProductOrder->andWhere([ 'status' => ProductOrderEnum::WAIT_SEND ])->all(); break; case 'wait_accept'://待收货 $ProductOrder->andWhere([ 'status' => ProductOrderEnum::WAIT_ACCEPT ])->all(); break; case 'finished'://已完成(已取消、已收货、已退款、待评价) $ProductOrder->andWhere([ 'in','status',[ProductOrderEnum::CANCEL, ProductOrderEnum::ACCEPTED, ProductOrderEnum::CONFIRM,ProductOrderEnum::REFUND, ProductOrderEnum::WAIT_COMMENT] ])->all(); break; default: break; } $this->field = [ ProductOrder::class => [ 'id','order_no', 'items_price','trans_expenses','decoct_price','process_price','treatement_price','total_pay_price','prescription_type', 'p_id','is_pay', 'status', 'cancel_status', 'refund_status', 'cancel_status_text' => function ($q){ return ProductOrderEnum::CANCEL_STATUS_TEXT[$q->cancel_status]; }, 'refund_status_text' => function ($q){ return ProductOrderEnum::REFUND_STATUS_TEXT[$q->refund_status]; }, 'status_text' => function ($q) { return ProductOrderEnum::STATUS_TEXT[$q->status]; }, 'number' => function ($q) { return ProductOrderItems::find()->where(['product_order_id' => $q->id])->count(); }, 'items' => function ($q) { return ProductOrderItems::find()->where(['product_order_id' => $q->id])->with([ 'drug' => function($q){ $q->select('function,specification'); } ])->asArray()->all(); }, 'store' => function ($q) { return Store::find()->select('id,name')->where(['id' => $q->store_id])->one(); }, 'forbiddenRefund' => 1 // 'forbiddenRefund'=>function($fund){ // $config = \Yii::$app->params; // $orderForbiddenRefundTime = isset($config['product_order']['forbidden_refund_time']) ? $config['product_order']['forbidden_refund_time'] :3600*24*7; // if ($fund->prescription_type==1 || $fund->prescription_type==3){ // return 1;////禁止退款 // }else{ // if (time()-$fund->pay_time<=$orderForbiddenRefundTime){ // return 0;//可以退款 // }else{ // return 1;//禁止退款 // } // } // } ] ]; return $this->create($ProductOrder, $post); } //根据互医的订单编号获取萧康的订单id public function actionOnlineToLocal(){ $param = \Yii::$app->request->get(); $this->requestValidate($param, [ [['order_no'], 'required'] ]); $productOrder = ProductOrder::find()->where([ 'sync_order_no' => $param['order_no'], 'user_id' => \Yii::$app->user->identity->getId() ])->one(); if(!$productOrder){ throw new Exception('订单生成中,请稍后'); } return ['order_id' => $productOrder->id]; } /*** * 预约购药 */ public function actionAppointMedicine() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['prescription_id', 'required'] ]); $ProductOrder = ProductOrder::find()->select('id,order_no,is_online,su_id,p_id,up_id,user_id,is_pay,prescription_type,address_id,address,decoct_price,order_type,items_price,process_price,treatement_price,total_pay_price,pay_method,trans_expenses,created_at,received_time,cancel_status,refund_status,status')->where([ 'p_id' => $post['prescription_id'], 'user_id' => \Yii::$app->user->identity->getId(), // 'store_id' => $post['store_id'] ])->asArray()->one(); if(!$ProductOrder){ throw new Exception('订单不存在'); } $ProductOrder['created_at'] = date('Y-m-d H:i:s', $ProductOrder['created_at']); $forbiddenRefund = 0; $config = \Yii::$app->params; $orderForbiddenRefundTime = isset($config['product_order']['forbidden_refund_time']) ? $config['product_order']['forbidden_refund_time'] : 24*3600*30; if(time() >= $orderForbiddenRefundTime + $ProductOrder['received_time']?? 0){ $forbiddenRefund = 1; } $ProductOrder['forbidden_refund'] = $forbiddenRefund; $userInfo = User::find()->select('id,nickname,avatarurl')->where([ 'id' => $ProductOrder['user_id'] ])->asArray()->one(); $hospital = DoctorInfo::find()->select('hospital_id')->where([ 'su_id' => $ProductOrder['su_id'] ])->with(['hospital' => function ($h) { $h->select('name'); }])->asArray()->one(); $prescription = Prescription::find()->select('cr_ids,wr_ids,gr_ids,category,store_id')->where(['id' => $ProductOrder['p_id']])->one(); // 获取处方来源诊所信息 $prescriptionStore = null; if ($prescription && $prescription->store_id) { $prescriptionStore = Store::find()->select('id,name,mobile,position')->where(['id' => $prescription->store_id])->asArray()->one(); } $count = 0; $west = null; $chinese = null; $granular = null; if($prescription && $prescription->wr_ids){ $wr_ids = explode(',', $prescription->wr_ids); if ($ProductOrder['prescription_type'] == 5) { $westModels = ServicePackageRepice::find()->select('content,number,total_price')->where([ 'in', 'id', $wr_ids ])->all(); } else { $westModels = WestRepice::find()->select('content,number,total_price')->where([ 'in', 'id', $wr_ids ])->all(); } $west = []; foreach ($westModels as $value) { $row = $value->toArray(); $content = Json::decode($row['content']); if (is_array($content) && !empty($content['id']) && empty($content['instruction'])) { $drugInstruction = Drug::find()->select('instruction')->where(['id' => $content['id']])->scalar(); if ($drugInstruction) { $content['instruction'] = $drugInstruction; } } $row['content'] = $content; $west[] = $row; } $count = count($west); }else if($prescription && $prescription->cr_ids){ $cr_ids = explode(',', $prescription->cr_ids); $chineseModels = ChineseRepice::find()->select('content,total_price')->where([ 'in', 'id', $cr_ids ])->all(); $chinese = ['list' => []]; foreach ($chineseModels as $val) { $content = Json::decode($val['content']); foreach ($content as $v){ $chinese['list'][]= $v; } } $count = count($chinese['list']); }else if($prescription && $prescription->gr_ids){ $gr_ids = explode(',', $prescription->gr_ids); $granularModels = GranularRepice::find()->select('content,total_price')->where([ 'in', 'id', $gr_ids ])->all(); $granular = ['list' => []]; foreach ($granularModels as $val) { $content = Json::decode($val['content']); foreach ($content as $v){ $granular['list'][]= $v; } } $count = count($granular['list']); } if ($ProductOrder['p_id'] !== 0 && $ProductOrder['order_type'] !== 2) { if ($prescription && $prescription->category === 2) { $ProductOrder['total_pay_price'] = $ProductOrder['trans_expenses']; $ProductOrder['items_price'] = 0; } } // 按订单明细回填仓名(appoint-medicine 展示用) $orderItems = ProductOrderItems::find() ->where(['product_order_id' => $ProductOrder['id']]) ->asArray() ->all(); $enriched = $this->enrichOrderItemsWarehouse($orderItems); $ProductOrder['has_delivery_warehouse'] = $enriched['has_delivery_warehouse'] ? 1 : 0; $warehouseNameByDrugId = []; foreach ($enriched['items'] as $it) { $warehouseNameByDrugId[(int) ($it['drug_id'] ?? 0)] = (string) ($it['delivery_warehouse_name'] ?? ''); } if (!empty($west) && is_array($west)) { foreach ($west as &$wItem) { $drugId = (int) ($wItem['content']['id'] ?? 0); $wItem['delivery_warehouse_name'] = $warehouseNameByDrugId[$drugId] ?? ''; } unset($wItem); } if (!empty($chinese['list']) && is_array($chinese['list'])) { foreach ($chinese['list'] as &$cItem) { $drugId = (int) ($cItem['id'] ?? $cItem['drug_id'] ?? 0); $cItem['delivery_warehouse_name'] = $warehouseNameByDrugId[$drugId] ?? ''; } unset($cItem); } if (!empty($granular['list']) && is_array($granular['list'])) { foreach ($granular['list'] as &$gItem) { $drugId = (int) ($gItem['id'] ?? $gItem['drug_id'] ?? 0); $gItem['delivery_warehouse_name'] = $warehouseNameByDrugId[$drugId] ?? ''; } unset($gItem); } $ProductOrder['count'] = $count; return [ 'ProductOrder' => $ProductOrder, 'userInfo' => $userInfo, 'hospital' => $hospital, 'west' => $west, 'chinese' => $chinese, 'granular' => $granular, 'ProductOrderItems' => $enriched['items'], 'store' => $prescriptionStore ? ['store' => $prescriptionStore] : null, 'patient' => $this->getOrderPatientInfo((int) ($ProductOrder['up_id'] ?? 0), (int) ($ProductOrder['p_id'] ?? 0)), ]; } /** * 代煎服务费用信息 */ public function actionDecoctService(){ $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $ProductOrder = ProductOrder::find()->select('dosage,prescription_type')->where([ 'id' => $post['order_id'], 'user_id' => \Yii::$app->user->identity->getId(), 'store_id' => $post['store_id'], 'status' => 0, 'cancel_status' => 0 ])->asArray()->one(); if(!$ProductOrder){ throw new Exception('订单信息错误'); } if($ProductOrder['dosage'] == 0){ throw new Exception('只有中药和颗粒药订单提供代煎服务'); } $systemConfig = SystemConfig::find()->where(['type' => $ProductOrder['prescription_type']])->one(); return [ 'decoct_price' => $systemConfig->value, 'dosage' => $ProductOrder['dosage'], 'total_decoct_price' => round($ProductOrder['dosage'] * $systemConfig->value, 2) ]; } /** * 更新代煎服务费用 */ public function actionUpdateDecoctService(){ $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $ProductOrder = ProductOrder::find()->where([ 'id' => $post['order_id'], 'user_id' => \Yii::$app->user->identity->getId(), 'store_id' => $post['store_id'], 'status' => 0, 'cancel_status' => 0 ])->one(); if(!$ProductOrder){ throw new Exception('订单信息错误'); } if($ProductOrder['prescription_type'] == 2){ throw new Exception('只有中药和颗粒药订单提供代煎服务'); } if($post['is_decoct'] ){ // 代煎 if(!$ProductOrder->is_decoct){ $systemConfig = SystemConfig::find()->where(['type' => $ProductOrder->prescription_type])->one(); //根据剂数计算代煎费用 $dosage = $ProductOrder->dosage; $decoctPrice = $dosage * $systemConfig->value; $ProductOrder->is_decoct = 1; $ProductOrder->decoct_price = $decoctPrice; $ProductOrder->total_pay_price = $ProductOrder->total_pay_price + $decoctPrice; $ProductOrder->saveOrFail(); } } else { if($ProductOrder->is_decoct && $ProductOrder->decoct_price > 0){ $ProductOrder->is_decoct = 0; $ProductOrder->total_pay_price = $ProductOrder->total_pay_price - $ProductOrder->decoct_price; $ProductOrder->decoct_price = 0; $ProductOrder->saveOrFail(); } } return ['success']; } /** * 更新订单收货地址 */ public function actionUpdateDelivery(){ $post = \Yii::$app->request->post(); $this->requestValidate($post, [ [['order_id', 'delivery_method'], 'required'], [['address_id'], 'integer'] ]); $ProductOrder = ProductOrder::find()->where([ 'id' => $post['order_id'], 'user_id' => \Yii::$app->user->identity->getId(), // 'store_id' => $post['store_id'], 'status' => 0, 'cancel_status' => 0 ])->one(); if (!$ProductOrder) throw new Exception('产品订单不存在'); if(!$post['delivery_method']){ // 快递配送 if(!$post['address_id']){ throw new Exception('请选择收货地址'); } $address = Address::find()->select(['id','name','mobile','province','region','detail_address'])->where([ 'id' => $post['address_id'], 'user_id' => \Yii::$app->user->identity->getId() ])->asArray()->one(); if (!$address) throw new Exception('收货地址不存在'); $ProductOrder->address_id = $address['id']; $ProductOrder->address = json_encode($address); $ProductOrder->express_name = $address['name']; $ProductOrder->express_mobile = $address['mobile']; $ProductOrder->express_region = $address['region']; $ProductOrder->express_address = $address['detail_address']; if(!$ProductOrder->is_free_shipping) { $region = Region::find()->where(['name' => $address['province']])->one(); $ProductOrder->total_pay_price = $ProductOrder->total_pay_price - $ProductOrder->trans_expenses + $region->express_fee; $ProductOrder->trans_expenses = $region->express_fee; } $ProductOrder->delivery_method = 0; $ProductOrder->saveOrFail(); } else { //门店自提 if(!$ProductOrder->delivery_method){ if ($ProductOrder->is_online != 0) { throw new Exception('在线复诊订单不支持药店自提请选择收货地址'); } $ProductOrder->address_id = 0; $ProductOrder->address = ''; $ProductOrder->express_name = ''; $ProductOrder->express_mobile = ''; $ProductOrder->express_region = ''; $ProductOrder->express_address = ''; $ProductOrder->delivery_method = 1; $ProductOrder->total_pay_price = $ProductOrder->total_pay_price - $ProductOrder->trans_expenses; $ProductOrder->trans_expenses = 0; $ProductOrder->saveOrFail(); } } return ['success']; } /** * @doc-name 订单信息 * @doc-param int order_id 订单id * @doc-return mixed @UserInfo{avatarurl-string-头像,@Address{name-string-名字,mobile-string-手机号码,region-string-地区,detail_address-string-详细地址}} 用户信息 * @doc-return mixed @Hospital{hospital_id-int-id,@Hospital{name-string-名字}} 医院信息 * @doc-return mixed @ProductOrder{order_no-string-订单编号,total_pay_price-float-实付金额,pay_method-int-支付方式1线上2线下,trans_expenses-float-运费,created_at-int-下单时间,status-int-产品订单状态0未支付1待发货2待收货3待评价4已退款5退款中6已收货7确认收货,is_pay-int-是否支付0否1是} 产品订单信息 * @doc-return mixed @Chinese{content-string-信息,total_price-float-单价} 药品信息 * @doc-return mixed @West{content-string-信息,number-int-数量,total_price-float-单价} 药品信息 */ public function actionInfo() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $ProductOrder = ProductOrder::find()->select('id,store_id,is_online,order_no,delivery_method,su_id,p_id,up_id,user_id,is_pay,prescription_type,address_id,address,decoct_price,items_price,process_price,treatement_price,total_pay_price,pay_method,trans_expenses,created_at,cancel_status,refund_status,status,pay_time')->where([ 'id' => $post['order_id'], 'user_id' => \Yii::$app->user->identity->getId(), // 'store_id' => $post['store_id'] ])->asArray()->one(); $ProductOrder['created_at'] = date('Y-m-d H:i:s', $ProductOrder['created_at']); $forbiddenRefund = 1; $config = \Yii::$app->params; $orderForbiddenRefundTime = isset($config['product_order']['forbidden_refund_time']) ? $config['product_order']['forbidden_refund_time'] :3600*24*7; if ($ProductOrder['prescription_type']==2 || $ProductOrder['prescription_type']==4){ if (time()-$ProductOrder['pay_time']<=$orderForbiddenRefundTime){ $ProductOrder['forbidden_refund'] = 0;//可以退款 }else{ $ProductOrder['forbidden_refund']=$forbiddenRefund;//禁止退款 } }else{ $ProductOrder['forbidden_refund'] = $forbiddenRefund;//禁止退款 } $userInfo = User::find()->select('id,nickname,avatarurl')->where([ 'id' => $ProductOrder['user_id'] ])->asArray()->one(); $hospital = DoctorInfo::find()->select('hospital_id')->where([ 'su_id' => $ProductOrder['su_id'] ])->with(['hospital' => function ($h) { $h->select('name'); }])->asArray()->one(); $ProductOrderItems = ProductOrderItems::find()->where(['product_order_id' => $ProductOrder['id']])->with(['drug' => function($q){ $q->select('id,drug_name,is_otc,type,function,specification,usage,instruction'); }])->asArray()->all(); // 回填配送仓名,供小程序按药展示「该药品由xxx配送」 $enriched = $this->enrichOrderItemsWarehouse($ProductOrderItems); $ProductOrderItems = $enriched['items']; $ProductOrder['has_delivery_warehouse'] = $enriched['has_delivery_warehouse'] ? 1 : 0; $ProductOrder['count'] = count($ProductOrderItems); // 获取处方来源诊所信息 $prescriptionStore = null; if ($ProductOrder['p_id']) { $prescription = Prescription::find()->select('store_id')->where(['id' => $ProductOrder['p_id']])->asArray()->one(); if ($prescription && isset($prescription['store_id']) && $prescription['store_id']) { $prescriptionStore = Store::find()->select('id,name,mobile,position')->where(['id' => $prescription['store_id']])->asArray()->one(); } } return [ 'ProductOrder' => $ProductOrder, 'userInfo' => $userInfo, 'hospital' => $hospital, 'ProductOrderItems' => $ProductOrderItems, 'store' => $prescriptionStore ? ['store' => $prescriptionStore] : null, 'patient' => $this->getOrderPatientInfo((int) ($ProductOrder['up_id'] ?? 0), (int) ($ProductOrder['p_id'] ?? 0)), ]; } /** * 为订单明细附加配送仓名称 * delivery_warehouse_id=0 → 萧康医药本仓库;>0 → xk_delivery_warehouse.name * @param array $items * @return array{items: array, has_delivery_warehouse: bool} */ private function enrichOrderItemsWarehouse(array $items): array { $warehouseIds = []; $hasDeliveryWarehouse = false; foreach ($items as $item) { $wid = (int) ($item['delivery_warehouse_id'] ?? 0); if ($wid > 0) { $hasDeliveryWarehouse = true; $warehouseIds[$wid] = true; } } $nameMap = []; if (!empty($warehouseIds)) { $rows = DeliveryWarehouseModel::find() ->select(['id', 'name']) ->where(['id' => array_keys($warehouseIds), 'deleted_at' => 0]) ->asArray() ->all(); foreach ($rows as $row) { $nameMap[(int) $row['id']] = (string) $row['name']; } } foreach ($items as &$item) { $wid = (int) ($item['delivery_warehouse_id'] ?? 0); $item['delivery_warehouse_id'] = $wid; if ($wid > 0) { $item['delivery_warehouse_name'] = $nameMap[$wid] ?? ('仓库' . $wid); } else { $item['delivery_warehouse_name'] = '萧康医药本仓库'; } } unset($item); return [ 'items' => $items, 'has_delivery_warehouse' => $hasDeliveryWarehouse, ]; } /** * @doc-name 支付产品订单 * @doc-param int order_id 订单id * @doc-return int is_paid 1已支付0未支付 * @doc-return int order_id 订单id * @doc-return array config 支付配置参数,在is_paid=0时返回 */ public function actionPay() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $form = new ProductOrderSubmitForm(); return $form->getPayData($post); } /** * @doc-name 产品订单确认收货 * @doc-param int order_id 订单id */ public function actionReceive() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $ProductOrder = ProductOrder::find()->where(['id' => $post['order_id'],'user_id' => \Yii::$app->user->identity->getId()])->one(); if($ProductOrder->status != ProductOrderEnum::WAIT_ACCEPT){ throw new Exception('订单状态错误'); } $ProductOrder->status = ProductOrderEnum::CONFIRM; $ProductOrder->received_time = time(); $ProductOrder->save(); if($ProductOrder->is_online){ //平台订单状态同步 \Yii::$app->queue->delay(0)->push(new ProductOrderSyncPlatformJob([ 'orderId' => $this->event->order->id, 'status' => 4 ])); } return ['签收成功']; } /** * @doc-name 产品订单取消 * @doc-param int order_id 订单id */ public function actionCancel() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $form = new ProductCancelForm(); return $form->cancel($post); } /** * @doc-name 产品订单退款 * @doc-param int order_id 订单id */ public function actionRefundBase() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ [['order_id'], 'required'] ]); $productOrder = ProductOrder::find()->where([ 'id' => $post['order_id'], 'user_id' => \Yii::$app->user->identity->getId(), 'store_id' => $post['store_id'] ])->select('id,total_pay_price,trans_expenses,items_price')->one(); return $productOrder; } /** * @doc-name 产品订单退款 * @doc-param int order_id 订单id */ public function actionRefund() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ [['order_id', 'reason'], 'required'] ]); $form = new ProductRefundForm(); return $form->refund($post); } /** * @doc-name 产品订单退款原因 * @doc-param int order_id 订单id */ public function actionRefundReason() { $list = RefundReason::find()->select('id,reason as text')->asArray()->all(); return $list; } /** * @doc-name 产品订单退款申请撤销 * @doc-param int order_id 订单id */ public function actionRefundCancel() { $post = \Yii::$app->request->post(); $this->requestValidate($post, [ ['order_id', 'required'] ]); $form = new ProductRefundCancelForm(); return $form->cancel($post['order_id']); } /** * 物流详情 */ public function actionExpress(){ $get = \Yii::$app->request->get(); $this->requestValidate($get, [ ['order_id', 'required'] ]); $express = (new ExpressService())->detail($get['order_id']); return $express; } /** * 获取产品订单关联的就诊人信息 * 优先订单 up_id,其次处方 up_id,最后从处方 content 兜底(兼容历史数据) * * @param int $upId 订单就诊人 id * @param int $prescriptionId 处方 id * @return array|null */ private function getOrderPatientInfo(int $upId, int $prescriptionId = 0): ?array { $patientUpId = $upId; $prescription = null; if (!$patientUpId && $prescriptionId > 0) { $prescription = Prescription::find()->select('up_id,content')->where(['id' => $prescriptionId])->asArray()->one(); if ($prescription && !empty($prescription['up_id'])) { $patientUpId = (int) $prescription['up_id']; } } if ($patientUpId > 0) { $patient = UserPatient::find()->select('id,name,mobile')->where([ 'id' => $patientUpId, 'is_delete' => 0, ])->asArray()->one(); if ($patient) { return $patient; } } if (!$prescription && $prescriptionId > 0) { $prescription = Prescription::find()->select('content')->where(['id' => $prescriptionId])->asArray()->one(); } if ($prescription && !empty($prescription['content'])) { $content = Json::decode($prescription['content']); if (!empty($content['patient']['name'])) { return [ 'id' => (int) ($content['patient']['id'] ?? 0), 'name' => $content['patient']['name'], 'mobile' => $content['patient']['mobile'] ?? '', ]; } } return null; } }