| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571 |
- <?php
- namespace addons\ReservationService\common\services;
- use addons\ReservationService\common\enums\ReservationServiceEnum;
- use addons\ReservationService\common\models\ReservationServiceGoods;
- use addons\ReservationService\common\models\ReservationServiceOccupy;
- use addons\ReservationService\common\models\ReservationServiceOrder;
- use addons\ReservationService\common\models\ReservationServiceStoreGoods;
- use addons\ReservationService\common\models\ReservationServiceStoreSecondaryCard;
- use addons\ReservationService\common\models\ReservationServiceUser;
- use addons\ReservationService\common\models\ReservationServiceUserBookTime;
- use addons\ReservationService\common\models\ReservationServiceWorkTime;
- use addons\SecondaryCard\common\enums\SecondaryCardEnum;
- use addons\SecondaryCard\common\models\SecondaryCard;
- use addons\SecondaryCard\common\models\SecondaryCardRelateStore;
- use addons\SecondaryCard\common\models\SecondaryCardReservationService;
- use addons\Store\common\models\Store;
- use addons\Store\common\models\StoreGoods;
- use addons\Store\common\models\StoreGoodsReserve;
- use addons\Store\common\models\StoreGoodsReserveSku;
- use addons\Store\common\models\StoreOrderReserve;
- use addons\Store\common\models\StoreReserveTechnicianScheduling;
- use addons\Store\common\services\StoreReserveSettingService;
- use common\enums\AddonsEnum;
- use common\enums\GoodsTypeEnum;
- use common\enums\StatusEnum;
- use common\helpers\DateHelper;
- use common\helpers\LocationHelper;
- use common\models\goods\GoodsReserve;
- use common\models\goods\GoodsReserveSku;
- use common\models\goods\GoodsReserveTime;
- use common\models\mall\MallAddons;
- use common\models\order\OrderReserve;
- use common\models\order\OrderReserveComments;
- use common\traits\ErrorTrait;
- class TechniciansService
- {
- use ErrorTrait;
- public static function search($params,$page,$limit)
- {
- try{
- if(!$params['lat'] || !$params['lng']){
- throw new \Exception('经纬度缺失');
- }
- $mall_id = $params['mall_id'];
- $basic = \Yii::$app->services->setting->addons->get($mall_id, ReservationServiceEnum::ADDONS_NAME, 'basic') ?? [];
- if (empty($basic['is_enable']) && empty($params['store_id'])) {
- throw new \Exception('未开启预约服务');
- }
- $max_distance = $basic['max_distance'] ?? 20; //限制
- $is_working = $params['is_working'] ?? 1;
- $working_field = empty($params['store_id']) ? 'is_working' : 'store_status';
- $where[] = ['mall_id' => $params['mall_id'],'is_working'=> 1,'status' => StatusEnum::ENABLED,'check_status'=>StatusEnum::ENABLED ];
- $min_age = $params['min_age'] ?? 0;
- $max_age = $params['max_age'] ?? 0;
- $gender = $params['gender'] ?? 0;
- $name = $params['name'] ?? '';
- $goods_id = $params['goods_id'] ?? 0;
- $sku_id = $params['sku_id'] ?? 0;
- $service_min = 30;
- $user_ids = [];
- $longitude = 'longitude';
- $latitude = 'latitude';
- $s_longitude = 'longitude';
- $s_latitude = 'latitude';
- if($goods_id && $sku_id){
- $select_date = $params['date'] ?? date('Y-m-d');
- $select_time = $params['time'] ?? '';
- if (!empty($params['store_id'])) {
- // 取出门店下面的技师
- if(empty($params['id'])){
- $user_ids = ReservationServiceUser::find()->where(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id'],'status'=>StatusEnum::ENABLED])->select('user_id')->column();
- if (empty($user_ids)) throw new \Exception("当前门店暂无技师");
- }else{
- $user_ids[] = $params['id'];
- }
- $sku = StoreGoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- $longitude = 'store_lng';
- $latitude = 'store_lat';
- $s_longitude = 'store_lng as longitude';
- $s_latitude = 'store_lat as latitude';
- } else {
- if(empty($params['id'])){
- $support_user_list = ReservationServiceGoods::find()->where(['mall_id' => $params['mall_id'],'goods_id' => $goods_id,'status'=>StatusEnum::ENABLED])->select('user_id')->asArray()->all();
- $user_ids = array_column($support_user_list,'user_id');
- $user_ids = array_unique($user_ids);
- if(!$user_ids) throw new \Exception('没有技师支持该项目');
- }else{
- $user_ids[] = $params['id'];
- }
- $sku = GoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- if (!empty($select_time)) {
- $tech_ids = OrderReserve::find()
- ->where(['<=', 'service_start_at', strtotime($select_date . ' ' . $select_time . ':00')])
- ->andWhere(['>', 'service_end_at', strtotime($select_date . ' ' . $select_time . ':00')])
- ->andWhere(['!=', 'tech_id', 0])
- ->andWhere(['!=', 'order_status', -4])
- ->select('tech_id')->column();
- $booked_user_ids = ReservationServiceUser::find()->where(['id' => $tech_ids, 'status' => StatusEnum::ENABLED])->select('user_id')->column();
- }
- }
- $service_min = $sku['service_min'] ?? 30; //服务分钟
- if($select_time){
- $select_timestamp = strtotime($select_date.' '.$select_time);
- $select_time_arr = explode(':',$select_time);
- $start_time = $select_time_arr[0]*100+ $select_time_arr[1] *1;
- $end_time = $start_time + $service_min;
- $select_timestamp_end = $select_timestamp + 60 * $service_min;
- $select_week_day = date('w',strtotime($select_date));
- $user_times = ReservationServiceWorkTime::find()->where(['mall_id' => $mall_id,'user_id' => $user_ids,'status'=>StatusEnum::ENABLED])
- ->andWhere(['week_day' => $select_week_day])
- ->andWhere(['<=','start_time',$start_time])
- ->andWhere(['>=', 'end_time', $start_time])
- ->select('user_id')
- ->asArray()->all();
- if(!$user_times) throw new \Exception('该时间下没有技师支持该项目');
- $user_ids = array_column($user_times,'user_id');
- }
- //排除当前有项目的技师
- $user_ids = self::checkCanBook($mall_id,$user_ids,$select_timestamp,$select_timestamp_end);
- if(!$user_ids) throw new \Exception('该时间已满员');
- $scheduling_user_ids = self::getSchedulingUserIds($mall_id, $select_date, $select_time);
- }
- $sql = "SELECT id,mall_id,user_id,`level`, {$s_longitude}, {$s_latitude},`name`,service_rating,order_num,gender,age,`desc`,avatar,store_id, address,
- round(
- 2 * 6378.137 * ASIN(
- SQRT(
- POW(
- SIN(
- PI() * ({$params['lng']} - {$longitude}) / 360
- ),
- 2
- ) + COS(PI() * {$params['lat']} / 180) * COS({$latitude} * PI() / 180) * POW(
- SIN(
- PI() * ({$params['lat']} - {$latitude}) / 360
- ),
- 2
- )
- )
- )
- ,1) AS distance
- FROM `qimall_addons_reservation_service_user` WHERE (`mall_id`={$mall_id}) AND (`status`=1) AND (`is_working`=1) AND (`check_status`= 1) AND (`{$working_field}` ={$is_working}) HAVING (`distance`<={$max_distance})";
- if ($gender > 0){
- $gender = $gender > 1 ? 2: 1;
- $sql .= " AND `gender` = " . $gender;
- }
- if ($min_age > 0 || $max_age > 0){
- $sql .= " AND `age` >= " . $min_age;
- $sql .= " AND `age` <= " . $max_age;
- }
- if($name){
- $name = trim($name);
- $sql .= " AND `name` LIKE '%" . $name . "%'";
- }
- if($user_ids){
- $sql .= " AND `user_id` in (" . implode(',',$user_ids) . ")";
- }
- if (!empty($booked_user_ids)) {
- $sql .= " AND `user_id` not in (" . join(',', $booked_user_ids) . ")";
- }
- if (!empty($scheduling_user_ids)) {
- $sql .= " AND `user_id` not in (" . join(',', $scheduling_user_ids) . ")";
- }
- $count_sql = $sql;
- $orderBy = 'distance asc,id desc'; //1-距离
- if (isset($params['sort']) && $params['sort'] > 1){
- //1-距离,2-订单量 order_num ,3-好评 service_rating
- if($params['sort'] == 1){
- $orderBy = 'distance asc'; //1-距离
- }else{
- $orderBy = $params['sort'] == 2 ? 'order_num desc' : 'service_rating desc';
- }
- }
- $total_data = \Yii::$app->db->createCommand($count_sql)->queryAll();
- $count = count($total_data);
- $sql .= " ORDER BY {$orderBy}";
- $sql .= " limit " . ($page - 1) * $limit . ",{$limit}";
- $list = \Yii::$app->db->createCommand($sql)->queryAll();
- $default_jishi = [];
- if (!empty($list)) {
- $location_obj = new LocationHelper();
- $store_ids = array_column($list,'store_id');
- $store_ids = array_unique($store_ids);
- if (MallAddons::isInstall($mall_id, 'Store')) {
- $store_list = Store::find()->where(['id' => $store_ids, 'mall_id' => $mall_id])->select('id,store_name')->indexBy('id')->asArray()->all();
- }
- $comments = OrderReserveComments::lists([
- 'where' => [
- ['tech_user_id' => array_column($list, 'user_id')],
- ['reserve_type' => StatusEnum::ENABLED],
- ['store_id'=>0]
- ],
- 'select'=> 'COUNT(*) as total, tech_user_id',
- 'group' => 'tech_user_id',
- 'index' => 'tech_user_id'
- ]);
- foreach ($list as &$item) {
- $item['store_name'] = $store_list[$item['store_id']]['store_name'] ?? '平台自营';
- $distance = $location_obj->getDistanceByGeo($item['latitude'], $item['longitude'],$params['lat'] , $params['lng']);
- // $item['distance'] = bcmul(bcmul($distance, 1000, 4), 1, 1); //米
- $item['distance'] = LocationHelper::formatDistance($distance); //米
- $item['comment_num'] = $comments[$item['user_id']]['total'] ?? 0;
- $item['commentNum'] = $comments[$item['user_id']]['total'] ?? 0;
- $item['serviceNum'] = $item['order_num'];
- $item['detail'] = $item['desc'];
- $item['gender_txt'] = ReservationServiceEnum::GENDER_MAP[$item['gender']];
- }
- if($goods_id && $sku_id){
- //默认技师,时间
- // $default_jishi = $list[0];
- $service_user = new UserService();
- foreach ($list as $key1 => $item1) {
- $default_jishi = $item1;
- $default_jishi_times = $service_user->getWorkingTime($mall_id, $item1['user_id']);
- if (!empty($default_jishi_times)) break;
- }
- unset($list[$key1]);
- array_unshift($list, $default_jishi);
- $time1 = date('Y-m-d 00:00:00');
- $time2 = date('Y-m-d 23:59:59');
- $buff = [];
- $service_min = $service_min <= 0 ? 30 : $service_min;
- for($i=strtotime($time1) ;$i<=strtotime($time2) ; $i=$i+60*$service_min){
- $buff[]= ['time' => date("H:i",$i),'time_num' => 100 * date("H",$i)+date("i",$i)];
- }
- $data = BackendService::getSetting($mall_id);
- $range_start_time = self::getRangeStartTime($data['basic']['range_start'] ?? 0);
- $time = time();
- $today_day = date('Y-m-d', $time);
- if ($range_start_time) {
- $time += $range_start_time;
- }
- //最近7天是否可约
- for($i = 0;$i < 7;$i++){
- $w = date('w',strtotime("+$i days"));
- $date = date('Y-m-d',strtotime("+$i days"));
- $day_times = $default_jishi_times[$w] ?? [];
- if($day_times){
- foreach($day_times as $day_time_info){
- foreach($buff as $one_buff_key => $one_buff){
- if ($today_day == $date) {
- $temp = strtotime($date . ' ' . $one_buff['time'] . ':00');
- if ($temp < $time) {
- continue;
- }
- }
- $next_buff = $buff[$one_buff_key + 1] ?? [];
- if($day_time_info['start_time'] >= $one_buff['time_num'] && $next_buff && $day_time_info['start_time'] < $next_buff['time_num']){
- //check
- $end_timestamp = strtotime($date.' '.$one_buff['time']) + 60 * $service_min;
- $check = self::checkCanBook($mall_id,[$default_jishi['user_id']],strtotime($date.' '.$one_buff['time']),$end_timestamp);
- if(!$check) continue;
- // 如果是今天
- $now_time_number = intval(date('Hi'));
- if ($date == date('Y-m-d') && ($day_time_info['end_time']) < $now_time_number) continue;
- //符合
- $min = intval(date('i'));
- $hour = intval(date('H'));
- $t = $one_buff['time_num'] > $now_time_number ? $one_buff['time'] : ($min >= 30 ? sprintf("%s:00", $hour+1) : sprintf("%s:30", $hour));
- if ($one_buff['time_num'] > $now_time_number && $hour == 24 && $min >= 30) {
- $date = strtotime("+1 days", strtotime($date));
- $t = "00:00";
- }
- $default_jishi['lately_time_arr'] = [
- 'date' => $date,
- 'time' => $t,
- 'week_day' => GoodsReserveTime::getWeekDay($date)
- ];
- break 3;
- }
- }
- }
- }
- }
- }
- }
- $list_page['list'] = $list;
- $list_page['page'] = $page;
- $list_page['page_size'] = $limit;
- $list_page['count'] = $count;
- $list_page['page_count'] = ceil($count / $limit);
- $list_page['default_jishi'] = $default_jishi;
- return $list_page;
- }catch(\Exception $e){
- $list_page['list'] = [];
- $list_page['page'] = 0;
- $list_page['page_size'] = 10;
- $list_page['count'] = 0;
- $list_page['page_count'] = 0;
- $list_page['error_msg'] = $e->getMessage();
- return $list_page;
- }
- }
- /**
- * 获取该时间内的有门店排班的技师user_id
- * @param $mall_id
- * @param $select_date
- * @param $select_time
- * @return array
- */
- public static function getSchedulingUserIds($mall_id, $select_date, $select_time)
- {
- $select_time = strtotime($select_date . ' ' . $select_time . ':00');
- $date_time = strtotime($select_date . ' 00:00:00');
- $scheduling_user_ids = [];//在门店排班内的技师user_id
- if (MallAddons::isInstall($mall_id, 'Store')) {
- $scheduling_list = StoreReserveTechnicianScheduling::lists([
- 'where' => [
- ['mall_id' => $mall_id],
- ['status' => StatusEnum::ENABLED],
- ['date_time' => $date_time],
- ['>', 'user_id', 0],
- ],
- 'with' => ['schedulingTime'],
- ]);
- if (!empty($scheduling_list)) {
- $store_ids = [];
- foreach ($scheduling_list as $scheduling) {
- if ($scheduling['is_all_day'] == 1) {
- $store_ids[] = $scheduling['store_id'];
- }
- }
- if (!empty($store_ids)) {
- $store_list = Store::lists([
- 'where' => [
- ['mall_id' => $mall_id],
- ['id' => $store_ids],
- ],
- 'index' => 'id'
- ]);
- }
- foreach ($scheduling_list as $scheduling) {
- if ($scheduling['is_all_day'] == 1) {
- $store_info = $store_list[$scheduling['store_id']] ?? [];
- $business_time_start = $store_info['business_time_start'] ?? '';
- $business_time_end = $store_info['business_time_end'] ?? '';
- $business_time_start = strtotime($select_date . ' ' . $business_time_start . ':00');
- $business_time_end = strtotime($select_date . ' ' . $business_time_end . ':00');
- if ($select_time >= $business_time_start && $select_time <= $business_time_end) {
- $scheduling_user_ids[] = $scheduling['user_id'];
- }
- } else {
- if (!empty($scheduling['schedulingTime'])) {
- foreach ($scheduling['schedulingTime'] as $val) {
- if ($select_time >= $val['start_time'] && $select_time <= $val['end_time']) {
- $scheduling_user_ids[] = $scheduling['user_id'];
- break;
- }
- }
- }
- }
- }
- }
- }
- return $scheduling_user_ids;
- }
- public static function getRangeStartTime($range_start)
- {
- $range_start_time = 0;
- switch ($range_start) {
- case 2:
- $range_start_time = 30 * 60;
- break;
- case 3:
- $range_start_time = 60 * 60;
- break;
- }
- return $range_start_time;
- }
- public static function searchBySecondaryCard($params,$page,$limit){
- try{
- $mall_id = $params['mall_id'];
- if(!$params['lat'] || !$params['lng']){
- throw new \Exception('经纬度缺失');
- }
- if(!MallAddons::isInstall($mall_id,'SecondaryCard')){
- throw new \Exception('没有安装次卡插件');
- }
- $select = 'id,reservation_time_type,reservation_time,store_type,use_type,reservation_model';
- $secondary_card = SecondaryCard::getOne([['id'=>$params['secondary_card_id']]],true,[],false,$select);
- switch ($secondary_card['store_type']){
- case 1:
- if (!MallAddons::isInstall($mall_id, 'Store')) {
- throw new \Exception('没有安装o2o门店插件');
- }
- break;
- }
- if (!empty($params['store_id'] && $secondary_card['reservation_model'] == 2)) {
- $store_reserve_setting = (new StoreReserveSettingService(['mall_id' => $mall_id, 'store_id' => $params['store_id']]))->detail();
- $employee_selection = $store_reserve_setting['employee_selection'] ?? 1;
- if ($employee_selection == 3) {
- $list_page['list'] = [];
- $list_page['page'] = 0;
- $list_page['page_size'] = 10;
- $list_page['count'] = 0;
- $list_page['page_count'] = 0;
- $list_page['error_msg'] = '技师不可选';
- return $list_page;
- }
- }
- if($secondary_card['use_type'] != SecondaryCardEnum::USE_TYPE_ALL){
- $secondary_card_relate_store_list = SecondaryCardRelateStore::lists([
- 'where'=>[
- ['mall_id'=>$mall_id],
- ['secondary_card_id'=>$params['secondary_card_id']],
- ['status'=>StatusEnum::ENABLED]
- ]
- ]);
- $store_id_arr = array_column($secondary_card_relate_store_list,'store_id');
- }
- $longitude= $params['lng'];
- $latitude= $params['lat'];
- $use_type = $secondary_card['use_type'];
- switch ($secondary_card['store_type']) {
- //o2o门店
- case 1:
- //预约模式:1:预约门店;2:预约服务人
- switch ($secondary_card['reservation_model']) {
- case 1:
- $offset = ($page - 1) * $limit;
- $sql = " SELECT id,store_name,shop_mobile,latitude,longitude,logo_img,sales_volume,praise,address,business_time_start,business_time_end,
- round(
- 2 * 6378.137 * ASIN(
- SQRT(
- POW(
- SIN(
- PI() * ({$longitude} - longitude) / 360
- ),
- 2
- ) + COS(PI() * {$latitude} / 180) * COS(latitude * PI() / 180) * POW(
- SIN(
- PI() * ({$latitude} - latitude) / 360
- ),
- 2
- )
- )
- )
- ,1) AS distance
- FROM `qimall_addons_store` WHERE (`mall_id`={$mall_id})";
- if (!empty($use_type)) {
- if (!empty($store_id_arr)) {
- $o2o_store_ids = join(',', $store_id_arr);
- } else {
- $o2o_store_ids = 0;
- }
- $sql .= " AND (`id` in ({$o2o_store_ids})) ";
- }
- if(!empty($params['store_cate_id'])){
- $sql .= " AND `c_id` = ".$params['store_cate_id'];
- }
- if(!empty($params['name'])){
- $sql .= " AND `store_name` like '%".$params['name']."%' ";
- }
- $count_sql = $sql;
- $total_data = \Yii::$app->db->createCommand($count_sql)->queryAll();
- $count = count($total_data);
- $orderBy = 'distance asc,id desc '; //1-距离
- if (isset($params['sort']) && $params['sort'] > 1){
- //1-距离,2-订单量 order_num ,3-好评 service_rating
- if($params['sort'] == 1){
- $orderBy = 'distance asc'; //1-距离
- }else{
- $orderBy = $params['sort'] == 2 ? 'sales_volume desc' : 'praise desc ';
- }
- }
- $sql .= " ORDER BY {$orderBy} limit {$limit} offset {$offset} ";
- $list = \Yii::$app->db->createCommand($sql)->queryAll();
- $list_page['list'] = $list;
- $list_page['page'] = $page;
- $list_page['page_size'] = $limit;
- $list_page['count'] = $count;
- $list_page['page_count'] = ceil($count / $limit);
- return $list_page;
- case 2:
- break;
- }
- break;
- }
- $basic = \Yii::$app->services->setting->addons->get($mall_id, ReservationServiceEnum::ADDONS_NAME, 'basic') ?? [];
- $max_distance = $basic['max_distance'] ?? 20; //限制
- $is_working = $params['is_working'] ?? 1;
- $working_field = empty($params['store_id']) ? 'is_working' : 'store_status';
- $where[] = ['mall_id' => $params['mall_id'],'is_working'=> 1,'status' => StatusEnum::ENABLED,'check_status'=>StatusEnum::ENABLED ];
- $min_age = $params['min_age'] ?? 0;
- $max_age = $params['max_age'] ?? 0;
- $gender = $params['gender'] ?? 0;
- $name = $params['name'] ?? '';
- $service_min = $secondary_card['appointment_interval_duration'] ?? 30;
- $user_ids = [];
- $longitude = 'longitude';
- $latitude = 'latitude';
- $s_longitude = 'longitude';
- $s_latitude = 'latitude';
- if (!empty($params['store_id']) || $secondary_card['use_type'] == SecondaryCardEnum::USE_TYPE_ALL) {
- $date = $params['date'] . ' ' . $params['time'] . ':00';
- $start_time = strtotime($date);
- $end_time = $start_time + $service_min * 60;
- // 取出门店下面的技师
- $where = ['mall_id' => $params['mall_id'],'status'=>StatusEnum::ENABLED];
- $where['store_id'] = $params['store_id'];
- $where['secondary_card_id'] = $params['secondary_card_id'];
- $user_ids = ReservationServiceStoreSecondaryCard::find()->where($where)->select('user_id')->column();
- if (empty($user_ids)) {
- throw new \Exception("当前门店暂无技师");
- }
- $longitude = 'store_lng';
- $latitude = 'store_lat';
- $s_longitude = 'store_lng as longitude';
- $s_latitude = 'store_lat as latitude';
- $new_user_ids = self::getNewUserIds($user_ids, $params['date'], $start_time, $end_time);
- $reserve_user_ids = self::getReserveUserIds($mall_id, $params['store_id'], $date);
- $occupy_user_ids = self::getOccupyUserIds($mall_id, $params['store_id'], $start_time, $end_time);
- $user_ids = array_diff($new_user_ids, $reserve_user_ids, $occupy_user_ids);
- }
- if (empty($user_ids)) {
- throw new \Exception('无可预约技师');
- }
- $sql = "SELECT id,mall_id,user_id,`level`, {$s_longitude}, {$s_latitude},`name`,service_rating,order_num,gender,age,`desc`,avatar,store_id, address,
- round(
- 2 * 6378.137 * ASIN(
- SQRT(
- POW(
- SIN(
- PI() * ({$params['lng']} - {$longitude}) / 360
- ),
- 2
- ) + COS(PI() * {$params['lat']} / 180) * COS({$latitude} * PI() / 180) * POW(
- SIN(
- PI() * ({$params['lat']} - {$latitude}) / 360
- ),
- 2
- )
- )
- )
- ,1) AS distance
- FROM `qimall_addons_reservation_service_user` WHERE (`mall_id`={$mall_id}) AND (`status`=1) AND (`check_status`= 1) AND (`{$working_field}` ={$is_working}) HAVING (`distance`<={$max_distance})";
- if ($gender > 0){
- $gender = $gender > 1 ? 2: 1;
- $sql .= " AND `gender` = " . $gender;
- }
- if ($min_age > 0 || $max_age > 0){
- $sql .= " AND `age` >= " . $min_age;
- $sql .= " AND `age` <= " . $max_age;
- }
- if($name){
- $name = trim($name);
- $sql .= " AND `name` LIKE '%" . $name . "%'";
- }
- $sql .= " AND `user_id` in (" . implode(',', $user_ids) . ")";
- if (!empty($params['store_id'])) {
- $sql .= " AND `store_id` = " . $params['store_id'];
- }
- $count_sql = $sql;
- $orderBy = 'distance asc,id desc'; //1-距离
- if (isset($params['sort']) && $params['sort'] > 1){
- //1-距离,2-订单量 order_num ,3-好评 service_rating
- if($params['sort'] == 1){
- $orderBy = 'distance asc'; //1-距离
- }else{
- $orderBy = $params['sort'] == 2 ? 'order_num desc' : 'service_rating desc';
- }
- }
- $total_data = \Yii::$app->db->createCommand($count_sql)->queryAll();
- $count = count($total_data);
- $sql .= " ORDER BY {$orderBy}";
- $sql .= " limit " . ($page - 1) * $limit . ",{$limit}";
- $list = \Yii::$app->db->createCommand($sql)->queryAll();
- $default_jishi = [];
- if (!empty($list)) {
- $location_obj = new LocationHelper();
- $store_ids = array_column($list,'store_id');
- $store_ids = array_unique($store_ids);
- $store_list = Store::find()->where(['id' => $store_ids,'mall_id' => $mall_id])->select('id,store_name')->indexBy('id')->asArray()->all();
- $comments = OrderReserveComments::lists([
- 'where' => [
- ['tech_user_id' => array_column($list, 'user_id')],
- ['reserve_type' => StatusEnum::ENABLED]
- ],
- 'select'=> 'COUNT(*) as total, tech_user_id',
- 'group' => 'tech_user_id',
- 'index' => 'tech_user_id'
- ]);
- foreach ($list as &$item) {
- $item['store_name'] = $store_list[$item['store_id']]['store_name'] ?? '平台自营';
- $distance = $location_obj->getDistanceByGeo($item['latitude'], $item['longitude'],$params['lat'] , $params['lng']);
- $item['distance'] = LocationHelper::formatDistance($distance); //米
- $item['comment_num'] = $comments[$item['user_id']]['total'] ?? 0;
- $item['commentNum'] = $comments[$item['user_id']]['total'] ?? 0;
- $item['serviceNum'] = $item['order_num'];
- $item['detail'] = $item['desc'];
- }
- }
- $list_page['list'] = $list;
- $list_page['page'] = $page;
- $list_page['page_size'] = $limit;
- $list_page['count'] = $count;
- $list_page['page_count'] = ceil($count / $limit);
- $list_page['default_jishi'] = $default_jishi;
- return $list_page;
- }catch(\Exception $e){
- $list_page['list'] = [];
- $list_page['page'] = 0;
- $list_page['page_size'] = 10;
- $list_page['count'] = 0;
- $list_page['page_count'] = 0;
- $list_page['error_msg'] = $e->getMessage();
- return $list_page;
- }
- }
- /**
- * 获取在排班时间内的技师user_id
- * @param $user_ids
- * @param $date
- * @param $start_time
- * @param $end_time
- * @return array
- */
- protected static function getNewUserIds($user_ids, $date, $start_time, $end_time)
- {
- $day_start_time = strtotime($date . ' 00:00:00');
- $new_user_ids = [];
- $user_ids_all = StoreReserveTechnicianScheduling::find()->where(['user_id' => $user_ids, 'is_all_day' => 1, 'date_time' => $day_start_time, 'status' => StatusEnum::ENABLED])
- ->select('user_id')->column();
- $new_user_ids = array_merge($new_user_ids, $user_ids_all);
- $scheduling_list = StoreReserveTechnicianScheduling::find()->where(['user_id' => $user_ids, 'is_all_day' => 0, 'date_time' => $day_start_time, 'status' => StatusEnum::ENABLED])
- ->with(['schedulingTime'])->all();
- foreach ($scheduling_list as $val) {
- foreach ($val['schedulingTime'] as $v) {
- if (($v['start_time'] <= $start_time && $start_time <= $v['end_time']) && ($v['start_time'] <= $end_time)) {
- $new_user_ids[] = $val['user_id'];
- break;
- }
- }
- }
- return $new_user_ids;
- }
- /**
- * 获取已预约的技师user_id
- * @param $mall_id
- * @param $store_id
- * @param $date
- * @return array
- */
- protected static function getReserveUserIds($mall_id, $store_id, $date)
- {
- $store_order_reserve_list = StoreOrderReserve::find()->where(['store_id' => $store_id, 'mall_id' => $mall_id])
- ->andWhere(['!=', 'order_status', -4])
- ->andWhere(['>=', 'service_start_at', time()])
- ->all();
- $tech_id_ids = [];
- $date_time = strtotime($date);
- foreach ($store_order_reserve_list as $value) {
- if ($value['service_start_at'] <= $date_time && $value['service_end_at'] > $date_time) {
- $tech_id_ids[] = $value['tech_id'];
- }
- }
- $reserve_user_ids = ReservationServiceUser::find()->where(['id' => $tech_id_ids])->select('user_id')->column();//已被预约的技师id
- return $reserve_user_ids;
- }
- /**
- * 获取已占用的技师user_id
- * @param $mall_id
- * @param $store_id
- * @param $start_time
- * @param $end_time
- * @return array
- */
- protected static function getOccupyUserIds($mall_id, $store_id, $start_time, $end_time)
- {
- $occupy_list = ReservationServiceOccupy::lists([
- 'where' => [
- ['mall_id' => $mall_id],
- ['store_id' => $store_id],
- ['status' => StatusEnum::ENABLED],
- ]
- ]
- );//已占用时间
- $occupy_user_ids = [];
- foreach ($occupy_list as $val) {
- if ($start_time >= $val['start_at'] && $start_time <= $val['end_at'] && $end_time <= $val['end_at']) {
- $occupy_user_ids[] = $val['staff_user_id'];
- }
- }
- return $occupy_user_ids;
- }
- /**
- * 检测用户时间段内是否可约
- * @param $mall_id
- * @param $user_ids
- * @param $start_time
- * @param $end_time
- * @return array
- */
- public static function checkCanBook($mall_id,$user_ids,$start_time,$end_time)
- {
- $book_user_ids = ReservationServiceUserBookTime::find()->where(['mall_id' => $mall_id,'user_id' => $user_ids,'status'=>StatusEnum::ENABLED])
- ->andWhere(['or',['and',['>','start_time',$start_time],['<','start_time',$end_time]],['and',['>','end_time',$start_time],['<','end_time',$end_time]]])
- ->select('user_id')
- ->column();
- if($book_user_ids){
- $user_ids = array_diff($user_ids,$book_user_ids);
- }
- return $user_ids;
- }
- /**
- * 检测技师是否可预约
- * @param $mall_id
- * @param $tech_id
- * @param string $select_time 预约日期时间
- * @param $goods_id
- * @param $sku_id
- * @param $lat
- * @param $lng
- * @param int $store_id
- * @return bool
- */
- public static function checkCanOrder($mall_id,$tech_id,$select_time,$goods_id,$sku_id,$lat,$lng,$store_id = 0, $addon = '')
- {
- try{
- $user_service = new UserService();
- $tech = $user_service->fetchById($mall_id,$tech_id);
- if(!is_array($tech)) throw new \Exception($tech);
- if(!$tech['is_working']) throw new \Exception('当前技师尚未开启接单');
- $basic = \Yii::$app->services->setting->addons->get($mall_id, ReservationServiceEnum::ADDONS_NAME, 'basic') ?? [];
- $max_distance = $basic['max_distance'] ?? 20; //限制
- $location_obj = new LocationHelper();
- $distance = $location_obj->getDistanceByGeo($tech['latitude'], $tech['longitude'],$lat , $lng);
- if($distance > bcmul($max_distance, 1000, 2)) throw new \Exception('超出技师接单范围,请重新选择');
- //时间判断
- $select_timestamp = strtotime($select_time);
- if (!empty($store_id)) {
- switch ($addon) {
- case AddonsEnum::ADDONS_NAME_LAO_DA_FU:
- $support = \addons\LaoDaFu\common\models\StoreGoods::find()->where(['mall_id' => $mall_id])
- ->andWhere(['id' => $goods_id])
- ->andWhere(['status' => StatusEnum::ENABLED])
- ->andWhere(['goods_type' => GoodsTypeEnum::GoodsTypeReserved])->asArray()->one();
- if(!$support) throw new \Exception('当前技师不支持该项目');
- $sku = \addons\LaoDaFu\common\models\StoreGoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- break;
- default:
- $support = StoreGoods::find()->where(['mall_id' => $mall_id])
- ->andWhere(['id' => $goods_id])
- ->andWhere(['status' => StatusEnum::ENABLED])
- ->andWhere(['store_id' => $store_id])
- ->andWhere(['goods_type' => GoodsTypeEnum::GoodsTypeReserved])->asArray()->one();
- if(!$support) throw new \Exception('当前技师不支持该项目');
- $sku = StoreGoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- $service_min = $sku['service_min'] ?? 0; //服务分钟
- $select_timestamp_end = $select_timestamp + 60 * $service_min;
- $reserve_date_time = $select_time . ',' . date('Y-m-d H:i', $select_timestamp_end);
- $res = StoreOrderReserve::find()->where(['tech_id' => $tech['id'], 'reserve_date_time' => $reserve_date_time])
- ->andWhere(['!=', 'order_status', -4])
- ->one();
- if ($res) throw new \Exception('该时间段已有预定');
- }
- } else {
- $support =ReservationServiceGoods::find()->where(['mall_id' => $mall_id,'goods_id' => $goods_id,
- 'status'=>StatusEnum::ENABLED,'user_id' => $tech['user_id']])->asArray()->one();
- if(!$support) throw new \Exception('当前技师不支持该项目');
- $sku = GoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- $service_min = $sku['service_min'] ?? 0; //服务分钟
- $select_timestamp_end = $select_timestamp + 60 * $service_min;
- $has_book = ReservationServiceUserBookTime::find()->where(['mall_id' => $mall_id, 'user_id' => $tech['user_id'], 'status' => StatusEnum::ENABLED])
- ->andWhere(['or', ['and', ['>', 'start_time', $select_timestamp], ['<', 'start_time', $select_timestamp_end]], ['and', ['>', 'end_time', $select_timestamp], ['<', 'end_time', $select_timestamp_end]]])
- ->all();
- if ($has_book) throw new \Exception('该时间段已有预定');
- }
- return true;
- }catch(\Exception $e){
- self::$static_error = $e->getMessage();
- return false;
- }
- }
- /**
- * 获取技师可预约时间
- * @param array $tech
- * @return array|string
- */
- public static function getTechLatelyCanReserveAt(array $tech)
- {
- $work_times = ReservationServiceWorkTime::lists([
- 'where' => [
- ['user_id' => $tech['user_id']],
- ['status' => StatusEnum::ENABLED]
- ],
- 'select'=> 'week_day, text',
- 'order' => 'week_day'
- ]);
- $times = [];
- for ($i = 0; $i < 1; $i++) {
- $day_time = time() + (86400 * $i);
- $week = date('w', $day_time);
- if (!empty($work_times[$week])) {
- $ts = explode("-", $work_times[$week]['text']);
- $day = date('Y-m-d', $day_time);
- $t_s = strtotime("{$day} {$ts[0]}:00");
- $t_e = strtotime("{$day} {$ts[1]}:00");
- // 这个时间段是否可约
- $select_timestamp = $t_s;
- $select_timestamp_end = $t_e;
- $has_book = ReservationServiceUserBookTime::find()->where(['user_id' => $tech['user_id'],'status'=>StatusEnum::ENABLED])
- ->andWhere(['or',['and',['>','start_time',$select_timestamp],['<','start_time',$select_timestamp_end]],['and',['>','end_time',$select_timestamp],['<','end_time',$select_timestamp_end]]])
- ->all();
- if(empty($has_book)) {
- return DateHelper::dayChineseText(strtotime($day));
- }
- }
- }
- return null;
- }
- public static function checkDate($params,$page=1,$limit=1)
- {
- try{
- if(!$params['lat'] || !$params['lng']){
- throw new \Exception('经纬度缺失');
- }
- $mall_id = $params['mall_id'];
- $basic = \Yii::$app->services->setting->addons->get($mall_id, ReservationServiceEnum::ADDONS_NAME, 'basic') ?? [];
- $max_distance = $basic['max_distance'] ?? 20; //限制
- $is_working = $params['is_working'] ?? 1;
- $working_field = empty($params['store_id']) ? 'is_working' : 'store_status';
- $goods_id = $params['goods_id'] ?? 0;
- $sku_id = $params['sku_id'] ?? 0;
- $user_ids = [];
- $longitude = 'longitude';
- $latitude = 'latitude';
- $s_longitude = 'longitude';
- $s_latitude = 'latitude';
- if($goods_id && $sku_id){
- if (!empty($params['store_id'])) {
- // 取出门店下面的技师
- $user_ids = ReservationServiceUser::find()->where(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id'],'status'=>StatusEnum::ENABLED])->select('user_id')->column();
- if (empty($user_ids)) throw new \Exception("当前门店暂无技师");
- $sku = StoreGoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- $longitude = 'store_lng';
- $latitude = 'store_lat';
- $s_longitude = 'store_lng as longitude';
- $s_latitude = 'store_lat as latitude';
- } else {
- $support_user_list = ReservationServiceGoods::find()->where(['mall_id' => $params['mall_id'],'goods_id' => $goods_id,'status'=>StatusEnum::ENABLED])->select('user_id')->asArray()->all();
- $user_ids = array_column($support_user_list,'user_id');
- $user_ids = array_unique($user_ids);
- if(!$user_ids) throw new \Exception('没有技师支持该项目');
- $sku = GoodsReserveSku::findOne(['id' => $sku_id,'goods_id' => $goods_id]);
- }
- $select_date = $params['date'] ?? date('Y-m-d');
- $start_time = strtotime($select_date.' 00:00:00');
- $end_time = strtotime($select_date.' 23:59:59');
- $select_week_day = date('w',strtotime($select_date));
- $user_times = ReservationServiceWorkTime::find()->where(['mall_id' => $mall_id,'user_id' => $user_ids,'status'=>StatusEnum::ENABLED])
- ->andWhere(['week_day' => $select_week_day])
- ->andWhere(['<=','start_time',$start_time])
- ->andWhere(['>=','end_time',$end_time])
- ->select('user_id')
- ->asArray()->all();
- if(!$user_times) throw new \Exception('暂无预约');
- $user_ids = array_column($user_times,'user_id');
- //排除当前有项目的技师
- $user_ids = self::checkCanBook($mall_id,$user_ids,$start_time,$end_time);
- if(!$user_ids) throw new \Exception('暂无预约');
- }
- $sql = "SELECT id,mall_id,user_id,`level`, {$s_longitude}, {$s_latitude},`name`,service_rating,order_num,gender,age,`desc`,avatar,store_id, address,
- round(
- 2 * 6378.137 * ASIN(
- SQRT(
- POW(
- SIN(
- PI() * ({$params['lng']} - {$longitude}) / 360
- ),
- 2
- ) + COS(PI() * {$params['lat']} / 180) * COS({$latitude} * PI() / 180) * POW(
- SIN(
- PI() * ({$params['lat']} - {$latitude}) / 360
- ),
- 2
- )
- )
- )
- ,1) AS distance
- FROM `qimall_addons_reservation_service_user` WHERE (`mall_id`={$mall_id}) AND (`status`=1) AND (`is_working`=1) AND (`check_status`= 1) AND (`{$working_field}` ={$is_working}) HAVING (`distance`<={$max_distance})";
- if($user_ids){
- $sql .= " AND `user_id` in (" . implode(',',$user_ids) . ")";
- }
- $sql .= " limit " . ($page - 1) * $limit . ",{$limit}";
- $list = \Yii::$app->db->createCommand($sql)->queryAll();
- if(empty($list)) throw new \Exception('暂无预约');
- return true;
- }catch(\Exception $e){
- throw new \Exception($e->getMessage());
- }
- }
- /**
- * 获取技师某日的时间段
- * @param $params
- * @return array
- * @throws \Exception
- */
- public static function getTimes($params)
- {
- if(empty($params['tech_user_id'])){
- $res = self::search($params,$params['page'],$params['limit']);
- $user_ids = [];
- if(!empty($res['list'])){
- $user_ids = array_column($res['list'],'user_id');
- }
- }else{
- $user_ids = $params['tech_user_id'];
- }
- $time = time();
- if (empty($params['store_id'])) {
- $buff = self::platformStaffTimeList($params,$user_ids,$time);
- }else{
- $buff = self::storeStaffTimeList($params,$user_ids,$time);
- }
- return $buff;
- }
- /**
- * 获取平台技师某天的工作时间段
- * @param $params
- * @param $user_ids
- * @param $time
- * @return array
- * @throws \Exception
- */
- protected static function platformStaffTimeList($params,$user_ids,$time)
- {
- $buff = [];
- $goods_reserve = GoodsReserve::findOne(['goods_id' => $params['goods_id'], 'reserve_type' => GoodsReserve::RESERVE_TYPE_SERVICE]);
- if (!$goods_reserve) {
- throw new \Exception('项目不存在');
- }
- $sku = GoodsReserveSku::findOne(['id' => $params['sku_id'], 'goods_id' => $params['goods_id']]);
- if (!$sku) {
- throw new \Exception('项目不存在');
- }
- $work_time_list = ReservationServiceWorkTime::lists([
- 'where'=>[
- ['user_id'=>$user_ids],
- ['week_day'=> date('w',strtotime($params['date'].' 00:00:00'))],
- ['mall_id'=>$params['mall_id']], ['status'=>StatusEnum::ENABLED]
- ]
- ]);
- if(!empty($params['tech_user_id'])) {
- $list = ReservationServiceOrder::lists([
- 'where' => [
- ['mall_id' => $goods_reserve['mall_id']],
- ['staff_user_id' => $user_ids],
- ['store_id' => 0],
- ['>=','service_start_at',strtotime($params['date'].' 00:00:00')],
- ['<=','service_end_at',strtotime($params['date'].' 23:59:59')],
- ['!=','service_status',ReservationServiceEnum::RESERVE_ORDER_STATUS_CANCEL]
- ]
- ]);
- $scheduled_time_arr = [];//已预约时间
- foreach ($list as $value){
- $scheduled_time_arr[date("H:i",$value['service_start_at'])] = 1;
- }
- }
- $service_min = $sku['service_min'] ?: 10; //服务分钟
- $time1 = date('Y-m-d 00:00:00');
- $time2 = date('Y-m-d 23:59:59');
- for($i=strtotime($time1) ;$i<=strtotime($time2) ; $i=$i+60*$service_min){
- $is_true = 0;
- $temp_time = $i;
- foreach ($work_time_list as $item){
- $time_arr = explode('-',$item['text']);
- $start_time = strtotime($params['date'].' '.$time_arr[0].':00');
- $end_time = strtotime($params['date'].' '.$time_arr[1].':00');
- if($temp_time>=$start_time && $temp_time<=$end_time){
- $is_true = 1;
- break;
- }
- }
- if($is_true==1 && $i>$time){
- $buff_time = date("H:i",$i);
- $is_reserve = 1;
- if(!empty($params['tech_user_id']) && isset($scheduled_time_arr[$buff_time])) {
- $is_reserve = 0;
- }
- $buff[]=['time'=>$buff_time,'is_reserve'=>$is_reserve];
- }
- }
- return $buff;
- }
- /**
- * 获取门店技师某天的工作时间段
- * @param $params
- * @param $user_ids
- * @param $time
- * @return array
- * @throws \Exception
- */
- protected static function storeStaffTimeList($params,$user_ids,$time)
- {
- $buff = [];
- $goods_reserve = StoreGoodsReserve::findOne(['goods_id' => $params['goods_id'], 'reserve_type' => GoodsReserve::RESERVE_TYPE_SERVICE]);
- if (!$goods_reserve) {
- throw new \Exception('项目不存在1');
- }
- $sku = StoreGoodsReserveSku::findOne(['id' => $params['sku_id'], 'goods_id' => $params['goods_id']]);
- if (!$sku) {
- throw new \Exception('项目不存在');
- }
- if(!empty($params['tech_user_id'])) {
- $reservation_service_order_list = ReservationServiceOrder::lists([
- 'where' => [
- ['mall_id' => $goods_reserve['mall_id']],
- ['staff_user_id' => $user_ids],
- ['store_id' => $params['store_id']],
- ['>=','service_start_at',strtotime($params['date'].' 00:00:00')],
- ['<=','service_end_at',strtotime($params['date'].' 23:59:59')],
- ['!=','server_status',ReservationServiceEnum::CANCELED]
- ]
- ]);
- }
- $scheduling_list = StoreReserveTechnicianScheduling::lists([
- 'where'=>[
- ['store_id'=>$goods_reserve['store_id']], ['user_id'=>$user_ids],
- ['date_time'=>strtotime($params['date'].' 00:00:00')]
- ],
- 'with'=>'schedulingTime'
- ]);
- $occupy_list = ReservationServiceOccupy::lists([
- 'where' => [
- ['mall_id' => $goods_reserve['mall_id']],
- ['store_id' => $params['store_id']],
- ['staff_user_id' => $user_ids],
- ['status'=>StatusEnum::ENABLED]
- ]
- ]
- );//已占用时间
- $service_min = $sku['service_min'] ?: 10; //服务分钟
- $store = Store::findOne(['id'=>$goods_reserve['store_id']]);
- $business_time_start = $store['business_time_start'];
- $business_time_end = $store['business_time_end'];
- $time1 = strtotime($params['date'].' '.$business_time_start.':00');
- $time2 =strtotime($params['date'].' '.$business_time_end.':00');
- for($i=$time1 ;$i<=$time2 ; $i=$i+60*$service_min){
- $is_true = 0;
- $temp_time = $i;
- foreach ($scheduling_list as $item){
- //全天
- if($item['is_all_day']){
- $is_true = 1;
- break;
- }else{
- //设置的时间段
- foreach ($item['schedulingTime'] as $val){
- if($temp_time>=$val['start_time'] && $temp_time<=$val['end_time']){
- $is_true = 1;
- break;
- }
- }
- }
- }
- if($is_true==1 && $i>$time){
- $buff_time = date("H:i",$i);
- $is_reserve = 1;
- if(!empty($params['tech_user_id'])) {
- //判断该时间段是否被人预约
- foreach ($reservation_service_order_list as $service_order) {
- if ($service_order['service_start_at'] <= $temp_time && $service_order['service_end_at'] >= $temp_time) {
- $is_reserve = 0;
- }
- }
- if ($is_reserve == 1) {
- //判断该时间段是否被占用
- foreach ($occupy_list as $occupy) {
- if ($occupy['start_time'] <= $temp_time && $occupy['end_time'] >= $temp_time) {
- $is_reserve = 0;
- }
- }
- }
- }
- $buff[]=['time'=>$buff_time,'is_reserve'=>$is_reserve];
- }
- }
- return $buff;
- }
- public static function getDate($params)
- {
- $data = $params['data'];
- $range_end = $data['basic']['range_end']??1;
- $range_end_arr = ReservationServiceEnum::RANGE_END_ARR_MAP;
- $date_list = [];
- $time = time();
- $i=0;
- $days = $range_end_arr[$range_end]??7;
- while (true){
- if($i>=$days){
- break;
- }
- $temp_time = $time + $i*86400;
- $date = date('Y-m-d',$temp_time);
- $date_list[]=['date'=>$date,'is_reserve'=>1, 'week_day' => GoodsReserveTime::getWeekDay($date)];
- $i++;
- }
- if(!empty($params['start'])){
- $start_time = strtotime($params['start'].' 00:00:00');
- $i=0;
- $temp_date_list = array_column($date_list,null,'date');
- $date_list = [];
- while (true){
- if($i>=$days){
- break;
- }
- $temp_time = $start_time + $i*86400;
- $date = date('Y-m-d',$temp_time);
- $is_reserve = 0;
- if(isset($temp_date_list[$date])){
- $is_reserve = 1;
- }
- $date_list[]=['date'=>$date,'is_reserve'=>$is_reserve, 'week_day' => GoodsReserveTime::getWeekDay($date)];
- $i++;
- }
- }
- return $date_list;
- }
- /**
- * 获取某个技师可以预约日期
- * @param $params
- * @return array|void
- */
- public static function getReservationDate($params)
- {
- if(empty($params['store_id'])){
- $work_time = ReservationServiceWorkTime::lists([
- 'where'=>[
- ['user_id'=>$params['tech_user_id']],
- ['mall_id'=>$params['mall_id']],
- ['status'=>StatusEnum::ENABLED]
- ],
- 'index'=>'week_day'
- ]);
- $data = BackendService::getSetting($params['mall_id']);
- $range_end = $data['basic']['range_end']??1;
- $range_end_arr = ReservationServiceEnum::RANGE_END_ARR_MAP;
- $date_list = [];
- $start_time = time();
- $today_end_time = strtotime(date('Y-m-d 23:59:59'));
- $tomorrow_start_time = strtotime(date('Y-m-d 00:00:00',strtotime('+1 day')));
- $tomorrow_end_time = strtotime(date('Y-m-d 23:59:59',strtotime('+1 day')));
- $after_tomorrow_start_time = strtotime(date('Y-m-d 00:00:00',strtotime('+2 day')));
- $after_tomorrow_end_time = strtotime(date('Y-m-d 23:59:59',strtotime('+2 day')));
- $i=0;
- $week_date_map = ReservationServiceEnum::WEEK_DATE_MAP;
- while (true){
- $range_end_limit = $range_end_arr[$range_end];
- if($i>=$range_end_limit){
- break;
- }
- $time = $start_time + $i*86400;
- $week_day = date('w',$time);
- if(!isset($work_time[$week_day])){
- continue;
- }
- $date = date('m-d',$time);
- if($time<=$today_end_time){
- $text = '今天';
- }elseif($time>=$tomorrow_start_time && $time<=$tomorrow_end_time){
- $text = '明天';
- }elseif($time>=$after_tomorrow_start_time && $time<=$after_tomorrow_end_time){
- $text = '后天';
- }else{
- $text = $week_date_map[$week_day]??'';
- }
- $date_list[]=['date_day'=>[
- 'date'=>$date,'text'=>$text
- ]];
- $i++;
- }
- return $date_list;
- }
- }
- /**
- * 平台预约商品详情-服务时间列表
- * @param $params
- * @return array
- * @throws \Exception
- */
- public static function serviceTimeList($params)
- {
- $reservation_service_user = ReservationServiceUser::findOne(['user_id' => $params['id'], 'status' => StatusEnum::ENABLED]);
- if (empty($reservation_service_user)) {
- throw new \Exception('技师不存在');
- }
- $data = BackendService::getSetting($params['mall_id']);
- $params['data'] = $data;
- $list = self::getDate($params);
- $sku = GoodsReserveSku::findOne(['id' => $params['sku_id']]);
- if (!$sku) {
- throw new \Exception('项目不存在');
- }
- if (!empty($reservation_service_user['store_id'])) {
- $store = Store::findOne(['id' => $reservation_service_user['store_id']]);
- if (!empty($params['start'])) {
- $date = $params['start'];
- } else {
- $date = date('Y-m-d', time());
- }
- $times = strtotime($date);
- $business_time_start = strtotime($date . ' ' . $store['business_time_start'] . ':00');
- $business_time_end = strtotime($date . ' ' . $store['business_time_end'] . ':00');
- $scheduling = StoreReserveTechnicianScheduling::lists([
- 'where' => [
- ['user_id' => $reservation_service_user['user_id']],
- ['>=', 'date_time', $times]
- ],
- 'with' => ['schedulingTime'],
- 'index' => 'date_time'
- ]
- );//技师在门店的排班时间
- }
- $service_min = $sku['service_min'];
- $week_day_arr = [];
- $start_time = 0;
- $end_time = 0;
- $time = time();
- $today = date('Y-m-d',$time);
- foreach ($list as $k=>$item){
- $temp_time = strtotime($item['date'].' 00:00:00');
- if($k==0){
- $start_time =$temp_time;
- }
- $end_time =$temp_time;
- $week_day_arr[]=date('w',$temp_time);
- }
- $work_time_arr = ReservationServiceWorkTime::lists([
- 'where'=>[
- ['user_id'=>$params['id']],
- ['week_day'=> $week_day_arr],
- ['mall_id'=>$params['mall_id']], ['status'=>StatusEnum::ENABLED]
- ],
- ]);
- $work_time_list = [];
- foreach ($work_time_arr as $val) {
- $work_time_list[$val['week_day']][] = $val;
- }
- $order_list = OrderReserve::find()
- ->where(['tech_id' => $reservation_service_user['id'], 'mall_id' => $reservation_service_user['mall_id'],])
- ->andWhere(['!=', 'order_status', -4])
- ->andWhere(['>=', 'service_start_at', time()])
- ->asArray()->all();
- $range_start_time = self::getRangeStartTime($data['basic']['range_start'] ?? 0);
- $time += $range_start_time;
- foreach ($list as &$item) {
- $date_time = strtotime($item['date']);
- $temp_time = $date_time;
- $temp_week_day = date('w',$temp_time);
- $time_list = [];
- if (!empty($reservation_service_user['store_id'])) {
- $business_time_start = strtotime($item['date'] . ' ' . $store['business_time_start'] . ':00');
- $business_time_end = strtotime($item['date'] . ' ' . $store['business_time_end'] . ':00');
- }
- $day_is_reserve = 0;
- if (isset($work_time_list[$temp_week_day])) {
- foreach ($work_time_list[$temp_week_day] as $value) {
- $time_arr = explode('-', $value['text']);
- $work_start_time_temp = strtotime($item['date'] . ' ' . $time_arr[0] . ':00');
- $work_end_time_temp = strtotime($item['date'] . ' ' . $time_arr[1] . ':00');
- $work_start_time = strtotime($item['date'] . '00:00:00');
- $work_end_time = strtotime($item['date'] . '23:59:59');
- for ($i = $work_start_time; $i <= $work_end_time; $i = $i + 60 * $service_min) {
- if ($today == $item['date']) {
- if ($i < $time) {
- continue;
- }
- }
- if (!empty($reservation_service_user['store_id'])) {
- if (isset($scheduling) && isset($scheduling[$work_start_time])) {
- if (!empty($scheduling[$work_start_time]['is_all_day'])) {
- if ($i >= $business_time_start && $i <= $business_time_end) {
- $time_list[$i] = ['time' => date("H:i", $i), 'is_reserve' => 0];
- continue;
- }
- } else {
- $is_continue = false;
- if (isset($scheduling[$work_start_time]['schedulingTime'])) {
- foreach ($scheduling[$work_start_time]['schedulingTime'] as $val) {
- $te_start_time = $val['start_time'];
- $te_end_time = $val['end_time'];
- if ($te_start_time < $business_time_start) {
- $te_start_time = $business_time_start;
- }
- if ($te_end_time > $business_time_end) {
- $te_end_time = $business_time_end;
- }
- if ($i >= $te_start_time && $i <= $te_end_time) {
- $is_continue = true;
- }
- }
- }
- if ($is_continue) {
- $time_list[$i] = ['time' => date("H:i", $i), 'is_reserve' => 0];
- continue;
- }
- }
- }
- }
- if ($i < $work_start_time_temp || $i > $work_end_time_temp) {
- continue;
- }
- if ($item['date'] == $today) {
- if ($i < $time) {
- $time_list[$i] = ['time' => date("H:i", $i), 'is_reserve' => 0];
- continue;
- }
- }
- $buff_time = date("H:i", $i);
- $is_reserve = 1;
- if (!empty($order_list)) {
- foreach ($order_list as $v) {
- if ($i >= $v['service_start_at'] && $i < $v['service_end_at']) {
- $is_reserve = 0;
- break;
- }
- }
- }
- if ($is_reserve) {
- $day_is_reserve = 1;
- }
- $time_list[$i] = ['time' => $buff_time, 'is_reserve' => $is_reserve];
- }
- }
- }
- sort($time_list);
- $item['time_list'] = $time_list;
- $item['is_reserve'] = $day_is_reserve;
- }
- return $list;
- }
- /**
- * h5端-预约时间列表-到店分配/技师不选项
- * @param $params
- * @return array
- * @throws \Exception
- */
- public static function getReservationTimeList(int $mall_id, $params)
- {
- $config = BackendService::getSetting($mall_id);
- $range_start = $config['range_start'];
- $range_end = $config['range_end'];
- $store_goods_reserve_sku = GoodsReserveSku::getOne([
- ['id' => $params['sku_id']]
- ], true, ['reserve']);
- if (empty($store_goods_reserve_sku)) {
- throw new \Exception('商品不存在');
- }
- $service_min = self::getServiceMin(1, $store_goods_reserve_sku['service_min'] ?? 0);
- if (empty($service_min)) {
- throw new \Exception('该商品没有设置服务时长');
- }
- $date = $params['date'];
- $appointments_number = $store_goods_reserve_sku['reserve']['appointments_number'] ?? 0;
- if (!empty($appointments_number)) {
- $reservation_service_order_list = OrderReserve::lists([
- 'where' => [
- ['mall_id' => $mall_id],
- ['goods_id' => $store_goods_reserve_sku['goods_id']],
- ['>=', 'service_start_at', strtotime($date . ' 00:00:00')],
- ['<=', 'service_end_at', strtotime($date . ' 23:59:59')],
- ['!=', 'order_status', -4],
- ['create_type' => 1],
- ],
- 'group' => 'service_start_at',
- 'select' => 'count(*) as counts,service_start_at',
- 'index' => 'service_start_at'
- ]);
- }
- $business_time_start = "08:00";
- $business_time_end = "22:00";
- $start_time = self::getRangeStartTime($range_start);
- $time1 = "{$date} {$business_time_start}:00";
- $time2 = "{$date} {$business_time_end}:59";
- $buff = [];
- $time = time();
- $start = strtotime($time1);
- $end = strtotime($time2);
- //切割时间
- for ($i = $start; $i <= $end; $i = $i + 60 * $service_min) {
- $is_reserve = 1;
- $hour_minute = date("H:i", $i);
- $buff[] = ['time' => $hour_minute, 'is_reserve' => $is_reserve];
- }
- $range_end_arr = ReservationServiceEnum::RANGE_END_ARR_MAP;
- $days = $range_end_arr[$range_end] ?? 7;
- $date_list = [];
- $today_time = strtotime(date('Y-m-d', $time) . ' 00:00:00');
- if (!empty($params['date'])) {
- $time = strtotime($params['date'] . ' 00:00:00');
- } else {
- $time = $today_time;
- }
- $end_time = $time + $days * 24 * 3600;
- for ($i = $time; $i < $end_time; $i += 24 * 60 * 60) {
- $is_reserve = 1;
- $time_list = $buff;
- $date = date('Y-m-d', $i);
- $new_time_list = [];
- foreach ($time_list as &$item) {
- $temp_time_start = strtotime("{$date} " . $item['time'] . ":00");
- if (!empty($appointments_number)) {
- if (isset($reservation_service_order_list[$temp_time_start]) && $reservation_service_order_list[$temp_time_start]['counts'] >= $appointments_number) {
- $item['is_reserve'] = 0;
- }
- }
- $te_time = strtotime($date . ' ' . $item['time'] . ':00');
- if ($te_time < time()) {
- continue;
- }
- if ((time() + $start_time) > $te_time) {
- continue;
- }
- $new_time_list[] = $item;
- }
- unset($item);
- $arr = ['date' => $date, 'week_day' => GoodsReserveTime::getWeekDay($date), 'time_list' => $new_time_list, 'is_reserve' => $is_reserve];
- $date_list[] = $arr;
- }
- return $date_list;
- }
- public static function getServiceMin($appointment_interval, $min)
- {
- switch ($appointment_interval) {
- case 1:
- $service_min = $min;
- break;
- default:
- $service_min = $min ?? 30;
- }
- return $service_min;
- }
- }
|