[ 'task_name' => '自动验收', 'time_radix' => 86400, // 时间节点计算的基数,订单自动自动过售后的时间单位是天,转换为秒的基数是86400 'method' => 'complete', 'time_field' => 'service_end_at', 'default' => 7, // 自动过售后默认时间 7 天 ], ]; try { $mall_list = Mall::getEnableMallList(true); $mall_ids = array_column($mall_list, 'id'); if (empty($mall_ids)) { echo '没有可用商城,不做处理 ... ' . PHP_EOL; return ExitCode::UNSPECIFIED_ERROR; } foreach ($mall_ids as $mall_id) { // 订单自动处理时间 $order_auto_handle_time = \Yii::$app->services->setting->mall->get($mall_id, $config_key); // 如果自动处理时间没有配置,则取默认值 if (empty($order_auto_handle_time)) $order_auto_handle_time = $action_info_map[$action]['default']; // 订单自动处理时间节点,延后两分钟处理,避免支付回调尚未回来订单已经被取消s $time_node = time() - $order_auto_handle_time * $action_info_map[$action]['time_radix'] - 120; $time_field = $action_info_map[$action]['time_field']; $where = [ 'and', ['mall_id' => $mall_id], ['<', $time_field, $time_node] ]; if (!empty($order_wheres)) { foreach ($order_wheres as $order_where) { array_push($where, $order_where); } } foreach (ReservationServiceOrder::find()->where($where)->each(500) as $order) { var_dump($order['order_id']); $data = []; $data['id'] = $order['order_id']; $data['mall_id'] = $order['mall_id']; $data['user_id'] = $order['user_id']; $data['operator_id'] = 0; $data['operator_name'] = ''; $data['from'] = OrderSourceEnum::SOURCE_RESERVE; Order::complete($data); } } return ExitCode::OK; } catch (\Exception $e) { echo ' 订单' . $action_info_map[$action]['task_name'] . ' 任务处理出错:' . $e->getMessage() . PHP_EOL; return ExitCode::UNSPECIFIED_ERROR; } } public static function getSkuList(int $mall_id) { $goods_list = Goods::lists([ 'where' => [ ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED], ['check_status' => StatusEnum::ENABLED], ['is_on_sale' => StatusEnum::ENABLED], ['goods_type' => GoodsTypeEnum::GoodsTypeReserved], ], 'select' => 'id,goods_name', 'index' => 'id' ]); $goods_ids = array_column($goods_list, 'id'); $sku_list = GoodsReserveSku::lists([ 'where' => [ ['goods_id' => $goods_ids], ], 'select' => 'id,goods_id,service_min,name', ]); foreach ($sku_list as &$sku) { $sku['goods_name'] = $goods_list[$sku['goods_id']]['goods_name'] . ':' . $sku['name']; } return $sku_list; } public static function getReserveDay(int $mall_id) { $config = BackendService::getSetting($mall_id); $range_end = $config['range_end']; $range_end_arr = ReservationServiceEnum::RANGE_END_ARR_MAP; $days = $range_end_arr[$range_end] ?? 7; $day_arr = []; $time = strtotime(date('Y-m-d')); $end_time = $time + $days * 24 * 3600; for ($i = $time; $i < $end_time; $i += 24 * 60 * 60) { $day_arr[] = $i * 1000;; } return ['day_arr' => $day_arr]; } /** * 后台添加预约/预约看板添加预约,获取可以预约的时间段 * @param $params * @return array */ public function getReserveTimes($params) { $date_time = strtotime($params['date']); $staff_user_id = $params['staff_user_id'] ?? 0; if (!empty($params['staff_user_id'])) { $scheduling = ReserveTechnicianScheduling::getOne([ ['user_id' => $staff_user_id], ['date_time' => $date_time], ['status' => StatusEnum::ENABLED] ], true, ['schedulingTime']); if (empty($scheduling)) { return []; } } $buff = []; $sku = StoreGoodsReserveSku::findOne(['id' => $params['sku_id']]); $date_day = date('Y-m-d', strtotime($params['date'])); $time = time(); $service_min = $sku['service_min']; $obj = new StoreReserveSettingService(['mall_id' => $mall_id, 'store_id' => $this->store_id]); $store_reserve_setting = $obj->detail(); if (strtotime(date('Y-m-d')) == $date_time) { $range_start_time = $obj->getRangeStartTime($store_reserve_setting['range_start']); $time += $range_start_time; } $reservation_service_order_list = ReservationServiceOrder::lists([ 'where' => [ ['mall_id' => $mall_id], ['store_id' => $this->store_id], ['staff_user_id' => $staff_user_id], ['>=', 'service_start_at', strtotime($date_day . ' 00:00:00')], ['<=', 'service_end_at', strtotime($date_day . ' 23:59:59')], ['!=', 'server_status', ReservationServiceEnum::CANCELED] ] ]);//已预约 $reservation_service_order_arr = []; foreach ($reservation_service_order_list as $value) { $reservation_service_order_arr[$value['service_start_at']] = $value; } $occupy_list = ReservationServiceOccupy::lists([ 'where' => [ ['mall_id' => $mall_id], ['store_id' => $this->store_id], ['staff_user_id' => $staff_user_id], ['status' => StatusEnum::ENABLED] ] ] );//已占用时间 if (!empty($staff_user_id)) { if (!empty($scheduling['is_all_day'])) { //全天 $store = Store::findOne(['id' => $this->store_id]); $time1 = $date_day . " " . $store['business_time_start'] . ":00"; $time2 = $date_day . " " . $store['business_time_end'] . ":59"; $start = strtotime($time1); $end = strtotime($time2); $this->getBuff($start, $end, $service_min, $reservation_service_order_arr, $occupy_list, $time, $buff); } else { if (!empty($scheduling['schedulingTime'])) { foreach ($scheduling['schedulingTime'] as $val) { $start = $val['start_time']; $end = $val['end_time']; $this->getBuff($start, $end, $service_min, $reservation_service_order_arr, $occupy_list, $time, $buff); } } } } else { $store = Store::findOne(['id' => $this->store_id]); $time1 = $date_day . " " . $store['business_time_start'] . ":00"; $time2 = $date_day . " " . $store['business_time_end'] . ":59"; $start = strtotime($time1); $end = strtotime($time2); $this->getBuff($start, $end, $service_min, $reservation_service_order_arr, $occupy_list, $time, $buff); } return $buff; } public static function getReserveTime(int $mall_id) { $step = '00:01'; $picker_options_time = [ 'start' => "00:00", 'end' => "23:59", 'step' => $step, ]; return ['picker_options_time' => $picker_options_time]; } public static function getStaffUserList(int $mall_id, $params) { if (empty($params['goods_id'])) { $sku = GoodsReserveSku::findOne(['id' => $params['sku_id']]); if ($sku === null) throw new \Exception('商品不存在.'); $goods_id = $sku['goods_id']; } else { $goods_id = $params['goods_id']; } $reservation_ervice_store_goods_list = ReservationServiceGoods::lists(['where' => [ ['goods_id' => $goods_id], ['status' => StatusEnum::ENABLED], ['mall_id' => $mall_id] ]]); $user_ids = array_column($reservation_ervice_store_goods_list, 'user_id'); $list = ReservationServiceUser::lists([ 'where' => [ ['mall_id' => $mall_id], ['user_id' => $user_ids], ['status' => StatusEnum::ENABLED] ], 'select' => 'user_id,name' ]); return $list; } public static function getUser(int $mall_id, $params) { $user = User::findOne(['mall_id' => $mall_id, 'mobile' => $params['mobile'], 'status' => [StatusEnum::ENABLED]]); $name = ''; if ($user !== null) { if (!empty($user['nickname'])) { $name = $user['nickname']; } else { $name = $user['mobile']; } } return $name; } public static function getEditData(int $mall_id, $params) { $goods_list = Goods::lists([ 'where' => [ ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED], ['check_status' => StatusEnum::ENABLED], ['is_on_sale' => StatusEnum::ENABLED], ['goods_type' => GoodsTypeEnum::GoodsTypeReserved], ], 'select' => 'id,goods_name', 'with' => ['reserve' => function ($q) { $q->select('id,goods_id,service_min'); }], ]); $config = BackendService::getSetting($mall_id); $ret['goods_list'] = $goods_list; $ret['range_start'] = $config['range_start'] ?? 1; $ret['range_end'] = $config['range_end'] ?? 1; $order = []; $goods_name = ''; $service_type_arr = []; if (!empty($params['id'])) { $order = ReservationServiceOrder::getOne([ ['id' => $params['id'], 'mall_id' => $mall_id] ], true ); $user = User::findOne(['id' => $order['user_id']]); if ($user === null) throw new \Exception('用户不存在'); $order['mobile'] = $user['mobile']; $order['nickname'] = !empty($user['nickname']) ? $user['nickname'] : $user['mobile']; $order['at_date'] = date('Y-m-d', $order['service_start_at']); $order['at_time'] = date('H:i', $order['service_start_at']); $params['goods_id'] = $order['goods_id']; $params['sku_id'] = $order['goods_reserve_sku_id']; $order['sku_id'] = $order['goods_reserve_sku_id']; if (empty($order['staff_user_id'])) { $order['staff_user_id'] = ''; } if (empty($order['secondary_card_id'])) { $sku = GoodsReserveSku::findOne(['id' => $order['sku_id']]); if ($sku === null) throw new \Exception('商品不存在'); if (empty($sku['name'])) { $store_goods = Goods::findOne(['id' => $order['goods_id']]); if ($store_goods === null) throw new \Exception('商品不存在!'); $goods_name = $store_goods['goods_name']; } else { $goods_name = $sku['name']; } $ret['staff_user_list'] = self::getStaffUserList($mall_id, $params); $order['master'] = [ ['sku_id' => $order['sku_id'], 'staff_user_id' => $order['staff_user_id'], 'service_min' => $sku['service_min'] ?? 0] ]; } else { $params['secondary_card_id'] = $order['secondary_card_id']; $secondary_card = SecondaryCard::getOne([['id' => $order['secondary_card_id']]]); $goods_name = $secondary_card['name'] ?? ''; $ret['staff_user_list'] = self::getStaffUserListBySecondaryCard($mall_id, $params); $order['master'] = [ ['sku_id' => $order['secondary_card_id'], 'staff_user_id' => $order['staff_user_id'], 'service_min' => $secondary_card['appointment_interval_duration'] ?? 0] ]; switch ($secondary_card['reservation_service_type']) { case 1: $service_type_arr[] = ['value' => 1, 'label' => '上门服务']; break; case 2: $service_type_arr[] = ['value' => 2, 'label' => '到店服务']; break; case 3: $service_type_arr[] = ['value' => 1, 'label' => '上门服务']; $service_type_arr[] = ['value' => 2, 'label' => '到店服务']; break; } } } $ret['service_type_arr'] = $service_type_arr; $ret['reserve_order'] = $order; $ret['goods_name'] = $goods_name; $store = $params['store']; $business_time_start = strtotime(date('Y-m-d') . ' ' . $store['business_time_start'] . ':00'); $business_time_end = strtotime(date('Y-m-d') . ' ' . $store['business_time_end'] . ':00'); $H = date('H', $business_time_start); $start_time = $H * 60; $H = date('H', $business_time_end); $minute = date('i', $business_time_end); $end_time = $H * 60 + $minute; $ret['start_time'] = $start_time; $ret['end_time'] = $end_time; return $ret; } public static function getStaffUserListBySecondaryCard(int $mall_id, $params) { $reservation_service_store_secondary_card_list = ReservationServiceStoreSecondaryCard::lists(['where' => [ ['secondary_card_id' => $params['secondary_card_id']], ['status' => StatusEnum::ENABLED], ['mall_id' => $mall_id] ]]); $user_ids = array_column($reservation_service_store_secondary_card_list, 'user_id'); return ReservationServiceUser::lists([ 'where' => [ ['mall_id' => $mall_id], ['user_id' => $user_ids], ['status' => StatusEnum::ENABLED] ], 'select' => 'user_id,name' ]); } /** * 后台添加预约 * @param $params * @return array * @throws \yii\base\Exception * @throws \yii\db\Exception */ public static function setEditData(int $mall_id, $params) { $t = Yii::$app->db->beginTransaction(); try { $user = User::findOne(['mobile' => $params['mobile'], 'mall_id' => $mall_id]); if (!empty($user)) { if ($user['status'] != StatusEnum::ENABLED) { throw new \Exception('用户状态异常'); } else { $params['user_id'] = $user['id']; } } else { //注册用户 $user = self::setUser($mall_id, $params); $params['user_id'] = $user['id']; } $service_start_at = strtotime(date('Y-m-d', strtotime($params['at_date'])) . ' ' . $params['at_time'] . ':00'); $config = BackendService::getSetting($mall_id); if (!empty($params['id'])) { $model = ReservationServiceOrder::findOne(['id' => $params['id'], 'mall_id' => $mall_id]); if ($model === null) { throw new \Exception('数据不存在'); } $params['secondary_card_id'] = $model['secondary_card_id']; } $params['staff_user_id'] = !empty($params['master'][0]['staff_user_id']) ? $params['master'][0]['staff_user_id'] : 0; if (empty($params['secondary_card_id'])) { $params['sku_id'] = $params['master'][0]['sku_id'];; $store_goods_reserve_sku = GoodsReserveSku::findOne(['id' => $params['sku_id']]); if (empty($store_goods_reserve_sku)) { throw new \Exception('预约商品规格不存在'); } $service_min = TechniciansService::getServiceMin(1, $store_goods_reserve_sku['service_min'] ?? 0); $goods_id = $store_goods_reserve_sku['goods_id']; } else { $secondary_card = SecondaryCard::getOne([['id' => $params['secondary_card_id']]]); $service_min = TechniciansService::getServiceMin(1, $secondary_card['appointment_interval_duration'] ?? 0); $goods_id = 0; $params['sku_id'] = 0; } $service_end_at = $service_start_at + $service_min * 60; self::checkEdit($params['staff_user_id'], $service_start_at, $service_end_at); if (!empty($params['create_type'])) { $update['create_type'] = $params['create_type']; } if (!empty($params['id'])) { if ($params['staff_user_id'] != $model['staff_user_id']) { $staff = ReservationServiceUser::findOne(['user_id' => $params['staff_user_id'], 'status' => StatusEnum::ENABLED]); } } else { throw new \Exception('预约订单不存在'); } $model->user_id = $params['user_id']; $model->staff_user_id = $params['staff_user_id']; $model->goods_id = $goods_id; $model->service_start_at = $service_start_at; $model->service_end_at = $service_end_at; $model->reservation_model = $params['reservation_model']; $model->goods_reserve_sku_id = $params['sku_id']; $model->commission = self::calcCommission($mall_id, $params['staff_user_id'], $goods_id, $store_goods_reserve_sku['price'] ?? 0); $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL; if (!empty($params['create_type'])) { $model->create_type = $params['create_type']; } if (!empty($params['service_type'])) { $model->service_type = $params['service_type']; } $res = $model->save(); $reserve_date_time = date('Y-m-d H:i', $model->service_start_at) . ',' . date('Y-m-d H:i', $model->service_end_at); $update['reserve_date_time'] = $reserve_date_time; $update['service_start_at'] = $model->service_start_at; $update['service_end_at'] = $model->service_end_at; $update['service_type'] = $model->service_type; $update['reservation_service_order_id'] = $model['id']; $update['reserve_code'] = OrderReserve::getClerkCode($mall_id, ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE); if (isset($staff)) { $update['tech_id'] = $staff['id']; } unset($update['create_type']); OrderReserve::updateAll($update, ['order_id' => $model['order_id']]); // 核销码 Order::updateAll(['clerk_code' => $update['reserve_code']], ['id' => $model->order_id]); if ($res == false) { throw new \Exception($model->getErrorMessage()); } $t->commit(); return ['id' => $model['id']]; } catch (\Exception $e) { $t->rollBack(); throw new \Exception($e->getMessage()); } } public static function calcCommission(int $mall_id, $tech_id, $goods_id, $goods_price) { $staff = ReservationServiceUser::findOne(['mall_id' => $mall_id, 'user_id' => $tech_id, 'status' => StatusEnum::ENABLED, 'check_status' => ReservationServiceEnum::CHECK_ADOPT]); if ($staff === null) throw new \Exception('技师不存在'); /** * @var $level ReservationServiceLevel */ $level = $staff->getLevel()->andWhere(['mall_id' => $mall_id])->one(); $commission = $level->item_commission; if (empty($level->item_commission_type)) { $commission = bcmul(bcmul($commission, $goods_price, 2), 0.01, 2); } /** * @var $goodsSetting ReservationServiceGoodsSetting */ $goodsSetting = ReservationServiceGoodsSetting::getOne([ ['mall_id' => $mall_id], ['status' => StatusEnum::ENABLED], ['item_id' => $goods_id], ['item_type' => 'goods'], ['is_enable' => StatusEnum::ENABLED], ['commission_type' => UserWalletService::WALLET_TYPE_COMMISSION] ]); if (!empty($goodsSetting)) { $commission = $goodsSetting->commission; if (!empty($goodsSetting->is_percent)) { $commission = bcmul(bcmul($commission, $goods_price, 2), 0.01, 2); } } if ($commission < 0) $commission = 0; return $commission; } /** * 注册用户 * @param $params * @return bool|User * @throws \yii\base\Exception * @throws \yii\db\Exception */ protected static function setUser(int $mall_id, $params) { $password = substr($params['mobile'], -6, 6); $params['mall_id'] = $mall_id; if (empty($params['username'])) { $params['username'] = $params['mobile']; } $params['parent_id'] = 0; $params['level'] = 0; $params['source'] = User::SOURCE_ADD_PLATFORM; $params['platform'] = User::TYPE_MANUAL; $params['password'] = Yii::$app->getSecurity()->generatePasswordHash($password); return User::setData($params); } /** * 检查该时间段是否被预约或者被占用 * @param $staff_user_id * @param $service_start_at * @param $service_end_at * @param $reservation_service_order_id * @return void * @throws \Exception */ protected static function checkEdit($staff_user_id, $service_start_at, $service_end_at, $reservation_service_order_id = null, $create_type = 2) { $list = ReservationServiceOccupy::lists([ 'where' => [ ['staff_user_id' => $staff_user_id], ['status' => StatusEnum::ENABLED], ] ]); foreach ($list as $item) { if ($service_start_at >= $item['start_at'] && $service_start_at < $item['end_at']) { throw new \Exception('该时间段已被占用'); } if ($service_end_at >= $item['start_at'] && $service_end_at < $item['end_at']) { throw new \Exception('该时间段已被占用'); } } } }