$mall_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]], ]; if(!empty($params['from'])){ switch ($params['from']){ case 'platform': $where[] = [ 'or', ['>','goods_id',0], ['reservation_model'=>2] ]; break; case 'store': $where[] = [ 'or', ['>','goods_id',0], [ 'and', ['>', 'secondary_card_id', 0], ['reservation_model' => 2] ], ]; break; } } if (!empty($params['staff_user_id'])) { $where[] = ['staff_user_id' => $params['staff_user_id']]; } else if (!empty($params['user_id'])) { $where[] = ['user_id' => $params['user_id']]; } else if (!empty($params['keyword'])) { $uids = User::find()->where(['mall_id' => $mall_id]) ->andWhere(['status' => StatusEnum::ENABLED]) ->andWhere(['or', ['like', 'id', $params['keyword']], ['like', 'nickname', $params['keyword']], ['like', 'mobile', $params['keyword']]]) ->select('id') ->column(); if (empty($uids)) return []; $where[] = ['user_id' => $uids]; } if (isset($params['service_status']) && $params['service_status'] !== '' && $params['service_status'] != 999) { $where[] = ['service_status' => $params['service_status']]; } if (!empty($params['server_status'])) { $where[] = ['server_status' => $params['server_status']]; } if (!empty($params['order_no'])) { $where[] = ['like', 'order_no', $params['order_no']]; } if (!empty($params['service_type'])) { $where[] = ['service_type' => $params['service_type']]; } if (!empty($params['create_type'])) { $where[] = ['create_type' => $params['create_type']]; } switch ($params['time_type']){ case 1: if (!empty($params['date_start'])) $where[] = ['>=', 'created_at', strtotime($params['date_start'])]; if (!empty($params['date_end'])) $where[] = ['<=', 'created_at', strtotime($params['date_end'])]; break; case 2: if (!empty($params['date_start'])) $where[] = ['>=', 'service_start_at', strtotime($params['date_start'])]; if (!empty($params['date_end'])) $where[] = ['<=', 'service_start_at', strtotime($params['date_end'])]; break; case 3: if (!empty($params['date_start'])) $where[] = ['>=', 'service_end_at', strtotime($params['date_start'])]; if (!empty($params['date_end'])) $where[] = ['<=', 'service_end_at', strtotime($params['date_end'])]; break; default: if (!empty($params['date_start'])) $where[] = ['>=', 'service_start_at', strtotime($params['date_start'])]; if (!empty($params['date_end'])) $where[] = ['<=', 'service_start_at', strtotime($params['date_end'])]; } if (!empty($params['reservation_model'])) { $where[] = ['reservation_model'=> $params['reservation_model']]; } if (!empty($params['order_no'])) { $where[] = ['like', 'order_no', trim($params['order_no'])]; } if (!empty($params['date_c_start'])) $where[] = ['>=', 'created_at', strtotime($params['date_c_start'])]; if (!empty($params['date_c_end'])) $where[] = ['<=', 'created_at', strtotime($params['date_c_end'])]; $with = [ 'user', 'staff' => function ($q) { $q->where(['status' => StatusEnum::ENABLED]); }, 'orderDetail',]; // 门店 if (!empty($params['store_id'])) { $where[] = ['store_id' => $params['store_id']]; } $ret = ReservationServiceOrder::listPage([ 'where' => $where, 'order' => 'id desc', 'limit' => $params['limit'] ?? 10, 'with' => $with ]); if (!empty(ReservationServiceOrder::getStaticError())) return ReservationServiceOrder::getStaticError(); $ret['status_text_map'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP; $server_status_map = ReservationServiceEnum::SERVER_STATUS_MAP; if (!empty($ret['list'])) { $goods_ids = $store_goods_ids = []; foreach ($ret['list'] as &$item){ if($item['store_id']){ $store_goods_ids[]=$item['goods_id']; }else{ $goods_ids[]=$item['goods_id']; } } $goods_list = Goods::lists(['where'=>[['id'=>$goods_ids]],'index'=>'id','select'=>'id,goods_name,cover_pic']); $store_goods_list = StoreGoods::lists(['where'=>[['id'=>$store_goods_ids]],'index'=>'id','select'=>'id,goods_name,cover_pic']); $mall_name = Yii::$app->services->setting->mall->get($mall_id, 'basic.name'); $mall_logo = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo'); $secondary_card_order_list = []; //次卡部分----start if (MallAddons::isInstall($mall_id, 'SecondaryCard')) { $secondary_card_no_arr = array_column($ret['list'],'secondary_card_no'); $secondary_card_order_list = SecondaryCardOrder::lists([ 'where'=> [ ['order_no'=>$secondary_card_no_arr], ], 'with'=>['secondaryCard'], 'index'=>'order_no' ]); $reservation_service_order_ids = array_column($ret['list'],'id'); $use_log_list = SecondaryCardUseLog::lists(['where'=>[['reservation_service_order_id'=>$reservation_service_order_ids]],'index'=>'reservation_service_order_id']); } foreach ($ret['list'] as &$item) { $item['status_text'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP[$item['service_status']]; $item['server_status_text'] = $server_status_map[$item['server_status']]??''; $item['service_start_at_text'] = ""; $item['duration'] = ($item['service_end_at'] - $item['service_start_at']) / 60; $item['be_late'] = ""; if (!empty($item['service_start_at'])){ $item['service_start_at_text'] = date('Y-m-d H:i', $item['service_start_at']); if($item['service_type']== 2){ if($item['at_store_time']){ //已到店 $late_time = $item['at_store_time']-$item['service_start_at']; }else{ $late_time = time() - $item['service_start_at']; } if($late_time>=60){ $item['be_late'] = '迟到'; $day = bcdiv($late_time,86400); if(!empty($day)){ $item['be_late'].= $day.'天'; } $hour = bcdiv($late_time-$day*86400,3600); if(!empty($hour)){ $item['be_late'].= $hour.'时'; } $minute = bcdiv($late_time-$day*86400-$hour*3600,60); if(!empty($day)){ $item['be_late'].= $minute.'分钟'; } } } } $item['mall_name'] = $mall_name; $item['mall_logo'] = $mall_logo; $item['create_type_text'] = ReservationServiceEnum::CREATE_TYPE_MAP[ $item['create_type']] ?? '未知'; if($item['store_id']){ $item['goods']=$store_goods_list[$item['goods_id']]??[]; }else{ $item['goods']=$goods_list[$item['goods_id']]??[]; } if (!empty($item['store_id'])) { $store = Store::findOne(['id' => $item['store_id']]); $item['mall_name'] = $store->store_name; $item['mall_logo'] = $store->logo_img; $reserveOrder = StoreOrderReserve::findOne(['main_order_id' => $item['order_id']]); if(empty($item['service_type'])){ $item['service_type'] = $reserveOrder->service_type; }else{ $item['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[ $item['service_type']] ?? '未知服务'; } } else { $reserveOrder = OrderReserve::findOne(['order_id' => $item['order_id']]); if(empty($item['service_type'])){ $item['service_type'] = $reserveOrder->service_type; }else{ $item['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[ $item['service_type']] ?? '未知服务'; } } $item['reserveOrder'] = []; if(!empty($reserveOrder)){ $item['reserveOrder'] = $reserveOrder->toArray(); } //次卡部分----start $item['secondary_card'] = []; $item['is_secondary_card'] = 0; if(!empty($secondary_card_order_list)&&isset($secondary_card_order_list[$item['secondary_card_no']])){ $item['is_secondary_card'] = 1; $secondary_card_order = $secondary_card_order_list[$item['secondary_card_no']]; $item['secondary_card'] = [ 'name'=>$secondary_card_order['secondaryCard']['name'], 'font_color'=>$secondary_card_order['secondaryCard']['font_color'], 'background'=>$secondary_card_order['secondaryCard']['background'], 'order_no'=>$secondary_card_order['order_no'], 'reservation_service_order_id'=>$secondary_card_order['id'], ]; $item['secondary_card']['order_source'] = \addons\SecondaryCard\common\service\SecondaryCardOrderService::getSourceName($secondary_card_order,$secondary_card_order['secondaryCard']['use_type']); $item['secondary_card']['service_times'] = $use_log_list[$item['id']]['clerk_nums']??1; $item['secondary_card']['service_income'] = $use_log_list[$item['id']]['service_income']??0; $item['secondary_card']['clerk_money'] = $use_log_list[$item['id']]['clerk_money']??0; // $item['service_type_text'] = \addons\SecondaryCard\common\service\SecondaryCardService::getServiceTypeText($secondary_card_order['secondaryCard']); } //次卡部分----end } } $tabsIndex = [999, 0, 1, 90, 100]; if (!empty($params['staff_user_id'])) { foreach ($tabsIndex as $index) { $badgeQuery = ReservationServiceOrder::find() ->where(['mall_id' => $mall_id, 'staff_user_id' => $params['staff_user_id'], // 这里处理一下 'status' => StatusEnum::ENABLED]); $num = StatusEnum::DISABLED; switch ($index) { case ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL: // 待接单 $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]) // ->andWhere(['>=', 'updated_at', time() - 86400]) ->count(); break; case ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING: // 待服务 $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING]) // ->andWhere(['>=', 'updated_at', time() - 86400]) ->count(); break; case ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER: // 待验收 $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]) // ->andWhere(['>=', 'updated_at', time() - 86400]) ->count(); break; case ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH: // 已完成 $num = 0; break; } $ret['tab_badge'][$index] = (int) $num; } } return $ret; } /** * 平台订单详情 * @param int $mall_id * @param int $order_id * @param int $user_id * @param null $platform * @return array|mixed|string */ public function orderDetail(int $mall_id, int $order_id, int $user_id = 0, $platform = null) { // 返回订单预约详情 $select = 'id,mall_id,store_id,order_no,receiver_name,mobile,pay_money,shipping_money,original_goods_price,coupon_money,goods_price,order_status,pay_status, shipping_status,review_status,is_feedback,address,created_at,pay_time,region_name,remark,consign_time,finish_time,sign_time,shipping_type,payment_type,score,score_money,marketing_id,marketing_type,extra_info,order_source,is_bill'; $where = []; $where[] = ['mall_id' => $mall_id]; $where[] = ['id' => $order_id]; if (!empty($user_id)) $where[] = ['user_id' => $user_id]; $order = Order::getOne($where, true, ['detail' => function ($query) { $query->select('id,order_id,goods_id,goods_name,pic_url,num,price,is_feedback,sign_id,goods_attr_name,order_status,adjust_money,extra_info'); }], false, $select); if (empty($order)) return '该订单不存在'; $marketing = OrderMarketing::getMarketingInfo($order); $order['order_status_text'] = OrderStatusEnum::getMap(); $order['is_feedback_text'] = OrderStatusEnum::getFeedbackMap(); $order['shipping_type_text'] = ShippingTypeEnum::getMap(); $order['payment_type_text'] = PayTypeEnum::getMap(); $order['created_at'] = date('Y-m-d H:i:s', $order['created_at']); $order['pay_time'] = date('Y-m-d H:i:s', $order['pay_time']); if ($platform) $order['pay_type_list'] = \Yii::$app->services->pay->getEnablePayment($mall_id, $platform); $order['change_price'] = array_sum(array_column($order['detail'],'adjust_money'));//预留字段 $order['marketing'] = $marketing; $order['marketing_type_map'] =MarketingTypeEnum::getMap(); $order_setting = Yii::$app->services->setting->mall->get($mall_id, 'order'); $order['payment_expire_time'] = $order_setting['payment_expire_time']??30; $order['auto_receiving_time'] = $order_setting['auto_receiving_time']??14; //查询商品单位 if($order['detail']){ foreach ($order['detail'] as $k => $v){ $goods_unit = Goods::getOne([['=','id',$v['goods_id']]],false,'','','unit')['unit']; $order['detail'][$k]['unit'] = $goods_unit; } } // 获取订单详情的状态文字描述 $order['status_text'] = OrderStatusEnum::getApiStatus($order['order_status'], $order['shipping_type']); $order['status'] == OrderStatusEnum::NOT_PAY && $order['status_text']['desc'] = $order['payment_expire_time'] . $order['status_text']['desc']; $order['status'] == OrderStatusEnum::SHIPMENTS && $order['status_text']['desc'] = $order['auto_receiving_time'] . $order['status_text']['desc']; $order['is_show_return_btn'] = 0; $order['return_prompt_content'] = ''; $is_show_return_btn = $order_setting['is_show_return_btn'] ?? 0; if(empty($order['is_feedback']) && empty($order['mch_id']) && empty($order['store_id']) && $is_show_return_btn && in_array($order['order_status'], [OrderStatusEnum::SHIPMENTS,OrderStatusEnum::SING,OrderStatusEnum::PAY])){ $order['is_show_return_btn'] = 1; $order['return_prompt_content'] = $order_setting['return_prompt_content'] ?? ''; } if (!empty($order['store_id'])) { $store = Store::findOne(['id' => $order['store_id']]); $order['mall_name'] = $store->store_name; $order['mall_logo'] = $store->logo_img; } else { $order['mall_name'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.name'); $order['mall_logo'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo'); } // 公共调用 return GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $mall_id, [ 'order' => $order, 'mall_id' => $mall_id, ]) ?: $order; } /** * 通过订单ID获取订单详情 * @param int $mall_id * @param int $user_id * @param int $order_id * @param $platform * @return array|mixed|string */ public function getOrderDetailById(int $mall_id, int $user_id, int $order_id, $platform) { $order = $this->orderDetail($mall_id, $order_id, $user_id, $platform); if (is_array($order)) { /** * @var $orderReserve OrderReserve */ $orderReserve = OrderReserve::getOne([ ['mall_id' => $mall_id], ['order_id' => $order_id], ['reserve_type' => StatusEnum::ENABLED] ]); if (empty($orderReserve)) return '订单不存在'; $order['reserve'] = $orderReserve->toArray(); // 取出预约的服务人员 $order['staff'] = ReservationServiceOrder::getOne([ ['mall_id' => $mall_id], ['order_id' => $order_id], ['user_id' => $user_id], ['status' => StatusEnum::ENABLED], ], true, ['staff' => function($query) { $query->select('user_id, name, gender, age, avatar, store_id'); }], 'id asc', 'id, user_id, service_status, staff_user_id, service_start_at, user_id, service_end_at'); } return $order; } /** * 通过ID获取订单详情 * @param int $mall_id * @param int $user_id * @param int $id * @return array|mixed|string */ public function getDetailById(int $mall_id, int $user_id, int $id) { $rWhere = [ ['mall_id' => $mall_id], ['id' => $id], // ['status' => StatusEnum::ENABLED], ['staff_user_id' => $user_id] ]; // 判断当前用户是否有权限查看当前订单 /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($rWhere); if (empty($model)) return '预约记录不存在'; if (!empty($model->store_id)) { $order_no = Order::find()->where(['mall_id' => $mall_id]) ->andWhere(['id' => $model->order_id]) ->select('order_no')->scalar(); if (empty($order_no)) return '订单不存在.'; $storeOrder = StoreOrder::findOne(['mall_id' => $mall_id, 'store_id' => $model->store_id, 'order_no' => $order_no]); if (empty($storeOrder)) return '订单不存在!'; /** * @var $orderReserve StoreOrderReserve */ $orderReserve = StoreOrderReserve::getOne([ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['order_id' => $storeOrder->id] ]); } else { $where = [ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['order_id' => $model->order_id] ]; /** * @var $orderReserve OrderReserve */ $orderReserve = OrderReserve::getOne($where); } if (empty($orderReserve)) return '订单不存在'; $order = $this->orderDetail($mall_id, $model->order_id); if (is_array($order)) { $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray(); $order['reserve'] = $orderReserve->toArray(); $order['service_status_map'] = [ 0 => '待接单', 1 => '待核销', 20 => '已取消接单', 50 => '拒绝接单', 70 => '已关闭', 90 => '已核销', 100 => '已完成' ]; // $order['service_status_map'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP; foreach ($order['detail'] as $val) { if ($val['order_status'] == -4) { $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_CLOSED; break; } } $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态'; $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at); $order['service_min'] = ($model->service_end_at - $model->service_start_at) / 60; // 分钟 $order['service_status'] = $model->service_status; $order['service_type'] = $orderReserve->service_type; // 是否为上面服务 $order['create_type'] = $model->create_type; $order['commission'] = bcmul($model->commission, 1, 2); $order['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve->service_type] ?? '未知服务'; if (!empty($order['finish_time'])) date('Y-m-d H:i:s', $order['finish_time']); if (!empty($order['sign_time'])) date('Y-m-d H:i:s', $order['sign_time']); } //次卡部分 if(!empty($model->secondary_card_id)){ if (MallAddons::isInstall($mall_id,'SecondaryCard')){ $secondary_card = SecondaryCard::findOne(['id'=>$model->secondary_card_id]); $order['secondary_card'] = [ 'name' => $secondary_card['name'], 'background' => $secondary_card['background'], 'font_color' => $secondary_card['font_color'], 'reservation_cancel_type' => $secondary_card['reservation_cancel_type'], 'service' => json_decode($secondary_card['service'],true), 'secondary_card_no' => $model->secondary_card_no, ]; $order['service_type_text'] = SecondaryCardService::getServiceTypeText($secondary_card); $secondary_card_order = SecondaryCardOrder::findOne(['order_no'=>$model->secondary_card_no]); $order['secondary_card']['verifiable_times'] =$secondary_card_order['verifiable_times']; $order['secondary_card']['use_times'] =$secondary_card['verifiable_times']-$secondary_card_order['verifiable_times']; $order['secondary_card']['clerk_code'] = $secondary_card_order['clerk_code']; $order['secondary_card']['order_source'] = SecondaryCardOrderService::getSourceName($secondary_card_order,$secondary_card['use_type']); $use_log = SecondaryCardUseLog::findOne(['reservation_service_order_id'=>$model['id']]); $order['secondary_card']['order_money'] = bcdiv($secondary_card_order['pay_money'],$secondary_card['verifiable_times'],2) ; $order['secondary_card']['service_income'] = $use_log['service_income']??0; $order['secondary_card']['service_times'] = $use_log['clerk_nums']??1; $order['secondary_card']['clerk_money'] = $use_log['clerk_money']??0; } } return $order; } /** * 扫码获取的订单详情 * @param int $mall_id * @param int $user_id * @param string $code * @param int $order_id * @param int $store_id * @return array|mixed|string */ public function getDetailByCodeOrId(int $mall_id, int $user_id, string $code = '', int $order_id = 0, int $store_id = 0) { // 这里无效了 if (!empty($store_id)) { if (empty($order_id)) return '订单ID不能为空'; $order_no = Order::find()->where(['mall_id' => $mall_id]) ->andWhere(['id' => $order_id]) ->select('order_no')->scalar(); if (empty($order_no)) return '订单不存在.'; $storeOrder = StoreOrder::findOne(['mall_id' => $mall_id, 'store_id' => $store_id, 'order_no' => $order_no]); if (empty($storeOrder)) return '订单不存在!'; /** * @var $orderReserve StoreOrderReserve */ $orderReserve = StoreOrderReserve::getOne([ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['order_id' => $storeOrder->id] ]); if (empty($orderReserve)) return '订单不存在'; if ($orderReserve['service_type'] == 1) { $store_reserve_setting = (new StoreReserveSettingService(['mall_id' => $mall_id, 'store_id' => $store_id]))->detail(); if (empty($store_reserve_setting['technician_verification_switch'])) { throw new \Exception('技师核销开关未开启'); } } } else { $where = [ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED] ]; if (!empty($code)) $where[] = ['reserve_code' => $code]; if (!empty($order_id)) $where[] = ['order_id' => $order_id]; /** * @var $orderReserve OrderReserve */ $orderReserve = OrderReserve::getOne($where); if (empty($orderReserve)) { /** * @var $orderReserve StoreOrderReserve */ $orderReserve = StoreOrderReserve::getOne([ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['reserve_code' => $code] ]); if (empty($orderReserve)) return '订单不存在'; $order_id = $orderReserve->main_order_id; $store_id = $orderReserve->store_id; $this->checkClerk($user_id, $store_id, $orderReserve['tech_id'], $orderReserve['service_type']); } else { $order_id = $orderReserve->order_id; } } $rWhere = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ]; if (!empty($store_id)) { $rWhere[] = ['store_id' => $store_id]; } else { $rWhere[] = ['staff_user_id' => $user_id]; } // 判断当前用户是否有权限查看当前订单 /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($rWhere, false, [], 'id desc'); if (empty($model)) return '预约记录不存在'; if (!empty($store_id)) { $user_id = $model['staff_user_id'];////替换成技师的会员id } // self::checkStoreStaffCanClerk($mall_id, $store_id, $user_id); $order = $this->orderDetail($mall_id, $model->order_id); if (is_array($order)) { $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray(); $order['reserve'] = $orderReserve->toArray(); $order['service_status_map'] = [ 1 => '待核销', 70 => '已关闭', 90 => '已核销', 100 => '已完成' ]; $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态'; $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at); } return $order; } /** * 检查门店技师在当前时间是否可以核销 * @param $store_id * @param $user_id * @return true * @throws \Exception */ public static function checkStoreStaffCanClerk($mall_id, $store_id, $user_id) { if (empty($store_id)) { return true; } $time = time(); $date = date('Y-m-d', $time); $date_time = strtotime($date . ' 00:00:00'); $scheduling = StoreReserveTechnicianScheduling::find()->where(['mall_id' => $mall_id, 'store_id' => $store_id, 'user_id' => $user_id, 'date_time' => $date_time, 'status' => StatusEnum::ENABLED]) ->with(['schedulingTime'])->one(); if (!empty($scheduling['is_all_day'])) { $store = Store::findOne(['id' => $store_id, 'mall_id' => $mall_id]); $business_time_start = strtotime($date . ' ' . $store['business_time_start'] . ':00'); $business_time_end = strtotime($date . ' ' . $store['business_time_end'] . ':00'); if ($time < $business_time_start || $time > $business_time_end) { throw new \Exception('当前时间不是门店营业时间'); } } else { if (empty($scheduling['schedulingTime'])) { throw new \Exception('当前时间技师没有排班'); } $is_true = false; foreach ($scheduling['schedulingTime'] as $val) { if ($time >= $val['start_time'] && $time <= $val['end_time']) { $is_true = true; break; } } if ($is_true == false) { throw new \Exception('当前时间技师没有排班'); } } return true; } /** * 获取核销记录详情 * @Author:hua * @Date:2024-03-14 10:26 * @Copyright:copyright(c)2024 广东七件事集团 * @param $mall_id * @param $reservation_service_order_id * @param $order_id * @return array|mixed|string */ public function getClerkLogDetail( $mall_id, $reservation_service_order_id , $order_id ) { $where = [ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['order_id' => $order_id] ]; $orderReserve = OrderReserve::getOne($where); if (empty($orderReserve)) { $orderReserve = StoreOrderReserve::getOne([ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['main_order_id' => $order_id] ]); if (empty($orderReserve)) return '订单不存在'; } $rWhere = [ ['mall_id' => $mall_id], ['id' => $reservation_service_order_id], ['status' => StatusEnum::ENABLED], ]; $model = ReservationServiceOrder::getOne($rWhere); if (empty($model)) return '预约记录不存在'; $order = $this->orderDetail($mall_id, $model->order_id); if (is_array($order)) { $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray(); $order['reserve'] = $orderReserve->toArray(); $order['service_status_map'] = [ 1 => '待核销', 90 => '已核销', 100 => '已完成' ]; $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态'; $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at); } return $order; } /** * 通过订单ID进行核销 * @param int $mall_id * @param int $user_id * @param int $order_id * @param int $store_id * @return ReservationServiceOrder|string */ public function underwriter(int $mall_id, int $user_id, int $order_id, int $store_id = 0) { $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING], ]; // 门店核销,门店所有技师都能进行核销处理,所以不需要绑定至某个用户,只需要判断当前用户是否为门店技师即可 if (!empty($store_id)) { $where[] = ['store_id' => $store_id]; } else { $where[] = ['staff_user_id' => $user_id]; } /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return '预约记录不存在或不可核销'; $t = \Yii::$app->db->beginTransaction(); try { $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER; $model->remark = "{$model->remark} 技师 [$user_id] 核销了当前订单 \n"; if (!$model->save()) throw new \Exception($model->getErrorMessage()); /** * @var $staff ReservationServiceUser */ $staff = $model->getStaff()->one(); // 累加订单 if (!empty($model->store_id)) { $staff->store_order_num += 1; } else { $staff->order_num += 1; } if (!$staff->save()) throw new \Exception($staff->getErrorMessage()); $user = User::findOne(['id' => $user_id]); $data['id'] = $order_id; $data['mall_id'] = $mall_id; $data['user_id'] = $model->user_id; $data['operator_id'] = $user_id; $data['operator_name'] = $user->nickname ?? $user->mobile; $data['from'] = OrderSourceEnum::SOURCE_RESERVE; $data['tech_id'] = $staff->id; // 技师ID $res = Order::takeDelivery($data); if ($res === false) throw new \Exception(Order::getStaticError()); if (!empty($model->store_id)) { $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } else { $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } $orderReserve->reserve_status = ReservationServiceEnum::CHECK_FAILED; // 如果是在后台直接核销的那么就没办法绑定技师了,所以一定需要技师进行核销才能处理 if (empty($orderReserve->tech_id)) $orderReserve->tech_id = $staff->id; // 绑定技师ID if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage()); $t->commit(); return $model; } catch (\Exception $e) { $t->rollBack(); return $e->getMessage(); } } /** * 通过核销码进行核销 * @param int $mall_id * @param int $user_id * @param int $order_id * @param int $store_id * @return ReservationServiceOrder|string */ public function clerk(int $mall_id, int $user_id, int $code, int $store_id = 0) { $where = [ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED] ]; if (!empty($code)) $where[] = ['reserve_code' => $code]; if (!empty($order_id)) $where[] = ['order_id' => $order_id]; /** * @var $orderReserve OrderReserve */ $orderReserve = OrderReserve::getOne($where); $service_type_text = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve['service_type']] ?? ''; $mall_logo = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo'); $mall = Mall::findOne(['id'=>$mall_id]); $mall_name = $mall['name']; if (empty($orderReserve)) { /** * @var $orderReserve StoreOrderReserve */ $orderReserve = StoreOrderReserve::getOne([ ['mall_id' => $mall_id], ['reserve_type' => StatusEnum::ENABLED], ['reserve_code' => $code] ]); if (empty($orderReserve)) return '订单不存在'; $this->checkClerk($user_id, $orderReserve->store_id, $orderReserve['tech_id'], $orderReserve['service_type']); $order_id = $orderReserve->main_order_id; $store_id = $orderReserve->store_id; $service_type_text = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve['service_type']] ?? ''; $store = Store::findOne(['id' => $orderReserve['store_id']]); $mall_logo = $store['logo_img']; $mall_name = $store['store_name']; } else { $order_id = $orderReserve->order_id; } $order = Order::findOne(['id'=>$order_id]); $order_detail = OrderDetail::findOne(['order_id'=>$order_id]); $num = OrderDetail::find()->where(['order_id'=>$order_id])->sum('num'); $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING], ]; $clerk_user_id = $user_id;//操作核销的会员id if (!empty($store_id)) { $where[] = ['store_id' => $store_id]; } else { $where[] = ['staff_user_id' => $user_id]; } /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return '预约记录不存在或不可核销'; if (!empty($store_id)) { $user_id = $model['staff_user_id'];//替换成技师的会员id } // self::checkStoreStaffCanClerk($mall_id, $store_id, $user_id); $t = \Yii::$app->db->beginTransaction(); try { $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER; $model->server_status = ReservationServiceEnum::TO_BE_ACCEPTED; $model->remark = "{$model->remark} , [$clerk_user_id] 核销了当前订单 \n"; if (!$model->save()) throw new \Exception($model->getErrorMessage()); /** * @var $staff ReservationServiceUser */ $staff = $model->getStaff()->one(); if (empty($staff)) { throw new \Exception('该订单未分配技师,不能核销'); } // 累加订单 if (!empty($model->store_id)) { $staff->store_order_num += 1; } else { $staff->order_num += 1; } if (!$staff->save()) throw new \Exception($staff->getErrorMessage()); $user = User::findOne(['id' => $user_id]); $data['id'] = $order_id; $data['mall_id'] = $mall_id; $data['user_id'] = $model->user_id; $data['operator_id'] = $user_id; $data['operator_name'] = $user->nickname ?? $user->mobile; $data['from'] = OrderSourceEnum::SOURCE_RESERVE; $data['tech_id'] = $staff->id; // 技师ID $res = Order::takeDelivery($data); if ($res === false) throw new \Exception(Order::getStaticError()); // 因为进行核销后平台预约订单和门店预约订单状态并为改为待服务,所以进行核销后需要修改 Order::updateAll(['order_status' => OrderStatusEnum::SING], ['id' => $model->order_id]); if (!empty($model->store_id)) { StoreOrder::updateAll(['order_status' => OrderStatusEnum::SING], ['id' => $orderReserve->order_id]); $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } else { $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } $orderReserve->reserve_status = OrderReserve::RESERVE_STATUS_PENDDING; // 如果是在后台直接核销的那么就没办法绑定技师了,所以一定需要技师进行核销才能处理 if (empty($orderReserve->tech_id)) $orderReserve->tech_id = $staff->id; // 绑定技师ID if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage()); $add_clerk_log_data = [ 'mall_id' => $model['mall_id'], 'user_id' => $clerk_user_id, 'mall_logo' => $mall_logo, 'mall_name' => $mall_name, 'name' => $order_detail['goods_name'], 'pic' => $order_detail['pic_url'], 'clerk_code' => (string)$code, 'type' => ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE, 'extra' => json_encode([ 'clerk_nums' => $num, 'verifiable_times' => 0, 'clerk_money' => 0, 'settled_money' => 0, 'order_money' => $order['pay_money'], 'pay_money' => $order['pay_money'], 'unit_times' => 0, 'service_type_text' => $service_type_text, 'service_income'=> $model['commission'], 'reservation_service_order_id'=> $model['id'], 'order_id'=> $order_id, ]), ]; $clerk_log_model = ClerkLog::setData($add_clerk_log_data); if ($clerk_log_model == false) { throw new \Exception(ClerkLog::getStaticError()); } $t->commit(); return $model; } catch (\Exception $e) { $t->rollBack(); \Yii::error('code:' . $code . ';;;' . $e->getMessage()); return $e->getMessage(); } } public function checkClerk($user_id, $store_id, $tech_id, $service_type) { $store = Store::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]); //先判断是不是本店店长 if (!empty($store)) { if ($store_id != $store['id']) { $reservation_service_user = ReservationServiceUser::findOne(['user_id' => $user_id, 'store_id' => $store_id, 'status' => StatusEnum::ENABLED]); if ($store_id != $reservation_service_user['store_id'] || $tech_id != $reservation_service_user['id']) { throw new \Exception('该订单你没有权限核销'); } } } else { $reservation_service_user = ReservationServiceUser::findOne(['user_id' => $user_id, 'store_id' => $store_id, 'status' => StatusEnum::ENABLED]); if (empty($reservation_service_user)) { //不是店长,先判断是不是本店核销员 $store_clerk = StoreClerk::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]); if (empty($store_clerk) || $store_id != $store_clerk['store_id']) { throw new \Exception('该订单你没有权限核销'); } } else { //技师,判断是不是同一个技师 if ($store_id != $reservation_service_user['store_id'] || $tech_id != $reservation_service_user['id']) { throw new \Exception('该订单你没有权限核销'); } if ($service_type == 1) { $store_reserve_setting = (new StoreReserveSettingService(['mall_id' => $reservation_service_user['mall_id'], 'store_id' => $store_id]))->detail(); if (empty($store_reserve_setting['technician_verification_switch'])) { throw new \Exception('技师核销开关未开启'); } } } } } /** * 接受订单 * @param int $mall_id * @param int $user_id * @param int $order_id * @param int $store_id * @return ReservationServiceOrder|string */ public function talking(int $mall_id, int $user_id, int $order_id, int $store_id = 0) { $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ['staff_user_id' => $user_id], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL] ]; if (!empty($store_id)) $where[] = ['store_id' => $store_id]; /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return '预约记录不存在'; $t = \Yii::$app->db->beginTransaction(); try { $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING; $model->remark = "{$model->remark} 技师 [$user_id] 接受了当前订单的预约 \n"; if (!$model->save()) throw new \Exception($model->getErrorMessage()); // 同意之后是否需要写入预约时间? // 并且写入技师ID $staff = ReservationServiceUser::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]); if (!empty($model->store_id)) { // 取出门店的预约订单 $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } else { $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } $orderReserve->tech_id = $staff->id; $orderReserve->reserve_status = StatusEnum::ENABLED; $orderReserve->reserve_date_time = date('Y-m-d H:i', $model->service_start_at) .','. date('Y-m-d H:i', $model->service_end_at); if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage()); // 被预约的时间 $bookTime = new ReservationServiceUserBookTime(); $bookTime->order_id = $model->order_id; $bookTime->user_id = $model->staff_user_id; $bookTime->mall_id = $model->mall_id; $bookTime->start_time = $model->service_start_at; $bookTime->end_time = $model->service_end_at; if (!$bookTime->save()) throw new \Exception($bookTime->getErrorMessage()); $user = User::findOne(['id' => $user_id]); if(!empty($model->secondary_card_id)){ $form['mall_id'] = $model->mall_id; $form['mch_id'] = 0; $form['shipping_type'] = 0; $form['id'] = $model->order_id; $form['operator_id'] = $user_id; $form['order_detail_ids'] = OrderDetail::find()->where(['order_id' => $model->order_id])->select('id')->column(); $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile; OrderExpress::delivery($form); // 发货 $form['mall_id'] = $mall_id; $form['shipping_type'] = 0; $form['mch_id'] = 0; $form['store_id'] = $model->store_id; $form['operator_id'] = $model->staff_user_id; $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile; $form['id'] = $orderReserve->order_id; $form['order_detail_ids'] = StoreOrderDetail::find()->where(['order_id' => $orderReserve->order_id])->select('id')->column(); $res = StoreOrder::OrderExpressDelivery($form); if (!$res) throw new \Exception(StoreOrder::getStaticError()); }else{ if (empty($model->store_id)) { // 门店也需要执行? // 执行发货操作 $form['mall_id'] = $model->mall_id; $form['mch_id'] = 0; $form['shipping_type'] = 0; $form['id'] = $model->order_id; $form['operator_id'] = $user_id; $form['order_detail_ids'] = OrderDetail::find()->where(['order_id' => $model->order_id])->select('id')->column(); $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile; OrderExpress::delivery($form); // 发货 } else { // 门店发货 $form['mall_id'] = $mall_id; $form['shipping_type'] = 0; $form['mch_id'] = 0; $form['store_id'] = $model->store_id; $form['operator_id'] = $model->staff_user_id; $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile; $form['id'] = $orderReserve->order_id; $form['order_detail_ids'] = StoreOrderDetail::find()->where(['order_id' => $orderReserve->order_id])->select('id')->column(); $res = StoreOrder::OrderExpressDelivery($form); if (!$res) throw new \Exception(StoreOrder::getStaticError()); } } $main_order = Order::findOne(['order_no' => $model['order_no']]); $main_order->order_status = OrderStatusEnum::SHIPMENTS; $main_order->shipping_time = time(); $main_order->save(); $t->commit(); // 记录数据 (new NoticeLogic())->send(['mall_id' => $mall_id, 'id' => $order_id, 'sms_key' => ReservationServiceEnum::SMS_KEY_AGREE]); return $model; } catch (\Exception $e) { $t->rollBack(); return $e->getMessage().$e->getFile().$e->getLine(); } } /** * 拒绝接单 * @param int $mall_id * @param int $user_id * @param int $order_id * @param int $store_id * @param string $reason * @return ReservationServiceOrder|string */ public function reject(int $mall_id, int $user_id, int $order_id, int $store_id = 0, string $reason = '无') { $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ['staff_user_id' => $user_id], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL] ]; if (!empty($store_id)) $where[] = ['store_id' => $store_id]; /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return '预约记录不存在'; $t = \Yii::$app->db->beginTransaction(); try { $remark = "{$model->remark} 技师 [$user_id] 拒绝了当前订单的预约, 拒绝理由[$reason] \n"; if($model->secondary_card_id){ $order = Order::findOne(['id'=>$model->order_id]); $order->status = StatusEnum::DISABLED; $order->save(); StoreOrder::updateAll(['status'=>StatusEnum::DISABLED],['order_no'=>$order->order_no]); $remark = "{$model->remark} 技师 [$user_id] 拒绝了当前次卡的预约, 拒绝理由[$reason] \n"; } $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_REJECT; $model->remark = $remark; $model->reject_reason = $reason; if (!$model->save()) throw new \Exception($model->getErrorMessage()); if (!empty($model->store_id)) { /** * @var $reserveOrder StoreOrderReserve */ $reserveOrder = StoreOrderReserve::getOne(['main_order_id' => $model['order_id']]); } else { /** * @var $reserveOrder OrderReserve */ $reserveOrder = $model->getReserveOrder()->one(); } $reserveOrder->reserve_status = OrderReserve::RESERVE_STATUS_WAIT; // 等待预约 $reserveOrder->tech_id = 0; if (!$reserveOrder->save()) throw new \Exception($reserveOrder->getErrorMessage()); $t->commit(); // 记录数据 (new NoticeLogic())->send(['mall_id' => $mall_id, 'id' => $order_id, 'sms_key' => ReservationServiceEnum::SMS_KEY_REJECT]); return $model; } catch (\Exception $e) { $t->rollBack(); return $e->getMessage(); } } /** * 取消预约 * @param int $mall_id * @param int $user_id * @param int $order_id * @param int $store_id * @param bool $is_buyer * @return ReservationServiceOrder|string */ public function cancel(int $mall_id, int $user_id, int $order_id, int $store_id = 0, bool $is_buyer = false) { $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], // ['staff_user_id' => $user_id], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING] ]; if ($is_buyer) { $role = '用户'; $where[] = ['user_id' => $user_id]; } else { $role = '技师'; $where[] = ['staff_user_id' => $user_id]; } if (!empty($store_id)) $where[] = ['store_id' => $store_id]; /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return '预约记录不存在'; $t = \Yii::$app->db->beginTransaction(); try { $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_CANCEL; $model->remark = "{$model->remark} {$role} [$user_id] 取消了当前订单的预约 \n"; if (!$model->save()) throw new \Exception($model->getErrorMessage()); if (!empty($model->store_id)) { $storeOrder = StoreOrder::findOne(['order_no' => $model->order_no]); if (empty($storeOrder)) throw new \Exception("预约订单不存在"); $orderReserve = StoreOrderReserve::findOne(['order_id' => $storeOrder->id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } else { $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]); if (empty($orderReserve)) throw new \Exception("预约订单不存在"); } $orderReserve->tech_id = 0; $orderReserve->reserve_status = 0; // $orderReserve->reserve_date_time = ''; if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage()); // 清除预约时间 ReservationServiceUserBookTime::updateAll(['status' => StatusEnum::DELETE], ['and', ['status' => StatusEnum::ENABLED], ['order_id' => $model->order_id]]); // 清除发货信息 if (empty($model->store_id)) { $order = Order::findOne(['id' => $order_id]); $order->sign_time = 0; $order->order_status = OrderStatusEnum::PAY; $order->shipping_status = StatusEnum::DISABLED; if (!$order->save()) throw new \Exception($order->getErrorMessage()); // 清除详情发货信息 OrderDetail::updateAll(['order_status' => OrderStatusEnum::PAY, 'shipping_status' => StatusEnum::DISABLED], ['in', 'id', OrderDetail::find()->where(['order_id' => $order_id])->select('id')->column()]); } if($model->secondary_card_id>0){ $order = Order::findOne(['id' => $model->order_id]); $order->status = StatusEnum::DISABLED; if (!$order->save()) throw new \Exception($order->getErrorMessage()); } $t->commit(); return $model; } catch (\Exception $e) { $t->rollBack(); return $e->getMessage(); } } /** * 验收 - 等同于平台订单确认收货 - 门店后台/门店技师/技师 * @param int $mall_id * @param int $order_id * @param int $user_id * @param int $store_id * @param null $admin * @param bool $run_global * @return ReservationServiceOrder|string */ public function acceptance(int $mall_id, int $order_id, int $user_id = 0, int $store_id = 0, $admin = null, bool $run_global = true) { $where = [ ['mall_id' => $mall_id], ['order_id' => $order_id], ['status' => StatusEnum::ENABLED], ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER] ]; if (!empty($store_id)) $where[] = ['store_id' => $store_id]; if (!empty($user_id)) $where[] = ['user_id' => $user_id]; /** * @var $model ReservationServiceOrder */ $model = ReservationServiceOrder::getOne($where); if (empty($model)) return !$run_global ? '预约记录不存在' : true; if ($model->service_status == ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH) return $model; if ($model->service_status != ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER) return '当前状态不可验收'; $t = \Yii::$app->db->beginTransaction(); try { // 门店核销员 if (!empty($user_id)) { $remark = "用户 [$user_id] 验收了当前预约订单"; } elseif (!empty($store_id)) { $remark = "门店 [$store_id] 验收了当前预约订单"; } elseif (!empty($admin)) { $remark = "后台雇员 [$admin->id] 验收了当前预约订单"; } else { $remark = "系统自动验收了当前预约订单"; } $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH; $model->remark = "{$model->remark} $remark \n"; $model->server_status = ReservationServiceEnum::COMPLETED; // $model->service_status = 100; if (!$model->save()) throw new \Exception($model->getErrorMessage()); // 执行平台的处理 if ($run_global) { $this->globalComplete($mall_id, $user_id, $model, $admin); } // 累加订单 if (!empty($model->store_id)) { $staff = $model->getStaff()->one(); $staff->store_order_num += 1; $staff->save(); } $t->commit(); return $model; } catch (\Exception $e) { $t->rollBack(); Yii::error(FormatHelper::exception($e, __METHOD__)); return $e->getMessage(); } } /** * @param int $mall_id * @param int $user_id * @param ReservationServiceOrder $reservationServiceOrder * @param $admin * @return void * @throws \Exception */ protected function globalComplete(int $mall_id, int $user_id, ReservationServiceOrder $reservationServiceOrder, $admin) { $nickname = ""; $mobile = ""; $operator_id = $user_id; if (!empty($admin)) { $nickname = $admin->account; $operator_id = $admin->id; } else if (!empty($user_id)) { /** * @var $user User */ $user = User::findOne(['id' => $user_id]); $nickname = $user->nickname; $mobile = $user->mobile; } $data['id'] = $reservationServiceOrder->order_id; $data['mall_id'] = $mall_id; if (!empty($user)) $data['user_id'] = $user_id; $data['operator_id'] = $operator_id; $data['operator_name'] = !empty($nickname) ? $nickname : $mobile; $data['from'] = OrderSourceEnum::SOURCE_RESERVE; $res = Order::complete($data); if ($res === false) throw new \Exception(Order::getStaticError()); } /** * @param int $mall_id * @param int $store_id * @return int[] */ public function dataStatistics(int $mall_id, int $store_id = 0) { // 累计服务数量 // 昨日服务数量 $query = ReservationServiceOrder::find()->where(['mall_id' => $mall_id]) ->andWhere(['status' => StatusEnum::ENABLED]) // ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]]); // 修改原因:现在按核销数量来计算,核销后,就会有核销备注“XXX核销了订单”,所以用备注不为空来计算 ->andWhere(['!=', 'remark', '']); if (!empty($store_id)) $query->andWhere(['store_id' => $store_id]); $y = strtotime(date('Y-m-d')) - 86400; return [ 'total' => $query->count(), 'yesterday' => $query ->andWhere(['between', 'service_start_at', $y, strtotime(date('Y-m-d'))]) ->count(), ]; } /** * 写入前校验 * @param array $params * @return ReservationServiceUser * @throws \Exception */ public function valid(array $params) { // 校验技师 /** * @var $staff ReservationServiceUser */ $staff = ReservationServiceUser::findOne(['mall_id' => $params['mall_id'], 'id' => $params['tech_id'], 'status' => StatusEnum::ENABLED, 'check_status' => ReservationServiceEnum::CHECK_ADOPT]); if (empty($staff)) throw new \Exception('技师不存在'); // 距离判断? $distance = (new LocationHelper())->getDistanceByGeo($staff->latitude, $staff->longitude, $params['lat'], $params['lng']); if (!empty($params['store_id'])) { $goods = StoreGoodsReserve::findOne([ 'goods_id' => $params['goods_id'] ]); } else { $goods = GoodsReserve::findOne([ 'goods_id' => $params['goods_id'] ]); } if ($distance > $goods->distance) { throw new \Exception("不在支持范围"); } return $staff; } /** * 写入数据 - 应该在订单支付的时候写入 * @param array $params * @return ReservationServiceOrder * @throws \Exception */ public function save(array $params) { // $staff = $this->valid($params); /** * @var $staff ReservationServiceUser */ if (!empty($params['tech_id'])) { $staff = ReservationServiceUser::findOne(['mall_id' => $params['mall_id'], 'id' => $params['tech_id'], 'status' => StatusEnum::ENABLED, 'check_status' => ReservationServiceEnum::CHECK_ADOPT]); } // if (empty($staff)) throw new \Exception('技师不存在'); // 是否已经预约过 if (!empty(ReservationServiceOrder::find()->where(['order_id' => $params['order_id']]) ->andWhere(['status' => StatusEnum::ENABLED]) ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH]])->one())) { throw new \Exception("不可重复预约"); }; if (empty($params['store_id']) && !empty($params['tech_id'])) { // 门店没有佣金 /** * @var $level ReservationServiceLevel */ $level = $staff->getLevel()->andWhere(['mall_id' => $params['mall_id']])->one(); $params['commission'] = $level->item_commission; if (empty($level->item_commission_type)) { $params['commission'] = bcmul(bcmul($params['commission'], $params['goods_price'], 2), 0.01, 2); } /** * @var $goodsSetting ReservationServiceGoodsSetting */ $goodsSetting = ReservationServiceGoodsSetting::getOne([ ['mall_id' => $params['mall_id']], ['status' => StatusEnum::ENABLED], ['item_id' => $params['goods_id']], ['item_type' => 'goods'], ['is_enable' => StatusEnum::ENABLED], ['commission_type' => UserWalletService::WALLET_TYPE_COMMISSION] ]); if (!empty($goodsSetting)) { $params['commission'] = $goodsSetting->commission; if (!empty($goodsSetting->is_percent)) { $params['commission'] = bcmul(bcmul($params['commission'], $params['goods_price'], 2), 0.01, 2); } } if ($params['commission'] < 0) $params['commission'] = 0; } if (empty($params['tech_id'])) { $params['is_match'] = StatusEnum::ENABLED; } $params['staff_user_id'] = $staff->user_id ?? 0; $model = new ReservationServiceOrder(); $model->loadDefaultValues(); if (!$model->load($params, '') || !$model->save()) throw new \Exception($model->getErrorMessage()); // 记录数据 (new NoticeLogic())->send(['mall_id' => $params['mall_id'], 'id' => $params['order_id'], 'sms_key' => ReservationServiceEnum::SMS_KEY_RESERVE]); return $model; } /** * 核销记录 * @param int $mall_id * @param array $params * @return array|false|mixed|string|null */ public function underwriterList(int $mall_id, array $params) { $where = [ ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED], ['staff_user_id' => $params['user_id']], ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH]] ]; $with = ['order' => function($query) { $query->with(['detail']); }, 'store' => function($query) { $query->select('id, store_name, logo_img'); }]; $ret = ReservationServiceOrder::listPage([ 'where' => $where, 'order' => 'id desc', 'limit' => $params['limit'] ?? 10, 'with' => $with ]); if (!empty(ReservationServiceOrder::getStaticError())) return ReservationServiceOrder::getStaticError(); return $ret; } /** * 获取技师信息 * @param int $order_id * @param $mall_id * @return void */ public function getStaffByOrderId(int $order_id, $mall_id) { $staff = ReservationServiceOrder::getOne([ ['order_id' => $order_id], ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]], ], true, ['staff' => function($query) use($mall_id) { $with = []; $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_STORE); if ($is_install) { $with = ['store' => function($query) { $query->select('id, store_name, logo_img'); }]; } $query->select('name, user_id, avatar, age, store_id')->with($with)->andwhere(['status' => StatusEnum::ENABLED]); }], 'id desc', 'staff_user_id'); return !empty($staff['staff']) ? $staff['staff'] : null; } /** * 全局调用 * @param array $params * @return mixed */ public function preview(array $params) { $response = $params['data']; $input = $params['params']; // 只能是一件商品 if (count($response['group_order_goods']) > 1 || empty($response['group_order_goods'][0]['goods'])) return $response; if (count($response['group_order_goods'][0]['goods']) > 1) return $response; $change_shipping_type_list = false; foreach ($response['group_order_goods'][0]['goods'] as $good) { if (!empty($good['reserve']) && $good['reserve']['reserve_type'] == StatusEnum::ENABLED) { // 仅限于家政服务 $good['reserve']['service_type'] = 1; $change_shipping_type_list = true; // switch ($good['reserve']['service_type']) { // case 1: // case 2: // case 3: foreach ($response['shipping_type_list'] as $key => $item) { if ($key != $good['reserve']['service_type']) unset($response['shipping_type_list'][$key]); if ($key > 2) unset($response['shipping_type_list'][$key]); } // break; // } } } // shipping_type_list if (!empty($input['tech_id'])) { $response['tech'] = $this->findByTech($input['tech_id'], $input['latitude'], $input['longitude'], $params['mall_id']); } if ($change_shipping_type_list) { if (!empty($response['shipping_type_list'][1])) $response['shipping_type_list'][1] = '上门服务'; if (!empty($response['shipping_type_list'][2])) $response['shipping_type_list'][2] = '到店服务'; } // 是否需要校验短信验证码 return $response; } /** * @param int $tech_id * @param $lat * @param $lng * @param $mall_id * @return array|mixed */ public function findByTech(int $tech_id, $lat, $lng, $mall_id) { // 判断预约服务是否安装门店 $with = []; $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_STORE); if ($is_install) { $with = ['store' => function($query) { $query->select("id, store_name, logo_img, shop_owner, shop_mobile, longitude, latitude, address, province_id, city_id, district_id"); }]; } $tech = ReservationServiceUser::getOne([ ['id' => $tech_id] ], true, $with, 'id asc', 'avatar, name, age, gender, store_id'); if (!empty($tech['store'])) { $tech['store']['region'] = implode("", Region::find()->where(['id' => [$tech['store']['province_id'], $tech['store']['city_id'], $tech['store']['district_id']]]) ->select('name')->column()); $tech['store']['distance'] = LocationHelper::formatDistance((new LocationHelper())->getDistanceByGeo($lat, $lng, $tech['store']['latitude'], $tech['store']['longitude'])); } return $tech; } /** * 执行退款 * @return void * @throws \Exception */ public function refund() { foreach (ReservationServiceOrder::find()->select('id, mall_id')->where(['is_refund' => StatusEnum::DISABLED]) ->andWhere(['>', 'refund_at', 0])->andWhere(['<=', 'refund_at', time()]) ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING]]) ->each() as $item) { // 这里操作退款 // 先申请退款 // 再执行退款 \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, ['mall_id' => $item->mall_id, 'id' => $item->id], self::class, 'createRefund'); // $this->createRefund(['mall_id' => $item->mall_id, 'id' => $item->id]); } } /** * 生成退款订单 * @param array $data * @return bool */ public function createRefund(array $data) { $rOrder = ReservationServiceOrder::findOne(['id' => $data['id']]); if (empty($rOrder) || $rOrder->is_refund != StatusEnum::DISABLED) return true; $order = Order::findOne(['id' => $rOrder->order_id]); $order_detail_id = OrderDetail::find()->where(['order_id' => $order->id])->scalar(); // 申请退款 $t = Yii::$app->db->beginTransaction(); try { $rOrder->is_refund = 1; // 退款中 if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage()); $params = [ 'order_detail_id' => $order_detail_id, 'reason' => '预约订单超时自动售后退款', 'remark' => '', 'type' => RefundTypeEnum::MONEY, 'refund_price' => $order->pay_money, 'user_id' => $order->user_id, 'mall_id' => $order->mall_id, 'pic_list' => Json::encode([]), ]; $res = OrderRefund::feedback($params); if ($res === false) throw new \Exception(Order::getStaticError()); $t->commit(); $event = new \common\events\order\OrderRefundEvent(); $event->mall_id = $order->mall_id; $order_detail['order_detail_id'] = $order_detail_id; $order_detail['id'] = $res->id; $order_detail['operator_id'] = 0; $order_detail['operator_name'] = '系统自动申请'; Yii::$app->services->events->dispatch($event, $order_detail, $event->listeners); \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER, RabbitMqEnum::ORDER_QUEUE, ['mall_id' => $order->mall_id, 'id' => $res->id, 'r_order_id' => $rOrder->id], self::class, 'refundPay'); // $this->refundPay(['mall_id' => $order->mall_id, 'id' => $res->id, 'r_order_id' => $rOrder->id]); } catch (\Exception $e) { $t->rollBack(); // var_dump($e->getMessage(), $e->getFile(), $e->getLine()); \Yii::error(FormatHelper::exception($e, __METHOD__)); return false; } return true; } /** * 退款支付打款 * @param array $params * @return bool */ public function refundPay(array $params) { $rOrder = ReservationServiceOrder::findOne(['id' => $params['r_order_id']]); if (empty($rOrder) || $rOrder->is_refund != StatusEnum::ENABLED) return true; // 退货地址 $address = ['consignee' => '','mobile' => '','address' => '']; // 换货物流信息 $express = ['saler_express' => '','saler_express_no' => '','customer_name' => '']; $data = [ 'id' => $params['id'], 'step_status' => RefundStatusEnum::STEP_6, // 直接打款操作 'address' => $address, 'express' => $express, 'refund_reason' => '', 'not_dec_fee' => StatusEnum::ENABLED, // 不需要手续费 ]; // 申请退款 $t = Yii::$app->db->beginTransaction(); try { $rOrder->is_refund = 100; // 退款中 if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage()); $logic = new OrderRefundLogic(); $res = $logic->execute($rOrder->mall_id, $data); if (!$res) throw new \Exception($logic->getError()); $t->commit(); } catch (\Exception $e) { $t->rollBack(); // var_dump("1", $e->getMessage(), $e->getFile(), $e->getLine()); \Yii::error(FormatHelper::exception($e, __METHOD__)); return false; } return true; } /** * 执行退款 废弃 * @param array $data * @return bool */ public function completeRefund(array $data) { $rOrder = ReservationServiceOrder::findOne(['id' => $data['id']]); if (empty($rOrder) || $rOrder->is_refund != StatusEnum::DISABLED) return true; $order = Order::findOne(['id' => $rOrder->order_id]); // 申请退款 $t = Yii::$app->db->beginTransaction(); try { $rOrder->is_refund = 100; // 退款中 if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage()); $order_detail_id = OrderDetail::find()->where(['order_id' => $order->id])->scalar(); $wallet_type = UserWalletService::WALLET_TYPE_BALANCE; if ($order->payment_type == PayTypeEnum::SCORE) $wallet_type = UserWalletService::WALLET_TYPE_SCORE; OrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_6), 'updated_at' => time()], ['order_id' => $order->id]); $is_install = MallAddons::isInstall($order->mall_id, AddonsEnum::ADDONS_NAME_STORE); Order::autoUpdateStatus($order); if($is_install){ $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]); if(!empty($store_order)){ $order['out_trade_no'] = $store_order['out_trade_no']; StoreOrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_6), 'updated_at' => time()], ['main_order_detail_id' => $order_detail_id]); StoreOrder::autoUpdateStatus($store_order); } } // 申请退款 if(in_array($order->payment_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])){ // 本地支付 // 如果是代付,那么就需要原路退回 $insert_wallet[] = [ 'mall_id' => $order->mall_id, 'user_id' => $order->user_id, 'is_frozen' => false, 'wallet_type' => $wallet_type,// 暂定退回余额或积分 'money' => $order->pay_money, 'desc' => '预约订单超时自动售后退款', 'source_table' => ReservationServiceOrder::tableName(), 'source_table_id' => $rOrder->id, 'from_type' => UserWalletEnum::REFUND, 'capital_type' => UserWalletEnum::REFUND_ORDER, 'order_no' => $order->order_no, 'not_add_total' => true ]; $res = UserWalletService::batchHandleByQueue($insert_wallet); if (empty($res)) throw new \Exception(UserWalletService::getStaticError()); } elseif(in_array($order->payment_type,[PayTypeEnum::JOINPAY,PayTypeEnum::ALI,PayTypeEnum::JOINPAY_FAST_PAY,PayTypeEnum::WECHAT])){ //原路返回 $out_trade_no = $order['out_trade_no']; $res = Yii::$app->services->pay->refund($order->pay_money,$order->pay_money, $out_trade_no, $order, '预约订单超时自动售后退款'); if ($res === false) throw new \Exception('退款失败'); } elseif ( // 当res返回为false 说明没有相对于的退款方式 $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_ORDER_REFUND, $order->mall_id, [ 'id' => 0, 'mall_id' => $order->mall_id, 'refund' => [ 'order_id' => $order->id, 'order_no' => $order->order_no, 'refund_price' => $order->pay_money ], 'order_no' => $order['order_no'], 'refund_order_no' => $order['order_no'], 'params' => [], 'pay_type' => $order->payment_type, ]) ) { // 当res不为空 进此判断 list($boolean, $msg) = $res; if ($boolean === false) { throw new \Exception($msg); } } else { } // 订单营销扣减返还 if(empty($order['store_id'])){ $res = OrderMarketing::deductBack($order['id'], [$order_detail_id], [$order_detail_id],$order->mall_id,$order->user_id,'订单退款', UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER); if (!$res) throw new \Exception(OrderMarketing::getStaticError()); }else{ if(MallAddons::isInstall($order['mall_id'],AddonsEnum::ADDONS_NAME_STORE)){ $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]); $store_order_detail_ids = array_column($store_order->detail,'id'); $store_order_detail_arr = array_column($store_order->detail,'id','main_order_detail_id'); $store_order_detail_id = $store_order_detail_arr[$order_detail_id]??0; $res = StoreOrderMarketing::deductBack($store_order,$store_order_detail_ids,[$store_order_detail_id],$order->mall_id, $order->user_id,'订单退款',UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER); if (!$res) throw new \Exception(StoreOrderMarketing::getStaticError()); } } $t->commit(); } catch (\Exception $e) { $t->rollBack(); \Yii::error(FormatHelper::exception($e, __METHOD__)); return false; } return true; } /** * 关闭预约订单 * @param int $mall_id * @param int $order_id * @return int */ public function closed(int $mall_id, int $order_id) { return ReservationServiceOrder::updateAll(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_CLOSED], ['and', ['order_id' => $order_id], ['mall_id' => $mall_id], ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]]]); } /** * 详情 * @param $params * @return mixed */ public function globalDetail($params) { if (empty($params['reserve'])) return $params['order']; if ($params['order']['reserve']['reserve_type'] == StatusEnum::ENABLED) { $params['order']['can_reserve'] = ReservationServiceOrder::find()->where(['order_id' => $params['order']['id']]) ->andWhere(['service_status' => [ ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ]])->count() == 0 ? StatusEnum::ENABLED : StatusEnum::DISABLED; } return $params['order']; } /** * 列表 * @param $params * @return mixed */ public function globalList($params) { if (empty($params['reserve'])) return $params['order']; if (!empty($params['order'])) { foreach ($params['order'] as &$item) { // 判断订单是否为预约订单 if ($item['reserve']['reserve_type'] == StatusEnum::ENABLED) { $item['can_reserve'] = ReservationServiceOrder::find()->where(['order_id' => $item['id']]) ->andWhere(['service_status' => [ ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ]])->count() == 0 ? StatusEnum::ENABLED : StatusEnum::DISABLED; } if ($item['order_source']=='Reserve'){ $service_order = ReservationServiceOrder::find()->where(['order_id' => $item['id']])->one(); $item['staff_user_id'] = 0; $item['nickname'] = ''; if(!empty($service_order['staff_user_id'])){ $user = User::findOne(['id'=>$service_order['staff_user_id']]); $item['nickname'] = $user['nickname']; $item['staff_user_id'] = $service_order['staff_user_id']; } } } } return $params['order']; } /** * 预约满员检测 * @param $goods_reserve_sku_id * @param $store_id * @param $date * @return bool * @throws \Exception */ public function checkReserveFull($goods_reserve_sku_id,$store_id = 0,$date = null) { if (empty($date)) { $time = time(); } else { $time = strtotime($date . ':00'); } $date = date('Y-m-d', $time); $start_time = strtotime($date.' 00:00:00'); $end_time = strtotime($date.' 23:59:59'); if(empty($store_id)){ $query = OrderReserve::find()->where(['attr_id' => $goods_reserve_sku_id]); $store_id = 0; $class = GoodsReserveSku::class; }else{ $query = StoreOrderReserve::find()->where(['attr_id' => $goods_reserve_sku_id]); //门店 $class = StoreGoodsReserveSku::class; } $query->andWhere(['!=', 'order_status', -4]); $goods_reserve_sku = $class::findOne(['id'=>$goods_reserve_sku_id]); if(empty($goods_reserve_sku)){ throw new \Exception('预约商品不存在'); } $counts = $query ->andWhere(['>=', 'service_start_at', $start_time])->andWhere(['<=', 'service_start_at', $end_time]) ->andWhere(['store_id'=>$store_id]) ->count(); if ($goods_reserve_sku['reserve_max_buy'] > 0 && $counts >= $goods_reserve_sku['reserve_max_buy']) { return false; } return true; } }