data = $data = is_array($form->data) ? $form->data : Json::decode($form->data, true); $skuId = $data['attr_id']; $timeId = $data['time_id'] ?? 0; //商品预约:时间ID $timeSpecId = $data['time_spec_id'] ?? 0;//商品预约:时间ID $buyNum = $data['num']; $serviceType = $data['service_type']; //服务类型 1上门 2到店 $address_id = $data['address_id']; $lat = $data['latitude']; $lng = $data['longitude']; $tech_id = $data['tech_id'] ?? 0 ; //项目服务预约:技师ID $select_time = $data['select_time'] ?? '' ; //项目服务预约:选择时间【2023-10-24 12:00】 if(empty($lat) || empty($lng)) throw new \Exception('请选择定位'); $form->data['order_source'] = OrderSourceEnum::SOURCE_RESERVE; $user = User::getOne([['id' => $form->user_id, 'mall_id' => $form->mall_id]]); if (empty($user)) throw new Exception('下单用户不存在'); if (!isset($data['num']) || (int)$data['num'] < 1) throw new Exception('请设置正确的下单数量'); $sku = StoreGoodsReserveSku::getOne([['id' => $skuId, 'mall_id' => $form->mall_id]], true, ['goods', 'reserve', 'goods.extra']); if(empty($sku) || empty($sku['goods'])) throw new Exception('找不到产品信息或者产品已删除'); if (empty($sku['goods']['is_on_sale'])) throw new Exception('商品' . $sku['goods']['goods_name'] . '已下架! '); $goods = $sku['goods']; if($goods['goods_type'] != GoodsTypeEnum::GoodsTypeReserved) throw new Exception('商品类型错误'); if (!empty($sku['reserve'])) { !empty($sku['reserve_date']) && $sku['reserve_date'] = json_decode($sku['reserve_date'], true); !empty($sku['reserve_week']) && $sku['reserve_week'] = explode(',', $sku['reserve_week']); !empty($sku['reserve_time_slot']) && $sku['reserve_time_slot'] = json_decode($sku['reserve_time_slot'], true); !empty($sku['reserve_time_slot_price']) && $sku['reserve_time_slot_price'] = json_decode($sku['reserve_time_slot_price'], true); $reserve = &$sku['reserve']; !empty($reserve['reserve_date']) && $reserve['reserve_date'] = json_decode($reserve['reserve_date'], true); !empty($reserve['reserve_time_slot']) && $reserve['reserve_time_slot'] = json_decode($reserve['reserve_time_slot'], true); !empty($reserve['reserve_time_slot_price']) && $reserve['reserve_time_slot_price'] = json_decode($reserve['reserve_time_slot_price'], true); !empty($reserve['service_type']) && $reserve['service_type'] = json_decode($reserve['service_type'], true); !empty($reserve['reserve_week']) && $reserve['reserve_week'] = explode(',', $reserve['reserve_week']); } $goodsId = $sku['goods_id']; // 扣减时间或时间段的库存 $reserve = StoreGoodsReserve::findOne(['goods_id' => $goodsId]); if (empty($reserve)) throw new \Exception('找不到该预约商品' . __METHOD__); $res = (new OrderService())->checkReserveFull($skuId, $sku['store_id'], $select_time); if ($res == false) { throw new \Exception('该商品预约已满'); } $reserve_type = $reserve['reserve_type']; //0商品预约,1项目服务预约 if($reserve_type){ //项目服务预约 只有在有选择技师的情况下才需要校验时间 if (!empty($tech_id)) $this->checkReservationService($sku,$tech_id,$select_time,$lat,$lng, $form->data['store_id']); //$serviceType = StatusEnum::ENABLED; // 技师一定是上门服务 }else{ throw new Exception("下单类型错误!"); /* // 预约模式(1按天预约 2按时间段预约) $reserveTimeRangeType = $sku['reserve_time_range_type']; // 预约时间处理 $time = StoreGoodsReserveTime::findOne($timeId); if (empty($time)) throw new \Exception('找不到该预约时间日期'); $date = $time->reserve_time; if ($time->stock < $buyNum) throw new \Exception('该预约时间日期已超过最大预约数量'); if ($reserveTimeRangeType == 2) { $timeSpec = GoodsReserveTimeSpec::findOne(['reserve_time_id' => $timeId, 'id' => $timeSpecId]); if (empty($timeSpec)) throw new \Exception('找不到该预约时间分片'); $startHis = $timeSpec->start; $endHis = $timeSpec->end; $start = implode(' ', [$date, $startHis]); if ($timeSpec->is_next) $date = date('Y-m-d', strtotime('+1 day', strtotime($date))); $end = implode(' ', [$date, $endHis]); $reserveDateTime = implode(' ', [$start, $end]); if ($timeSpec->stock < $buyNum) throw new \Exception('该预约时间段已超过最大预约数量'); }*/ } if ($serviceType === 1 && $form->action == AppEnum::ACTION_CREATE) { //1上门 $address= UserAddress::findOne(['user_id'=>$form->user_id,'id'=> $address_id]); $province = $address->province_id; $city = $address->city_id; $district = $address->district_id; if (empty($province) || empty($city) || empty($district) || empty($address) || empty($lat) || empty($lng)) { throw new \Exception('服务地址或定位信息错误'); } } // 上门/到店 $freight_type_arr = "1,2"; $t_freight_type_arr = [1, 2]; switch ($reserve->service_type) { case 1: $freight_type_arr = "1"; // 上门 $t_freight_type_arr = [1]; // 上门 break; case 2: $freight_type_arr = "2"; // 到店 $t_freight_type_arr = [2]; // 到店 break; } if (!in_array($data['service_type'], $t_freight_type_arr)) { throw new Exception('预约类型不匹配'); } // if ($buyNum > $sku['stock']) throw new Exception('商品' . $sku['goods']['goods_name'] . '超过可预约数量! '); $order_goods = new StoreOrderDetail(); $order_goods = $order_goods->loadDefaultValues(); $order_goods->goods_id = $goodsId; $order_goods->goods_name = $sku['goods']['goods_name']; $order_goods->goods_attr_id = $sku['id']; $order_goods->sign_id = $sku['sign_id']; $order_goods->goods_attr_name = $sku['name']; $order_goods->num = $buyNum; $order_goods->cost_price = $sku['cost_price']; $order_goods->price = $sku['price']; $order_goods->goods_price = BcHelper::mul($order_goods->num, $order_goods->price); $order_goods->original_goods_price = $order_goods->goods_price; $order_goods->pic_url = !empty($sku['pic_url']) ? $sku['pic_url'] : $sku['goods']['cover_pic']; $order_goods->user_id = $form->user_id; $order_goods->mch_id = $sku['goods']['mch_id'] ?? 0; $order_goods->mall_id = $form->mall_id; $order_goods->store_id = $form->data['store_id']; $order_goods->marketing_type = $data['marketing_type'] ?? '0'; $order_goods->marketing_id = $data['marketing_id'] ?? 0; // 默认数据带下单数量方便计算 $sku['goods']['freight_type'] = $freight_type_arr; $goods = $sku['goods']; $goods['number'] = $buyNum; $order_goods_arr = ArrayHelper::toArray($order_goods); $order_goods_arr['freight_type'] = $freight_type_arr; $order_goods_arr['supplier_type'] = $sku['goods']['supplier_type']; $order_goods_arr['supplier_id'] = $sku['goods']['supplier_id']; $order_goods_arr['supplier_goods_id'] = $sku['goods']['supplier_goods_id']; $order_goods_arr['store_id'] = $sku['goods']['store_id']; $order_goods_arr['credit_rate'] = $sku['goods']['credit_rate']??0; // $order_goods_arr['mch_id'] = $sku['goods']['supplier_id']; $form->order_goods[] = $order_goods_arr; // unset($sku['product']); $form->sku[$goodsId] = $sku; $form->user = $user; return $form; } catch (Exception $e) { $this->setError($e->getMessage()); return false; } } /** * 项目服务预约--检测 * @param $sku * @param $tech_id * @param $select_time * @param $lat * @param $lng * @param int $store_id * @return bool * @throws Exception */ private function checkReservationService($sku,$tech_id,$select_time,$lat,$lng, $store_id = 0) { $appointments_number = $store_goods_reserve_sku['reserve']['appointments_number'] ?? 0; $store_goods_reserve_sku = StoreGoodsReserveSku::findOne(['id' => $sku['id']]); if (!empty($appointments_number)) { $service_min = $store_goods_reserve_sku['service_min'] ?? 0; $start_time = strtotime($select_time); $end_time = $start_time + $service_min * 60; $store_order_reserve_list = StoreOrderReserve::lists([ 'where' => [ ['mall_id' => $store_goods_reserve_sku['mall_id']], ['store_id' => $store_id], ['goods_id' => $store_goods_reserve_sku['goods_id']], ['>=', 'service_start_at', $start_time], ['<=', 'service_end_at', $end_time], ['!=', 'order_status', -4], ['create_type' => 1], ], 'group' => 'service_start_at', 'select' => 'count(*) as counts,service_start_at', 'index' => 'service_start_at' ]); if (isset($store_order_reserve_list) && $store_order_reserve_list[$start_time]['counts'] >= $appointments_number) { throw new \Exception('同一时间点只能预约' . $appointments_number . '人'); } } $mall_id = $sku['mall_id']; if (!MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_RESERVATION_SERVICE)) { throw new \Exception('您还未安装当前插件'); } $time = strtotime($select_time); if($time <= time()) throw new \Exception('选择时间错误'); if(!$tech_id) throw new \Exception('请选择对应技师'); //检测技师 $check = TechniciansService::checkCanOrder($mall_id,$tech_id,$select_time,$sku['goods_id'],$sku['id'],$lat,$lng, $store_id); if(!$check) throw new Exception(TechniciansService::getStaticError()); return true; } /** * 获取下单类型 * @Author bing * @DateTime 2021-09-23 09:48:45 * @copyright: Copyright (c) 2020 广东七件事集团 * @return string */ public static function getType(): string { return 'reserve_now'; } }