OrderService.php 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023
  1. <?php
  2. namespace addons\ReservationService\common\services;
  3. use addons\ReservationService\common\enums\ReservationServiceEnum;
  4. use addons\ReservationService\common\logic\NoticeLogic;
  5. use addons\ReservationService\common\models\ReservationServiceGoodsSetting;
  6. use addons\ReservationService\common\models\ReservationServiceLevel;
  7. use addons\ReservationService\common\models\ReservationServiceOrder;
  8. use addons\ReservationService\common\models\ReservationServiceUser;
  9. use addons\ReservationService\common\models\ReservationServiceUserBookTime;
  10. use addons\SecondaryCard\common\models\SecondaryCard;
  11. use addons\SecondaryCard\common\models\SecondaryCardOrder;
  12. use addons\SecondaryCard\common\models\SecondaryCardUseLog;
  13. use addons\SecondaryCard\common\service\SecondaryCardOrderService;
  14. use addons\SecondaryCard\common\service\SecondaryCardService;
  15. use addons\Store\common\models\Store;
  16. use addons\Store\common\models\StoreClerk;
  17. use addons\Store\common\models\StoreGoods;
  18. use addons\Store\common\models\StoreGoodsReserve;
  19. use addons\Store\common\models\StoreGoodsReserveSku;
  20. use addons\Store\common\models\StoreOrder;
  21. use addons\Store\common\models\StoreOrderDetail;
  22. use addons\Store\common\models\StoreOrderMarketing;
  23. use addons\Store\common\models\StoreOrderReserve;
  24. use addons\Store\common\models\StoreReserveTechnicianScheduling;
  25. use addons\Store\common\services\StoreReserveSettingService;
  26. use common\enums\AddonsEnum;
  27. use common\enums\ClerkEnum;
  28. use common\enums\MarketingTypeEnum;
  29. use common\enums\OrderSourceEnum;
  30. use common\enums\OrderStatusEnum;
  31. use common\enums\PayTypeEnum;
  32. use common\enums\RabbitMqEnum;
  33. use common\enums\RefundStatusEnum;
  34. use common\enums\RefundTypeEnum;
  35. use common\enums\ShippingTypeEnum;
  36. use common\enums\StatusEnum;
  37. use common\enums\UserWalletEnum;
  38. use common\globals\GlobalInvoke;
  39. use common\helpers\FormatHelper;
  40. use common\helpers\LocationHelper;
  41. use common\logic\order\OrderRefundLogic;
  42. use common\models\common\ClerkLog;
  43. use common\models\common\Region;
  44. use common\models\goods\Goods;
  45. use common\models\goods\GoodsReserve;
  46. use common\models\goods\GoodsReserveSku;
  47. use common\models\mall\Mall;
  48. use common\models\mall\MallAddons;
  49. use common\models\order\Order;
  50. use common\models\order\OrderDetail;
  51. use common\models\order\OrderExpress;
  52. use common\models\order\OrderMarketing;
  53. use common\models\order\OrderRefund;
  54. use common\models\order\OrderReserve;
  55. use common\models\user\User;
  56. use services\common\UserWalletService;
  57. use Yii;
  58. use yii\helpers\Json;
  59. class OrderService
  60. {
  61. public function page(int $mall_id, array $params)
  62. {
  63. $where = [
  64. ['mall_id' => $mall_id],
  65. ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]],
  66. ];
  67. if(!empty($params['from'])){
  68. switch ($params['from']){
  69. case 'platform':
  70. $where[] = [
  71. 'or',
  72. ['>','goods_id',0],
  73. ['reservation_model'=>2]
  74. ];
  75. break;
  76. case 'store':
  77. $where[] = [
  78. 'or',
  79. ['>','goods_id',0],
  80. [
  81. 'and',
  82. ['>', 'secondary_card_id', 0],
  83. ['reservation_model' => 2]
  84. ],
  85. ];
  86. break;
  87. }
  88. }
  89. if (!empty($params['staff_user_id'])) {
  90. $where[] = ['staff_user_id' => $params['staff_user_id']];
  91. } else if (!empty($params['user_id'])) {
  92. $where[] = ['user_id' => $params['user_id']];
  93. } else if (!empty($params['keyword'])) {
  94. $uids = User::find()->where(['mall_id' => $mall_id])
  95. ->andWhere(['status' => StatusEnum::ENABLED])
  96. ->andWhere(['or', ['like', 'id', $params['keyword']], ['like', 'nickname', $params['keyword']], ['like', 'mobile', $params['keyword']]])
  97. ->select('id')
  98. ->column();
  99. if (empty($uids)) return [];
  100. $where[] = ['user_id' => $uids];
  101. }
  102. if (isset($params['service_status']) && $params['service_status'] !== '' && $params['service_status'] != 999) {
  103. $where[] = ['service_status' => $params['service_status']];
  104. }
  105. if (!empty($params['server_status'])) {
  106. $where[] = ['server_status' => $params['server_status']];
  107. }
  108. if (!empty($params['order_no'])) {
  109. $where[] = ['like', 'order_no', $params['order_no']];
  110. }
  111. if (!empty($params['service_type'])) {
  112. $where[] = ['service_type' => $params['service_type']];
  113. }
  114. if (!empty($params['create_type'])) {
  115. $where[] = ['create_type' => $params['create_type']];
  116. }
  117. switch ($params['time_type']){
  118. case 1:
  119. if (!empty($params['date_start'])) $where[] = ['>=', 'created_at', strtotime($params['date_start'])];
  120. if (!empty($params['date_end'])) $where[] = ['<=', 'created_at', strtotime($params['date_end'])];
  121. break;
  122. case 2:
  123. if (!empty($params['date_start'])) $where[] = ['>=', 'service_start_at', strtotime($params['date_start'])];
  124. if (!empty($params['date_end'])) $where[] = ['<=', 'service_start_at', strtotime($params['date_end'])];
  125. break;
  126. case 3:
  127. if (!empty($params['date_start'])) $where[] = ['>=', 'service_end_at', strtotime($params['date_start'])];
  128. if (!empty($params['date_end'])) $where[] = ['<=', 'service_end_at', strtotime($params['date_end'])];
  129. break;
  130. default:
  131. if (!empty($params['date_start'])) $where[] = ['>=', 'service_start_at', strtotime($params['date_start'])];
  132. if (!empty($params['date_end'])) $where[] = ['<=', 'service_start_at', strtotime($params['date_end'])];
  133. }
  134. if (!empty($params['reservation_model'])) {
  135. $where[] = ['reservation_model'=> $params['reservation_model']];
  136. }
  137. if (!empty($params['order_no'])) {
  138. $where[] = ['like', 'order_no', trim($params['order_no'])];
  139. }
  140. if (!empty($params['date_c_start'])) $where[] = ['>=', 'created_at', strtotime($params['date_c_start'])];
  141. if (!empty($params['date_c_end'])) $where[] = ['<=', 'created_at', strtotime($params['date_c_end'])];
  142. $with = [
  143. 'user',
  144. 'staff' => function ($q) {
  145. $q->where(['status' => StatusEnum::ENABLED]);
  146. },
  147. 'orderDetail',];
  148. // 门店
  149. if (!empty($params['store_id'])) {
  150. $where[] = ['store_id' => $params['store_id']];
  151. }
  152. $ret = ReservationServiceOrder::listPage([
  153. 'where' => $where,
  154. 'order' => 'id desc',
  155. 'limit' => $params['limit'] ?? 10,
  156. 'with' => $with
  157. ]);
  158. if (!empty(ReservationServiceOrder::getStaticError())) return ReservationServiceOrder::getStaticError();
  159. $ret['status_text_map'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP;
  160. $server_status_map = ReservationServiceEnum::SERVER_STATUS_MAP;
  161. if (!empty($ret['list'])) {
  162. $goods_ids = $store_goods_ids = [];
  163. foreach ($ret['list'] as &$item){
  164. if($item['store_id']){
  165. $store_goods_ids[]=$item['goods_id'];
  166. }else{
  167. $goods_ids[]=$item['goods_id'];
  168. }
  169. }
  170. $goods_list = Goods::lists(['where'=>[['id'=>$goods_ids]],'index'=>'id','select'=>'id,goods_name,cover_pic']);
  171. $store_goods_list = StoreGoods::lists(['where'=>[['id'=>$store_goods_ids]],'index'=>'id','select'=>'id,goods_name,cover_pic']);
  172. $mall_name = Yii::$app->services->setting->mall->get($mall_id, 'basic.name');
  173. $mall_logo = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo');
  174. $secondary_card_order_list = [];
  175. //次卡部分----start
  176. if (MallAddons::isInstall($mall_id, 'SecondaryCard')) {
  177. $secondary_card_no_arr = array_column($ret['list'],'secondary_card_no');
  178. $secondary_card_order_list = SecondaryCardOrder::lists([
  179. 'where'=> [
  180. ['order_no'=>$secondary_card_no_arr],
  181. ],
  182. 'with'=>['secondaryCard'],
  183. 'index'=>'order_no'
  184. ]);
  185. $reservation_service_order_ids = array_column($ret['list'],'id');
  186. $use_log_list = SecondaryCardUseLog::lists(['where'=>[['reservation_service_order_id'=>$reservation_service_order_ids]],'index'=>'reservation_service_order_id']);
  187. }
  188. foreach ($ret['list'] as &$item) {
  189. $item['status_text'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP[$item['service_status']];
  190. $item['server_status_text'] = $server_status_map[$item['server_status']]??'';
  191. $item['service_start_at_text'] = "";
  192. $item['duration'] = ($item['service_end_at'] - $item['service_start_at']) / 60;
  193. $item['be_late'] = "";
  194. if (!empty($item['service_start_at'])){
  195. $item['service_start_at_text'] = date('Y-m-d H:i', $item['service_start_at']);
  196. if($item['service_type']== 2){
  197. if($item['at_store_time']){
  198. //已到店
  199. $late_time = $item['at_store_time']-$item['service_start_at'];
  200. }else{
  201. $late_time = time() - $item['service_start_at'];
  202. }
  203. if($late_time>=60){
  204. $item['be_late'] = '迟到';
  205. $day = bcdiv($late_time,86400);
  206. if(!empty($day)){
  207. $item['be_late'].= $day.'天';
  208. }
  209. $hour = bcdiv($late_time-$day*86400,3600);
  210. if(!empty($hour)){
  211. $item['be_late'].= $hour.'时';
  212. }
  213. $minute = bcdiv($late_time-$day*86400-$hour*3600,60);
  214. if(!empty($day)){
  215. $item['be_late'].= $minute.'分钟';
  216. }
  217. }
  218. }
  219. }
  220. $item['mall_name'] = $mall_name;
  221. $item['mall_logo'] = $mall_logo;
  222. $item['create_type_text'] = ReservationServiceEnum::CREATE_TYPE_MAP[ $item['create_type']] ?? '未知';
  223. if($item['store_id']){
  224. $item['goods']=$store_goods_list[$item['goods_id']]??[];
  225. }else{
  226. $item['goods']=$goods_list[$item['goods_id']]??[];
  227. }
  228. if (!empty($item['store_id'])) {
  229. $store = Store::findOne(['id' => $item['store_id']]);
  230. $item['mall_name'] = $store->store_name;
  231. $item['mall_logo'] = $store->logo_img;
  232. $reserveOrder = StoreOrderReserve::findOne(['main_order_id' => $item['order_id']]);
  233. if(empty($item['service_type'])){
  234. $item['service_type'] = $reserveOrder->service_type;
  235. }else{
  236. $item['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[ $item['service_type']] ?? '未知服务';
  237. }
  238. } else {
  239. $reserveOrder = OrderReserve::findOne(['order_id' => $item['order_id']]);
  240. if(empty($item['service_type'])){
  241. $item['service_type'] = $reserveOrder->service_type;
  242. }else{
  243. $item['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[ $item['service_type']] ?? '未知服务';
  244. }
  245. }
  246. $item['reserveOrder'] = [];
  247. if(!empty($reserveOrder)){
  248. $item['reserveOrder'] = $reserveOrder->toArray();
  249. }
  250. //次卡部分----start
  251. $item['secondary_card'] = [];
  252. $item['is_secondary_card'] = 0;
  253. if(!empty($secondary_card_order_list)&&isset($secondary_card_order_list[$item['secondary_card_no']])){
  254. $item['is_secondary_card'] = 1;
  255. $secondary_card_order = $secondary_card_order_list[$item['secondary_card_no']];
  256. $item['secondary_card'] = [
  257. 'name'=>$secondary_card_order['secondaryCard']['name'],
  258. 'font_color'=>$secondary_card_order['secondaryCard']['font_color'],
  259. 'background'=>$secondary_card_order['secondaryCard']['background'],
  260. 'order_no'=>$secondary_card_order['order_no'],
  261. 'reservation_service_order_id'=>$secondary_card_order['id'],
  262. ];
  263. $item['secondary_card']['order_source'] = \addons\SecondaryCard\common\service\SecondaryCardOrderService::getSourceName($secondary_card_order,$secondary_card_order['secondaryCard']['use_type']);
  264. $item['secondary_card']['service_times'] = $use_log_list[$item['id']]['clerk_nums']??1;
  265. $item['secondary_card']['service_income'] = $use_log_list[$item['id']]['service_income']??0;
  266. $item['secondary_card']['clerk_money'] = $use_log_list[$item['id']]['clerk_money']??0;
  267. // $item['service_type_text'] = \addons\SecondaryCard\common\service\SecondaryCardService::getServiceTypeText($secondary_card_order['secondaryCard']);
  268. }
  269. //次卡部分----end
  270. }
  271. }
  272. $tabsIndex = [999, 0, 1, 90, 100];
  273. if (!empty($params['staff_user_id'])) {
  274. foreach ($tabsIndex as $index) {
  275. $badgeQuery = ReservationServiceOrder::find()
  276. ->where(['mall_id' => $mall_id, 'staff_user_id' => $params['staff_user_id'], // 这里处理一下
  277. 'status' => StatusEnum::ENABLED]);
  278. $num = StatusEnum::DISABLED;
  279. switch ($index) {
  280. case ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL: // 待接单
  281. $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL])
  282. // ->andWhere(['>=', 'updated_at', time() - 86400])
  283. ->count();
  284. break;
  285. case ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING: // 待服务
  286. $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING])
  287. // ->andWhere(['>=', 'updated_at', time() - 86400])
  288. ->count();
  289. break;
  290. case ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER: // 待验收
  291. $num = $badgeQuery->andWhere(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER])
  292. // ->andWhere(['>=', 'updated_at', time() - 86400])
  293. ->count();
  294. break;
  295. case ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH: // 已完成
  296. $num = 0;
  297. break;
  298. }
  299. $ret['tab_badge'][$index] = (int) $num;
  300. }
  301. }
  302. return $ret;
  303. }
  304. /**
  305. * 平台订单详情
  306. * @param int $mall_id
  307. * @param int $order_id
  308. * @param int $user_id
  309. * @param null $platform
  310. * @return array|mixed|string
  311. */
  312. public function orderDetail(int $mall_id, int $order_id, int $user_id = 0, $platform = null)
  313. {
  314. // 返回订单预约详情
  315. $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,
  316. 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';
  317. $where = [];
  318. $where[] = ['mall_id' => $mall_id];
  319. $where[] = ['id' => $order_id];
  320. if (!empty($user_id)) $where[] = ['user_id' => $user_id];
  321. $order = Order::getOne($where, true, ['detail' => function ($query) {
  322. $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');
  323. }], false, $select);
  324. if (empty($order)) return '该订单不存在';
  325. $marketing = OrderMarketing::getMarketingInfo($order);
  326. $order['order_status_text'] = OrderStatusEnum::getMap();
  327. $order['is_feedback_text'] = OrderStatusEnum::getFeedbackMap();
  328. $order['shipping_type_text'] = ShippingTypeEnum::getMap();
  329. $order['payment_type_text'] = PayTypeEnum::getMap();
  330. $order['created_at'] = date('Y-m-d H:i:s', $order['created_at']);
  331. $order['pay_time'] = date('Y-m-d H:i:s', $order['pay_time']);
  332. if ($platform) $order['pay_type_list'] = \Yii::$app->services->pay->getEnablePayment($mall_id, $platform);
  333. $order['change_price'] = array_sum(array_column($order['detail'],'adjust_money'));//预留字段
  334. $order['marketing'] = $marketing;
  335. $order['marketing_type_map'] =MarketingTypeEnum::getMap();
  336. $order_setting = Yii::$app->services->setting->mall->get($mall_id, 'order');
  337. $order['payment_expire_time'] = $order_setting['payment_expire_time']??30;
  338. $order['auto_receiving_time'] = $order_setting['auto_receiving_time']??14;
  339. //查询商品单位
  340. if($order['detail']){
  341. foreach ($order['detail'] as $k => $v){
  342. $goods_unit = Goods::getOne([['=','id',$v['goods_id']]],false,'','','unit')['unit'];
  343. $order['detail'][$k]['unit'] = $goods_unit;
  344. }
  345. }
  346. // 获取订单详情的状态文字描述
  347. $order['status_text'] = OrderStatusEnum::getApiStatus($order['order_status'], $order['shipping_type']);
  348. $order['status'] == OrderStatusEnum::NOT_PAY && $order['status_text']['desc'] = $order['payment_expire_time'] . $order['status_text']['desc'];
  349. $order['status'] == OrderStatusEnum::SHIPMENTS && $order['status_text']['desc'] = $order['auto_receiving_time'] . $order['status_text']['desc'];
  350. $order['is_show_return_btn'] = 0;
  351. $order['return_prompt_content'] = '';
  352. $is_show_return_btn = $order_setting['is_show_return_btn'] ?? 0;
  353. 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])){
  354. $order['is_show_return_btn'] = 1;
  355. $order['return_prompt_content'] = $order_setting['return_prompt_content'] ?? '';
  356. }
  357. if (!empty($order['store_id'])) {
  358. $store = Store::findOne(['id' => $order['store_id']]);
  359. $order['mall_name'] = $store->store_name;
  360. $order['mall_logo'] = $store->logo_img;
  361. } else {
  362. $order['mall_name'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.name');
  363. $order['mall_logo'] = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo');
  364. }
  365. // 公共调用
  366. return GlobalInvoke::exec(GlobalInvoke::ORDER_DETAIL, $mall_id, [
  367. 'order' => $order,
  368. 'mall_id' => $mall_id,
  369. ]) ?: $order;
  370. }
  371. /**
  372. * 通过订单ID获取订单详情
  373. * @param int $mall_id
  374. * @param int $user_id
  375. * @param int $order_id
  376. * @param $platform
  377. * @return array|mixed|string
  378. */
  379. public function getOrderDetailById(int $mall_id, int $user_id, int $order_id, $platform)
  380. {
  381. $order = $this->orderDetail($mall_id, $order_id, $user_id, $platform);
  382. if (is_array($order)) {
  383. /**
  384. * @var $orderReserve OrderReserve
  385. */
  386. $orderReserve = OrderReserve::getOne([
  387. ['mall_id' => $mall_id],
  388. ['order_id' => $order_id],
  389. ['reserve_type' => StatusEnum::ENABLED]
  390. ]);
  391. if (empty($orderReserve)) return '订单不存在';
  392. $order['reserve'] = $orderReserve->toArray();
  393. // 取出预约的服务人员
  394. $order['staff'] = ReservationServiceOrder::getOne([
  395. ['mall_id' => $mall_id],
  396. ['order_id' => $order_id],
  397. ['user_id' => $user_id],
  398. ['status' => StatusEnum::ENABLED],
  399. ], true, ['staff' => function($query) {
  400. $query->select('user_id, name, gender, age, avatar, store_id');
  401. }], 'id asc', 'id, user_id, service_status, staff_user_id, service_start_at, user_id, service_end_at');
  402. }
  403. return $order;
  404. }
  405. /**
  406. * 通过ID获取订单详情
  407. * @param int $mall_id
  408. * @param int $user_id
  409. * @param int $id
  410. * @return array|mixed|string
  411. */
  412. public function getDetailById(int $mall_id, int $user_id, int $id)
  413. {
  414. $rWhere = [
  415. ['mall_id' => $mall_id],
  416. ['id' => $id],
  417. // ['status' => StatusEnum::ENABLED],
  418. ['staff_user_id' => $user_id]
  419. ];
  420. // 判断当前用户是否有权限查看当前订单
  421. /**
  422. * @var $model ReservationServiceOrder
  423. */
  424. $model = ReservationServiceOrder::getOne($rWhere);
  425. if (empty($model)) return '预约记录不存在';
  426. if (!empty($model->store_id)) {
  427. $order_no = Order::find()->where(['mall_id' => $mall_id])
  428. ->andWhere(['id' => $model->order_id])
  429. ->select('order_no')->scalar();
  430. if (empty($order_no)) return '订单不存在.';
  431. $storeOrder = StoreOrder::findOne(['mall_id' => $mall_id, 'store_id' => $model->store_id, 'order_no' => $order_no]);
  432. if (empty($storeOrder)) return '订单不存在!';
  433. /**
  434. * @var $orderReserve StoreOrderReserve
  435. */
  436. $orderReserve = StoreOrderReserve::getOne([
  437. ['mall_id' => $mall_id],
  438. ['reserve_type' => StatusEnum::ENABLED],
  439. ['order_id' => $storeOrder->id]
  440. ]);
  441. } else {
  442. $where = [
  443. ['mall_id' => $mall_id],
  444. ['reserve_type' => StatusEnum::ENABLED],
  445. ['order_id' => $model->order_id]
  446. ];
  447. /**
  448. * @var $orderReserve OrderReserve
  449. */
  450. $orderReserve = OrderReserve::getOne($where);
  451. }
  452. if (empty($orderReserve)) return '订单不存在';
  453. $order = $this->orderDetail($mall_id, $model->order_id);
  454. if (is_array($order)) {
  455. $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray();
  456. $order['reserve'] = $orderReserve->toArray();
  457. $order['service_status_map'] = [
  458. 0 => '待接单',
  459. 1 => '待核销',
  460. 20 => '已取消接单',
  461. 50 => '拒绝接单',
  462. 70 => '已关闭',
  463. 90 => '已核销',
  464. 100 => '已完成'
  465. ];
  466. // $order['service_status_map'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_MAP;
  467. foreach ($order['detail'] as $val) {
  468. if ($val['order_status'] == -4) {
  469. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_CLOSED;
  470. break;
  471. }
  472. }
  473. $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态';
  474. $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at);
  475. $order['service_min'] = ($model->service_end_at - $model->service_start_at) / 60; // 分钟
  476. $order['service_status'] = $model->service_status;
  477. $order['service_type'] = $orderReserve->service_type; // 是否为上面服务
  478. $order['create_type'] = $model->create_type;
  479. $order['commission'] = bcmul($model->commission, 1, 2);
  480. $order['service_type_text'] = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve->service_type] ?? '未知服务';
  481. if (!empty($order['finish_time'])) date('Y-m-d H:i:s', $order['finish_time']);
  482. if (!empty($order['sign_time'])) date('Y-m-d H:i:s', $order['sign_time']);
  483. }
  484. //次卡部分
  485. if(!empty($model->secondary_card_id)){
  486. if (MallAddons::isInstall($mall_id,'SecondaryCard')){
  487. $secondary_card = SecondaryCard::findOne(['id'=>$model->secondary_card_id]);
  488. $order['secondary_card'] = [
  489. 'name' => $secondary_card['name'],
  490. 'background' => $secondary_card['background'],
  491. 'font_color' => $secondary_card['font_color'],
  492. 'reservation_cancel_type' => $secondary_card['reservation_cancel_type'],
  493. 'service' => json_decode($secondary_card['service'],true),
  494. 'secondary_card_no' => $model->secondary_card_no,
  495. ];
  496. $order['service_type_text'] = SecondaryCardService::getServiceTypeText($secondary_card);
  497. $secondary_card_order = SecondaryCardOrder::findOne(['order_no'=>$model->secondary_card_no]);
  498. $order['secondary_card']['verifiable_times'] =$secondary_card_order['verifiable_times'];
  499. $order['secondary_card']['use_times'] =$secondary_card['verifiable_times']-$secondary_card_order['verifiable_times'];
  500. $order['secondary_card']['clerk_code'] = $secondary_card_order['clerk_code'];
  501. $order['secondary_card']['order_source'] = SecondaryCardOrderService::getSourceName($secondary_card_order,$secondary_card['use_type']);
  502. $use_log = SecondaryCardUseLog::findOne(['reservation_service_order_id'=>$model['id']]);
  503. $order['secondary_card']['order_money'] = bcdiv($secondary_card_order['pay_money'],$secondary_card['verifiable_times'],2) ;
  504. $order['secondary_card']['service_income'] = $use_log['service_income']??0;
  505. $order['secondary_card']['service_times'] = $use_log['clerk_nums']??1;
  506. $order['secondary_card']['clerk_money'] = $use_log['clerk_money']??0;
  507. }
  508. }
  509. return $order;
  510. }
  511. /**
  512. * 扫码获取的订单详情
  513. * @param int $mall_id
  514. * @param int $user_id
  515. * @param string $code
  516. * @param int $order_id
  517. * @param int $store_id
  518. * @return array|mixed|string
  519. */
  520. public function getDetailByCodeOrId(int $mall_id, int $user_id, string $code = '', int $order_id = 0, int $store_id = 0)
  521. {
  522. // 这里无效了
  523. if (!empty($store_id)) {
  524. if (empty($order_id)) return '订单ID不能为空';
  525. $order_no = Order::find()->where(['mall_id' => $mall_id])
  526. ->andWhere(['id' => $order_id])
  527. ->select('order_no')->scalar();
  528. if (empty($order_no)) return '订单不存在.';
  529. $storeOrder = StoreOrder::findOne(['mall_id' => $mall_id, 'store_id' => $store_id, 'order_no' => $order_no]);
  530. if (empty($storeOrder)) return '订单不存在!';
  531. /**
  532. * @var $orderReserve StoreOrderReserve
  533. */
  534. $orderReserve = StoreOrderReserve::getOne([
  535. ['mall_id' => $mall_id],
  536. ['reserve_type' => StatusEnum::ENABLED],
  537. ['order_id' => $storeOrder->id]
  538. ]);
  539. if (empty($orderReserve)) return '订单不存在';
  540. if ($orderReserve['service_type'] == 1) {
  541. $store_reserve_setting = (new StoreReserveSettingService(['mall_id' => $mall_id, 'store_id' => $store_id]))->detail();
  542. if (empty($store_reserve_setting['technician_verification_switch'])) {
  543. throw new \Exception('技师核销开关未开启');
  544. }
  545. }
  546. } else {
  547. $where = [
  548. ['mall_id' => $mall_id],
  549. ['reserve_type' => StatusEnum::ENABLED]
  550. ];
  551. if (!empty($code)) $where[] = ['reserve_code' => $code];
  552. if (!empty($order_id)) $where[] = ['order_id' => $order_id];
  553. /**
  554. * @var $orderReserve OrderReserve
  555. */
  556. $orderReserve = OrderReserve::getOne($where);
  557. if (empty($orderReserve)) {
  558. /**
  559. * @var $orderReserve StoreOrderReserve
  560. */
  561. $orderReserve = StoreOrderReserve::getOne([
  562. ['mall_id' => $mall_id],
  563. ['reserve_type' => StatusEnum::ENABLED],
  564. ['reserve_code' => $code]
  565. ]);
  566. if (empty($orderReserve)) return '订单不存在';
  567. $order_id = $orderReserve->main_order_id;
  568. $store_id = $orderReserve->store_id;
  569. $this->checkClerk($user_id, $store_id, $orderReserve['tech_id'], $orderReserve['service_type']);
  570. } else {
  571. $order_id = $orderReserve->order_id;
  572. }
  573. }
  574. $rWhere = [
  575. ['mall_id' => $mall_id],
  576. ['order_id' => $order_id],
  577. ['status' => StatusEnum::ENABLED],
  578. ];
  579. if (!empty($store_id)) {
  580. $rWhere[] = ['store_id' => $store_id];
  581. } else {
  582. $rWhere[] = ['staff_user_id' => $user_id];
  583. }
  584. // 判断当前用户是否有权限查看当前订单
  585. /**
  586. * @var $model ReservationServiceOrder
  587. */
  588. $model = ReservationServiceOrder::getOne($rWhere, false, [], 'id desc');
  589. if (empty($model)) return '预约记录不存在';
  590. if (!empty($store_id)) {
  591. $user_id = $model['staff_user_id'];////替换成技师的会员id
  592. }
  593. // self::checkStoreStaffCanClerk($mall_id, $store_id, $user_id);
  594. $order = $this->orderDetail($mall_id, $model->order_id);
  595. if (is_array($order)) {
  596. $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray();
  597. $order['reserve'] = $orderReserve->toArray();
  598. $order['service_status_map'] = [
  599. 1 => '待核销',
  600. 70 => '已关闭',
  601. 90 => '已核销',
  602. 100 => '已完成'
  603. ];
  604. $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态';
  605. $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at);
  606. }
  607. return $order;
  608. }
  609. /**
  610. * 检查门店技师在当前时间是否可以核销
  611. * @param $store_id
  612. * @param $user_id
  613. * @return true
  614. * @throws \Exception
  615. */
  616. public static function checkStoreStaffCanClerk($mall_id, $store_id, $user_id)
  617. {
  618. if (empty($store_id)) {
  619. return true;
  620. }
  621. $time = time();
  622. $date = date('Y-m-d', $time);
  623. $date_time = strtotime($date . ' 00:00:00');
  624. $scheduling = StoreReserveTechnicianScheduling::find()->where(['mall_id' => $mall_id, 'store_id' => $store_id, 'user_id' => $user_id, 'date_time' => $date_time, 'status' => StatusEnum::ENABLED])
  625. ->with(['schedulingTime'])->one();
  626. if (!empty($scheduling['is_all_day'])) {
  627. $store = Store::findOne(['id' => $store_id, 'mall_id' => $mall_id]);
  628. $business_time_start = strtotime($date . ' ' . $store['business_time_start'] . ':00');
  629. $business_time_end = strtotime($date . ' ' . $store['business_time_end'] . ':00');
  630. if ($time < $business_time_start || $time > $business_time_end) {
  631. throw new \Exception('当前时间不是门店营业时间');
  632. }
  633. } else {
  634. if (empty($scheduling['schedulingTime'])) {
  635. throw new \Exception('当前时间技师没有排班');
  636. }
  637. $is_true = false;
  638. foreach ($scheduling['schedulingTime'] as $val) {
  639. if ($time >= $val['start_time'] && $time <= $val['end_time']) {
  640. $is_true = true;
  641. break;
  642. }
  643. }
  644. if ($is_true == false) {
  645. throw new \Exception('当前时间技师没有排班');
  646. }
  647. }
  648. return true;
  649. }
  650. /**
  651. * 获取核销记录详情
  652. * @Author:hua
  653. * @Date:2024-03-14 10:26
  654. * @Copyright:copyright(c)2024 广东七件事集团
  655. * @param $mall_id
  656. * @param $reservation_service_order_id
  657. * @param $order_id
  658. * @return array|mixed|string
  659. */
  660. public function getClerkLogDetail( $mall_id, $reservation_service_order_id , $order_id )
  661. {
  662. $where = [
  663. ['mall_id' => $mall_id],
  664. ['reserve_type' => StatusEnum::ENABLED],
  665. ['order_id' => $order_id]
  666. ];
  667. $orderReserve = OrderReserve::getOne($where);
  668. if (empty($orderReserve)) {
  669. $orderReserve = StoreOrderReserve::getOne([
  670. ['mall_id' => $mall_id],
  671. ['reserve_type' => StatusEnum::ENABLED],
  672. ['main_order_id' => $order_id]
  673. ]);
  674. if (empty($orderReserve)) return '订单不存在';
  675. }
  676. $rWhere = [
  677. ['mall_id' => $mall_id],
  678. ['id' => $reservation_service_order_id],
  679. ['status' => StatusEnum::ENABLED],
  680. ];
  681. $model = ReservationServiceOrder::getOne($rWhere);
  682. if (empty($model)) return '预约记录不存在';
  683. $order = $this->orderDetail($mall_id, $model->order_id);
  684. if (is_array($order)) {
  685. $order['user'] = $model->getUser()->select('id, nickname, avatar_url, mobile')->one()->toArray();
  686. $order['reserve'] = $orderReserve->toArray();
  687. $order['service_status_map'] = [
  688. 1 => '待核销',
  689. 90 => '已核销',
  690. 100 => '已完成'
  691. ];
  692. $order['service_status_text'] = $order['service_status_map'][$model->service_status] ?? '未知状态';
  693. $order['service_start_at_text'] = date('Y-m-d H:i', $model->service_start_at);
  694. }
  695. return $order;
  696. }
  697. /**
  698. * 通过订单ID进行核销
  699. * @param int $mall_id
  700. * @param int $user_id
  701. * @param int $order_id
  702. * @param int $store_id
  703. * @return ReservationServiceOrder|string
  704. */
  705. public function underwriter(int $mall_id, int $user_id, int $order_id, int $store_id = 0)
  706. {
  707. $where = [
  708. ['mall_id' => $mall_id],
  709. ['order_id' => $order_id],
  710. ['status' => StatusEnum::ENABLED],
  711. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING],
  712. ];
  713. // 门店核销,门店所有技师都能进行核销处理,所以不需要绑定至某个用户,只需要判断当前用户是否为门店技师即可
  714. if (!empty($store_id)) {
  715. $where[] = ['store_id' => $store_id];
  716. } else {
  717. $where[] = ['staff_user_id' => $user_id];
  718. }
  719. /**
  720. * @var $model ReservationServiceOrder
  721. */
  722. $model = ReservationServiceOrder::getOne($where);
  723. if (empty($model)) return '预约记录不存在或不可核销';
  724. $t = \Yii::$app->db->beginTransaction();
  725. try {
  726. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER;
  727. $model->remark = "{$model->remark} 技师 [$user_id] 核销了当前订单 \n";
  728. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  729. /**
  730. * @var $staff ReservationServiceUser
  731. */
  732. $staff = $model->getStaff()->one();
  733. // 累加订单
  734. if (!empty($model->store_id)) {
  735. $staff->store_order_num += 1;
  736. } else {
  737. $staff->order_num += 1;
  738. }
  739. if (!$staff->save()) throw new \Exception($staff->getErrorMessage());
  740. $user = User::findOne(['id' => $user_id]);
  741. $data['id'] = $order_id;
  742. $data['mall_id'] = $mall_id;
  743. $data['user_id'] = $model->user_id;
  744. $data['operator_id'] = $user_id;
  745. $data['operator_name'] = $user->nickname ?? $user->mobile;
  746. $data['from'] = OrderSourceEnum::SOURCE_RESERVE;
  747. $data['tech_id'] = $staff->id; // 技师ID
  748. $res = Order::takeDelivery($data);
  749. if ($res === false) throw new \Exception(Order::getStaticError());
  750. if (!empty($model->store_id)) {
  751. $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $model->order_id]);
  752. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  753. } else {
  754. $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]);
  755. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  756. }
  757. $orderReserve->reserve_status = ReservationServiceEnum::CHECK_FAILED;
  758. // 如果是在后台直接核销的那么就没办法绑定技师了,所以一定需要技师进行核销才能处理
  759. if (empty($orderReserve->tech_id)) $orderReserve->tech_id = $staff->id; // 绑定技师ID
  760. if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage());
  761. $t->commit();
  762. return $model;
  763. } catch (\Exception $e) {
  764. $t->rollBack();
  765. return $e->getMessage();
  766. }
  767. }
  768. /**
  769. * 通过核销码进行核销
  770. * @param int $mall_id
  771. * @param int $user_id
  772. * @param int $order_id
  773. * @param int $store_id
  774. * @return ReservationServiceOrder|string
  775. */
  776. public function clerk(int $mall_id, int $user_id, int $code, int $store_id = 0)
  777. {
  778. $where = [
  779. ['mall_id' => $mall_id],
  780. ['reserve_type' => StatusEnum::ENABLED]
  781. ];
  782. if (!empty($code)) $where[] = ['reserve_code' => $code];
  783. if (!empty($order_id)) $where[] = ['order_id' => $order_id];
  784. /**
  785. * @var $orderReserve OrderReserve
  786. */
  787. $orderReserve = OrderReserve::getOne($where);
  788. $service_type_text = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve['service_type']] ?? '';
  789. $mall_logo = Yii::$app->services->setting->mall->get($mall_id, 'basic.logo');
  790. $mall = Mall::findOne(['id'=>$mall_id]);
  791. $mall_name = $mall['name'];
  792. if (empty($orderReserve)) {
  793. /**
  794. * @var $orderReserve StoreOrderReserve
  795. */
  796. $orderReserve = StoreOrderReserve::getOne([
  797. ['mall_id' => $mall_id],
  798. ['reserve_type' => StatusEnum::ENABLED],
  799. ['reserve_code' => $code]
  800. ]);
  801. if (empty($orderReserve)) return '订单不存在';
  802. $this->checkClerk($user_id, $orderReserve->store_id, $orderReserve['tech_id'], $orderReserve['service_type']);
  803. $order_id = $orderReserve->main_order_id;
  804. $store_id = $orderReserve->store_id;
  805. $service_type_text = ReservationServiceEnum::SERVICE_TYPE_MAP[$orderReserve['service_type']] ?? '';
  806. $store = Store::findOne(['id' => $orderReserve['store_id']]);
  807. $mall_logo = $store['logo_img'];
  808. $mall_name = $store['store_name'];
  809. } else {
  810. $order_id = $orderReserve->order_id;
  811. }
  812. $order = Order::findOne(['id'=>$order_id]);
  813. $order_detail = OrderDetail::findOne(['order_id'=>$order_id]);
  814. $num = OrderDetail::find()->where(['order_id'=>$order_id])->sum('num');
  815. $where = [
  816. ['mall_id' => $mall_id],
  817. ['order_id' => $order_id],
  818. ['status' => StatusEnum::ENABLED],
  819. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING],
  820. ];
  821. $clerk_user_id = $user_id;//操作核销的会员id
  822. if (!empty($store_id)) {
  823. $where[] = ['store_id' => $store_id];
  824. } else {
  825. $where[] = ['staff_user_id' => $user_id];
  826. }
  827. /**
  828. * @var $model ReservationServiceOrder
  829. */
  830. $model = ReservationServiceOrder::getOne($where);
  831. if (empty($model)) return '预约记录不存在或不可核销';
  832. if (!empty($store_id)) {
  833. $user_id = $model['staff_user_id'];//替换成技师的会员id
  834. }
  835. // self::checkStoreStaffCanClerk($mall_id, $store_id, $user_id);
  836. $t = \Yii::$app->db->beginTransaction();
  837. try {
  838. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER;
  839. $model->server_status = ReservationServiceEnum::TO_BE_ACCEPTED;
  840. $model->remark = "{$model->remark} , [$clerk_user_id] 核销了当前订单 \n";
  841. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  842. /**
  843. * @var $staff ReservationServiceUser
  844. */
  845. $staff = $model->getStaff()->one();
  846. if (empty($staff)) {
  847. throw new \Exception('该订单未分配技师,不能核销');
  848. }
  849. // 累加订单
  850. if (!empty($model->store_id)) {
  851. $staff->store_order_num += 1;
  852. } else {
  853. $staff->order_num += 1;
  854. }
  855. if (!$staff->save()) throw new \Exception($staff->getErrorMessage());
  856. $user = User::findOne(['id' => $user_id]);
  857. $data['id'] = $order_id;
  858. $data['mall_id'] = $mall_id;
  859. $data['user_id'] = $model->user_id;
  860. $data['operator_id'] = $user_id;
  861. $data['operator_name'] = $user->nickname ?? $user->mobile;
  862. $data['from'] = OrderSourceEnum::SOURCE_RESERVE;
  863. $data['tech_id'] = $staff->id; // 技师ID
  864. $res = Order::takeDelivery($data);
  865. if ($res === false) throw new \Exception(Order::getStaticError());
  866. // 因为进行核销后平台预约订单和门店预约订单状态并为改为待服务,所以进行核销后需要修改
  867. Order::updateAll(['order_status' => OrderStatusEnum::SING], ['id' => $model->order_id]);
  868. if (!empty($model->store_id)) {
  869. StoreOrder::updateAll(['order_status' => OrderStatusEnum::SING], ['id' => $orderReserve->order_id]);
  870. $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $model->order_id]);
  871. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  872. } else {
  873. $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]);
  874. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  875. }
  876. $orderReserve->reserve_status = OrderReserve::RESERVE_STATUS_PENDDING;
  877. // 如果是在后台直接核销的那么就没办法绑定技师了,所以一定需要技师进行核销才能处理
  878. if (empty($orderReserve->tech_id)) $orderReserve->tech_id = $staff->id; // 绑定技师ID
  879. if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage());
  880. $add_clerk_log_data = [
  881. 'mall_id' => $model['mall_id'],
  882. 'user_id' => $clerk_user_id,
  883. 'mall_logo' => $mall_logo,
  884. 'mall_name' => $mall_name,
  885. 'name' => $order_detail['goods_name'],
  886. 'pic' => $order_detail['pic_url'],
  887. 'clerk_code' => (string)$code,
  888. 'type' => ClerkEnum::RESERVATION_SERVICE_CLERK_CODE_PRE,
  889. 'extra' => json_encode([
  890. 'clerk_nums' => $num,
  891. 'verifiable_times' => 0,
  892. 'clerk_money' => 0,
  893. 'settled_money' => 0,
  894. 'order_money' => $order['pay_money'],
  895. 'pay_money' => $order['pay_money'],
  896. 'unit_times' => 0,
  897. 'service_type_text' => $service_type_text,
  898. 'service_income'=> $model['commission'],
  899. 'reservation_service_order_id'=> $model['id'],
  900. 'order_id'=> $order_id,
  901. ]),
  902. ];
  903. $clerk_log_model = ClerkLog::setData($add_clerk_log_data);
  904. if ($clerk_log_model == false) {
  905. throw new \Exception(ClerkLog::getStaticError());
  906. }
  907. $t->commit();
  908. return $model;
  909. } catch (\Exception $e) {
  910. $t->rollBack();
  911. \Yii::error('code:' . $code . ';;;' . $e->getMessage());
  912. return $e->getMessage();
  913. }
  914. }
  915. public function checkClerk($user_id, $store_id, $tech_id, $service_type)
  916. {
  917. $store = Store::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]);
  918. //先判断是不是本店店长
  919. if (!empty($store)) {
  920. if ($store_id != $store['id']) {
  921. $reservation_service_user = ReservationServiceUser::findOne(['user_id' => $user_id, 'store_id' => $store_id, 'status' => StatusEnum::ENABLED]);
  922. if ($store_id != $reservation_service_user['store_id'] || $tech_id != $reservation_service_user['id']) {
  923. throw new \Exception('该订单你没有权限核销');
  924. }
  925. }
  926. } else {
  927. $reservation_service_user = ReservationServiceUser::findOne(['user_id' => $user_id, 'store_id' => $store_id, 'status' => StatusEnum::ENABLED]);
  928. if (empty($reservation_service_user)) {
  929. //不是店长,先判断是不是本店核销员
  930. $store_clerk = StoreClerk::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]);
  931. if (empty($store_clerk) || $store_id != $store_clerk['store_id']) {
  932. throw new \Exception('该订单你没有权限核销');
  933. }
  934. } else {
  935. //技师,判断是不是同一个技师
  936. if ($store_id != $reservation_service_user['store_id'] || $tech_id != $reservation_service_user['id']) {
  937. throw new \Exception('该订单你没有权限核销');
  938. }
  939. if ($service_type == 1) {
  940. $store_reserve_setting = (new StoreReserveSettingService(['mall_id' => $reservation_service_user['mall_id'], 'store_id' => $store_id]))->detail();
  941. if (empty($store_reserve_setting['technician_verification_switch'])) {
  942. throw new \Exception('技师核销开关未开启');
  943. }
  944. }
  945. }
  946. }
  947. }
  948. /**
  949. * 接受订单
  950. * @param int $mall_id
  951. * @param int $user_id
  952. * @param int $order_id
  953. * @param int $store_id
  954. * @return ReservationServiceOrder|string
  955. */
  956. public function talking(int $mall_id, int $user_id, int $order_id, int $store_id = 0)
  957. {
  958. $where = [
  959. ['mall_id' => $mall_id],
  960. ['order_id' => $order_id],
  961. ['status' => StatusEnum::ENABLED],
  962. ['staff_user_id' => $user_id],
  963. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]
  964. ];
  965. if (!empty($store_id)) $where[] = ['store_id' => $store_id];
  966. /**
  967. * @var $model ReservationServiceOrder
  968. */
  969. $model = ReservationServiceOrder::getOne($where);
  970. if (empty($model)) return '预约记录不存在';
  971. $t = \Yii::$app->db->beginTransaction();
  972. try {
  973. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING;
  974. $model->remark = "{$model->remark} 技师 [$user_id] 接受了当前订单的预约 \n";
  975. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  976. // 同意之后是否需要写入预约时间?
  977. // 并且写入技师ID
  978. $staff = ReservationServiceUser::findOne(['user_id' => $user_id, 'status' => StatusEnum::ENABLED]);
  979. if (!empty($model->store_id)) {
  980. // 取出门店的预约订单
  981. $orderReserve = StoreOrderReserve::findOne(['main_order_id' => $order_id]);
  982. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  983. } else {
  984. $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]);
  985. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  986. }
  987. $orderReserve->tech_id = $staff->id;
  988. $orderReserve->reserve_status = StatusEnum::ENABLED;
  989. $orderReserve->reserve_date_time = date('Y-m-d H:i', $model->service_start_at) .','. date('Y-m-d H:i', $model->service_end_at);
  990. if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage());
  991. // 被预约的时间
  992. $bookTime = new ReservationServiceUserBookTime();
  993. $bookTime->order_id = $model->order_id;
  994. $bookTime->user_id = $model->staff_user_id;
  995. $bookTime->mall_id = $model->mall_id;
  996. $bookTime->start_time = $model->service_start_at;
  997. $bookTime->end_time = $model->service_end_at;
  998. if (!$bookTime->save()) throw new \Exception($bookTime->getErrorMessage());
  999. $user = User::findOne(['id' => $user_id]);
  1000. if(!empty($model->secondary_card_id)){
  1001. $form['mall_id'] = $model->mall_id;
  1002. $form['mch_id'] = 0;
  1003. $form['shipping_type'] = 0;
  1004. $form['id'] = $model->order_id;
  1005. $form['operator_id'] = $user_id;
  1006. $form['order_detail_ids'] = OrderDetail::find()->where(['order_id' => $model->order_id])->select('id')->column();
  1007. $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile;
  1008. OrderExpress::delivery($form); // 发货
  1009. $form['mall_id'] = $mall_id;
  1010. $form['shipping_type'] = 0;
  1011. $form['mch_id'] = 0;
  1012. $form['store_id'] = $model->store_id;
  1013. $form['operator_id'] = $model->staff_user_id;
  1014. $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile;
  1015. $form['id'] = $orderReserve->order_id;
  1016. $form['order_detail_ids'] = StoreOrderDetail::find()->where(['order_id' => $orderReserve->order_id])->select('id')->column();
  1017. $res = StoreOrder::OrderExpressDelivery($form);
  1018. if (!$res) throw new \Exception(StoreOrder::getStaticError());
  1019. }else{
  1020. if (empty($model->store_id)) { // 门店也需要执行?
  1021. // 执行发货操作
  1022. $form['mall_id'] = $model->mall_id;
  1023. $form['mch_id'] = 0;
  1024. $form['shipping_type'] = 0;
  1025. $form['id'] = $model->order_id;
  1026. $form['operator_id'] = $user_id;
  1027. $form['order_detail_ids'] = OrderDetail::find()->where(['order_id' => $model->order_id])->select('id')->column();
  1028. $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile;
  1029. OrderExpress::delivery($form); // 发货
  1030. } else { // 门店发货
  1031. $form['mall_id'] = $mall_id;
  1032. $form['shipping_type'] = 0;
  1033. $form['mch_id'] = 0;
  1034. $form['store_id'] = $model->store_id;
  1035. $form['operator_id'] = $model->staff_user_id;
  1036. $form['operator_name'] = !empty($user->nickname) ? $user->nickname : $user->mobile;
  1037. $form['id'] = $orderReserve->order_id;
  1038. $form['order_detail_ids'] = StoreOrderDetail::find()->where(['order_id' => $orderReserve->order_id])->select('id')->column();
  1039. $res = StoreOrder::OrderExpressDelivery($form);
  1040. if (!$res) throw new \Exception(StoreOrder::getStaticError());
  1041. }
  1042. }
  1043. $main_order = Order::findOne(['order_no' => $model['order_no']]);
  1044. $main_order->order_status = OrderStatusEnum::SHIPMENTS;
  1045. $main_order->shipping_time = time();
  1046. $main_order->save();
  1047. $t->commit();
  1048. // 记录数据
  1049. (new NoticeLogic())->send(['mall_id' => $mall_id, 'id' => $order_id, 'sms_key' => ReservationServiceEnum::SMS_KEY_AGREE]);
  1050. return $model;
  1051. } catch (\Exception $e) {
  1052. $t->rollBack();
  1053. return $e->getMessage().$e->getFile().$e->getLine();
  1054. }
  1055. }
  1056. /**
  1057. * 拒绝接单
  1058. * @param int $mall_id
  1059. * @param int $user_id
  1060. * @param int $order_id
  1061. * @param int $store_id
  1062. * @param string $reason
  1063. * @return ReservationServiceOrder|string
  1064. */
  1065. public function reject(int $mall_id, int $user_id, int $order_id, int $store_id = 0, string $reason = '无')
  1066. {
  1067. $where = [
  1068. ['mall_id' => $mall_id],
  1069. ['order_id' => $order_id],
  1070. ['status' => StatusEnum::ENABLED],
  1071. ['staff_user_id' => $user_id],
  1072. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]
  1073. ];
  1074. if (!empty($store_id)) $where[] = ['store_id' => $store_id];
  1075. /**
  1076. * @var $model ReservationServiceOrder
  1077. */
  1078. $model = ReservationServiceOrder::getOne($where);
  1079. if (empty($model)) return '预约记录不存在';
  1080. $t = \Yii::$app->db->beginTransaction();
  1081. try {
  1082. $remark = "{$model->remark} 技师 [$user_id] 拒绝了当前订单的预约, 拒绝理由[$reason] \n";
  1083. if($model->secondary_card_id){
  1084. $order = Order::findOne(['id'=>$model->order_id]);
  1085. $order->status = StatusEnum::DISABLED;
  1086. $order->save();
  1087. StoreOrder::updateAll(['status'=>StatusEnum::DISABLED],['order_no'=>$order->order_no]);
  1088. $remark = "{$model->remark} 技师 [$user_id] 拒绝了当前次卡的预约, 拒绝理由[$reason] \n";
  1089. }
  1090. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_REJECT;
  1091. $model->remark = $remark;
  1092. $model->reject_reason = $reason;
  1093. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  1094. if (!empty($model->store_id)) {
  1095. /**
  1096. * @var $reserveOrder StoreOrderReserve
  1097. */
  1098. $reserveOrder = StoreOrderReserve::getOne(['main_order_id' => $model['order_id']]);
  1099. } else {
  1100. /**
  1101. * @var $reserveOrder OrderReserve
  1102. */
  1103. $reserveOrder = $model->getReserveOrder()->one();
  1104. }
  1105. $reserveOrder->reserve_status = OrderReserve::RESERVE_STATUS_WAIT; // 等待预约
  1106. $reserveOrder->tech_id = 0;
  1107. if (!$reserveOrder->save()) throw new \Exception($reserveOrder->getErrorMessage());
  1108. $t->commit();
  1109. // 记录数据
  1110. (new NoticeLogic())->send(['mall_id' => $mall_id, 'id' => $order_id, 'sms_key' => ReservationServiceEnum::SMS_KEY_REJECT]);
  1111. return $model;
  1112. } catch (\Exception $e) {
  1113. $t->rollBack();
  1114. return $e->getMessage();
  1115. }
  1116. }
  1117. /**
  1118. * 取消预约
  1119. * @param int $mall_id
  1120. * @param int $user_id
  1121. * @param int $order_id
  1122. * @param int $store_id
  1123. * @param bool $is_buyer
  1124. * @return ReservationServiceOrder|string
  1125. */
  1126. public function cancel(int $mall_id, int $user_id, int $order_id, int $store_id = 0, bool $is_buyer = false)
  1127. {
  1128. $where = [
  1129. ['mall_id' => $mall_id],
  1130. ['order_id' => $order_id],
  1131. ['status' => StatusEnum::ENABLED],
  1132. // ['staff_user_id' => $user_id],
  1133. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING]
  1134. ];
  1135. if ($is_buyer) {
  1136. $role = '用户';
  1137. $where[] = ['user_id' => $user_id];
  1138. } else {
  1139. $role = '技师';
  1140. $where[] = ['staff_user_id' => $user_id];
  1141. }
  1142. if (!empty($store_id)) $where[] = ['store_id' => $store_id];
  1143. /**
  1144. * @var $model ReservationServiceOrder
  1145. */
  1146. $model = ReservationServiceOrder::getOne($where);
  1147. if (empty($model)) return '预约记录不存在';
  1148. $t = \Yii::$app->db->beginTransaction();
  1149. try {
  1150. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_CANCEL;
  1151. $model->remark = "{$model->remark} {$role} [$user_id] 取消了当前订单的预约 \n";
  1152. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  1153. if (!empty($model->store_id)) {
  1154. $storeOrder = StoreOrder::findOne(['order_no' => $model->order_no]);
  1155. if (empty($storeOrder)) throw new \Exception("预约订单不存在");
  1156. $orderReserve = StoreOrderReserve::findOne(['order_id' => $storeOrder->id]);
  1157. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  1158. } else {
  1159. $orderReserve = OrderReserve::findOne(['order_id' => $model->order_id]);
  1160. if (empty($orderReserve)) throw new \Exception("预约订单不存在");
  1161. }
  1162. $orderReserve->tech_id = 0;
  1163. $orderReserve->reserve_status = 0;
  1164. // $orderReserve->reserve_date_time = '';
  1165. if (!$orderReserve->save()) throw new \Exception($orderReserve->getErrorMessage());
  1166. // 清除预约时间
  1167. ReservationServiceUserBookTime::updateAll(['status' => StatusEnum::DELETE],
  1168. ['and', ['status' => StatusEnum::ENABLED], ['order_id' => $model->order_id]]);
  1169. // 清除发货信息
  1170. if (empty($model->store_id)) {
  1171. $order = Order::findOne(['id' => $order_id]);
  1172. $order->sign_time = 0;
  1173. $order->order_status = OrderStatusEnum::PAY;
  1174. $order->shipping_status = StatusEnum::DISABLED;
  1175. if (!$order->save()) throw new \Exception($order->getErrorMessage());
  1176. // 清除详情发货信息
  1177. OrderDetail::updateAll(['order_status' => OrderStatusEnum::PAY, 'shipping_status' => StatusEnum::DISABLED],
  1178. ['in', 'id', OrderDetail::find()->where(['order_id' => $order_id])->select('id')->column()]);
  1179. }
  1180. if($model->secondary_card_id>0){
  1181. $order = Order::findOne(['id' => $model->order_id]);
  1182. $order->status = StatusEnum::DISABLED;
  1183. if (!$order->save()) throw new \Exception($order->getErrorMessage());
  1184. }
  1185. $t->commit();
  1186. return $model;
  1187. } catch (\Exception $e) {
  1188. $t->rollBack();
  1189. return $e->getMessage();
  1190. }
  1191. }
  1192. /**
  1193. * 验收 - 等同于平台订单确认收货 - 门店后台/门店技师/技师
  1194. * @param int $mall_id
  1195. * @param int $order_id
  1196. * @param int $user_id
  1197. * @param int $store_id
  1198. * @param null $admin
  1199. * @param bool $run_global
  1200. * @return ReservationServiceOrder|string
  1201. */
  1202. public function acceptance(int $mall_id, int $order_id, int $user_id = 0, int $store_id = 0, $admin = null, bool $run_global = true)
  1203. {
  1204. $where = [
  1205. ['mall_id' => $mall_id],
  1206. ['order_id' => $order_id],
  1207. ['status' => StatusEnum::ENABLED],
  1208. ['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]
  1209. ];
  1210. if (!empty($store_id)) $where[] = ['store_id' => $store_id];
  1211. if (!empty($user_id)) $where[] = ['user_id' => $user_id];
  1212. /**
  1213. * @var $model ReservationServiceOrder
  1214. */
  1215. $model = ReservationServiceOrder::getOne($where);
  1216. if (empty($model)) return !$run_global ? '预约记录不存在' : true;
  1217. if ($model->service_status == ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH) return $model;
  1218. if ($model->service_status != ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER) return '当前状态不可验收';
  1219. $t = \Yii::$app->db->beginTransaction();
  1220. try {
  1221. // 门店核销员
  1222. if (!empty($user_id)) {
  1223. $remark = "用户 [$user_id] 验收了当前预约订单";
  1224. } elseif (!empty($store_id)) {
  1225. $remark = "门店 [$store_id] 验收了当前预约订单";
  1226. } elseif (!empty($admin)) {
  1227. $remark = "后台雇员 [$admin->id] 验收了当前预约订单";
  1228. } else {
  1229. $remark = "系统自动验收了当前预约订单";
  1230. }
  1231. $model->service_status = ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH;
  1232. $model->remark = "{$model->remark} $remark \n";
  1233. $model->server_status = ReservationServiceEnum::COMPLETED;
  1234. // $model->service_status = 100;
  1235. if (!$model->save()) throw new \Exception($model->getErrorMessage());
  1236. // 执行平台的处理
  1237. if ($run_global) {
  1238. $this->globalComplete($mall_id, $user_id, $model, $admin);
  1239. }
  1240. // 累加订单
  1241. if (!empty($model->store_id)) {
  1242. $staff = $model->getStaff()->one();
  1243. $staff->store_order_num += 1;
  1244. $staff->save();
  1245. }
  1246. $t->commit();
  1247. return $model;
  1248. } catch (\Exception $e) {
  1249. $t->rollBack();
  1250. Yii::error(FormatHelper::exception($e, __METHOD__));
  1251. return $e->getMessage();
  1252. }
  1253. }
  1254. /**
  1255. * @param int $mall_id
  1256. * @param int $user_id
  1257. * @param ReservationServiceOrder $reservationServiceOrder
  1258. * @param $admin
  1259. * @return void
  1260. * @throws \Exception
  1261. */
  1262. protected function globalComplete(int $mall_id, int $user_id, ReservationServiceOrder $reservationServiceOrder, $admin)
  1263. {
  1264. $nickname = "";
  1265. $mobile = "";
  1266. $operator_id = $user_id;
  1267. if (!empty($admin)) {
  1268. $nickname = $admin->account;
  1269. $operator_id = $admin->id;
  1270. } else if (!empty($user_id)) {
  1271. /**
  1272. * @var $user User
  1273. */
  1274. $user = User::findOne(['id' => $user_id]);
  1275. $nickname = $user->nickname;
  1276. $mobile = $user->mobile;
  1277. }
  1278. $data['id'] = $reservationServiceOrder->order_id;
  1279. $data['mall_id'] = $mall_id;
  1280. if (!empty($user)) $data['user_id'] = $user_id;
  1281. $data['operator_id'] = $operator_id;
  1282. $data['operator_name'] = !empty($nickname) ? $nickname : $mobile;
  1283. $data['from'] = OrderSourceEnum::SOURCE_RESERVE;
  1284. $res = Order::complete($data);
  1285. if ($res === false) throw new \Exception(Order::getStaticError());
  1286. }
  1287. /**
  1288. * @param int $mall_id
  1289. * @param int $store_id
  1290. * @return int[]
  1291. */
  1292. public function dataStatistics(int $mall_id, int $store_id = 0)
  1293. {
  1294. // 累计服务数量
  1295. // 昨日服务数量
  1296. $query = ReservationServiceOrder::find()->where(['mall_id' => $mall_id])
  1297. ->andWhere(['status' => StatusEnum::ENABLED])
  1298. // ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]]);
  1299. // 修改原因:现在按核销数量来计算,核销后,就会有核销备注“XXX核销了订单”,所以用备注不为空来计算
  1300. ->andWhere(['!=', 'remark', '']);
  1301. if (!empty($store_id)) $query->andWhere(['store_id' => $store_id]);
  1302. $y = strtotime(date('Y-m-d')) - 86400;
  1303. return [
  1304. 'total' => $query->count(),
  1305. 'yesterday' => $query
  1306. ->andWhere(['between', 'service_start_at', $y, strtotime(date('Y-m-d'))])
  1307. ->count(),
  1308. ];
  1309. }
  1310. /**
  1311. * 写入前校验
  1312. * @param array $params
  1313. * @return ReservationServiceUser
  1314. * @throws \Exception
  1315. */
  1316. public function valid(array $params)
  1317. {
  1318. // 校验技师
  1319. /**
  1320. * @var $staff ReservationServiceUser
  1321. */
  1322. $staff = ReservationServiceUser::findOne(['mall_id' => $params['mall_id'], 'id' => $params['tech_id'],
  1323. 'status' => StatusEnum::ENABLED, 'check_status' => ReservationServiceEnum::CHECK_ADOPT]);
  1324. if (empty($staff)) throw new \Exception('技师不存在');
  1325. // 距离判断?
  1326. $distance = (new LocationHelper())->getDistanceByGeo($staff->latitude, $staff->longitude, $params['lat'], $params['lng']);
  1327. if (!empty($params['store_id'])) {
  1328. $goods = StoreGoodsReserve::findOne([
  1329. 'goods_id' => $params['goods_id']
  1330. ]);
  1331. } else {
  1332. $goods = GoodsReserve::findOne([
  1333. 'goods_id' => $params['goods_id']
  1334. ]);
  1335. }
  1336. if ($distance > $goods->distance) {
  1337. throw new \Exception("不在支持范围");
  1338. }
  1339. return $staff;
  1340. }
  1341. /**
  1342. * 写入数据 - 应该在订单支付的时候写入
  1343. * @param array $params
  1344. * @return ReservationServiceOrder
  1345. * @throws \Exception
  1346. */
  1347. public function save(array $params)
  1348. {
  1349. // $staff = $this->valid($params);
  1350. /**
  1351. * @var $staff ReservationServiceUser
  1352. */
  1353. if (!empty($params['tech_id'])) {
  1354. $staff = ReservationServiceUser::findOne(['mall_id' => $params['mall_id'], 'id' => $params['tech_id'],
  1355. 'status' => StatusEnum::ENABLED, 'check_status' => ReservationServiceEnum::CHECK_ADOPT]);
  1356. }
  1357. // if (empty($staff)) throw new \Exception('技师不存在');
  1358. // 是否已经预约过
  1359. if (!empty(ReservationServiceOrder::find()->where(['order_id' => $params['order_id']])
  1360. ->andWhere(['status' => StatusEnum::ENABLED])
  1361. ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING,
  1362. ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH]])->one())) {
  1363. throw new \Exception("不可重复预约");
  1364. };
  1365. if (empty($params['store_id']) && !empty($params['tech_id'])) { // 门店没有佣金
  1366. /**
  1367. * @var $level ReservationServiceLevel
  1368. */
  1369. $level = $staff->getLevel()->andWhere(['mall_id' => $params['mall_id']])->one();
  1370. $params['commission'] = $level->item_commission;
  1371. if (empty($level->item_commission_type)) {
  1372. $params['commission'] = bcmul(bcmul($params['commission'], $params['goods_price'], 2), 0.01, 2);
  1373. }
  1374. /**
  1375. * @var $goodsSetting ReservationServiceGoodsSetting
  1376. */
  1377. $goodsSetting = ReservationServiceGoodsSetting::getOne([
  1378. ['mall_id' => $params['mall_id']],
  1379. ['status' => StatusEnum::ENABLED],
  1380. ['item_id' => $params['goods_id']],
  1381. ['item_type' => 'goods'],
  1382. ['is_enable' => StatusEnum::ENABLED],
  1383. ['commission_type' => UserWalletService::WALLET_TYPE_COMMISSION]
  1384. ]);
  1385. if (!empty($goodsSetting)) {
  1386. $params['commission'] = $goodsSetting->commission;
  1387. if (!empty($goodsSetting->is_percent)) {
  1388. $params['commission'] = bcmul(bcmul($params['commission'], $params['goods_price'], 2), 0.01, 2);
  1389. }
  1390. }
  1391. if ($params['commission'] < 0) $params['commission'] = 0;
  1392. }
  1393. if (empty($params['tech_id'])) {
  1394. $params['is_match'] = StatusEnum::ENABLED;
  1395. }
  1396. $params['staff_user_id'] = $staff->user_id ?? 0;
  1397. $model = new ReservationServiceOrder();
  1398. $model->loadDefaultValues();
  1399. if (!$model->load($params, '') || !$model->save()) throw new \Exception($model->getErrorMessage());
  1400. // 记录数据
  1401. (new NoticeLogic())->send(['mall_id' => $params['mall_id'], 'id' => $params['order_id'], 'sms_key' => ReservationServiceEnum::SMS_KEY_RESERVE]);
  1402. return $model;
  1403. }
  1404. /**
  1405. * 核销记录
  1406. * @param int $mall_id
  1407. * @param array $params
  1408. * @return array|false|mixed|string|null
  1409. */
  1410. public function underwriterList(int $mall_id, array $params)
  1411. {
  1412. $where = [
  1413. ['mall_id' => $mall_id],
  1414. ['status' => StatusEnum::ENABLED],
  1415. ['staff_user_id' => $params['user_id']],
  1416. ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER, ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH]]
  1417. ];
  1418. $with = ['order' => function($query) {
  1419. $query->with(['detail']);
  1420. }, 'store' => function($query) {
  1421. $query->select('id, store_name, logo_img');
  1422. }];
  1423. $ret = ReservationServiceOrder::listPage([
  1424. 'where' => $where,
  1425. 'order' => 'id desc',
  1426. 'limit' => $params['limit'] ?? 10,
  1427. 'with' => $with
  1428. ]);
  1429. if (!empty(ReservationServiceOrder::getStaticError())) return ReservationServiceOrder::getStaticError();
  1430. return $ret;
  1431. }
  1432. /**
  1433. * 获取技师信息
  1434. * @param int $order_id
  1435. * @param $mall_id
  1436. * @return void
  1437. */
  1438. public function getStaffByOrderId(int $order_id, $mall_id)
  1439. {
  1440. $staff = ReservationServiceOrder::getOne([
  1441. ['order_id' => $order_id],
  1442. ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING,
  1443. ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER,
  1444. ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]],
  1445. ], true, ['staff' => function($query) use($mall_id) {
  1446. $with = [];
  1447. $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_STORE);
  1448. if ($is_install) {
  1449. $with = ['store' => function($query) {
  1450. $query->select('id, store_name, logo_img');
  1451. }];
  1452. }
  1453. $query->select('name, user_id, avatar, age, store_id')->with($with)->andwhere(['status' => StatusEnum::ENABLED]);
  1454. }], 'id desc', 'staff_user_id');
  1455. return !empty($staff['staff']) ? $staff['staff'] : null;
  1456. }
  1457. /**
  1458. * 全局调用
  1459. * @param array $params
  1460. * @return mixed
  1461. */
  1462. public function preview(array $params)
  1463. {
  1464. $response = $params['data'];
  1465. $input = $params['params'];
  1466. // 只能是一件商品
  1467. if (count($response['group_order_goods']) > 1 || empty($response['group_order_goods'][0]['goods'])) return $response;
  1468. if (count($response['group_order_goods'][0]['goods']) > 1) return $response;
  1469. $change_shipping_type_list = false;
  1470. foreach ($response['group_order_goods'][0]['goods'] as $good) {
  1471. if (!empty($good['reserve']) && $good['reserve']['reserve_type'] == StatusEnum::ENABLED) { // 仅限于家政服务
  1472. $good['reserve']['service_type'] = 1;
  1473. $change_shipping_type_list = true;
  1474. // switch ($good['reserve']['service_type']) {
  1475. // case 1:
  1476. // case 2:
  1477. // case 3:
  1478. foreach ($response['shipping_type_list'] as $key => $item) {
  1479. if ($key != $good['reserve']['service_type']) unset($response['shipping_type_list'][$key]);
  1480. if ($key > 2) unset($response['shipping_type_list'][$key]);
  1481. }
  1482. // break;
  1483. // }
  1484. }
  1485. }
  1486. // shipping_type_list
  1487. if (!empty($input['tech_id'])) {
  1488. $response['tech'] = $this->findByTech($input['tech_id'], $input['latitude'], $input['longitude'], $params['mall_id']);
  1489. }
  1490. if ($change_shipping_type_list) {
  1491. if (!empty($response['shipping_type_list'][1])) $response['shipping_type_list'][1] = '上门服务';
  1492. if (!empty($response['shipping_type_list'][2])) $response['shipping_type_list'][2] = '到店服务';
  1493. }
  1494. // 是否需要校验短信验证码
  1495. return $response;
  1496. }
  1497. /**
  1498. * @param int $tech_id
  1499. * @param $lat
  1500. * @param $lng
  1501. * @param $mall_id
  1502. * @return array|mixed
  1503. */
  1504. public function findByTech(int $tech_id, $lat, $lng, $mall_id)
  1505. {
  1506. // 判断预约服务是否安装门店
  1507. $with = [];
  1508. $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_STORE);
  1509. if ($is_install) {
  1510. $with = ['store' => function($query) {
  1511. $query->select("id, store_name, logo_img, shop_owner, shop_mobile, longitude, latitude, address, province_id, city_id, district_id");
  1512. }];
  1513. }
  1514. $tech = ReservationServiceUser::getOne([
  1515. ['id' => $tech_id]
  1516. ], true, $with, 'id asc', 'avatar, name, age, gender, store_id');
  1517. if (!empty($tech['store'])) {
  1518. $tech['store']['region'] = implode("", Region::find()->where(['id' =>
  1519. [$tech['store']['province_id'], $tech['store']['city_id'], $tech['store']['district_id']]])
  1520. ->select('name')->column());
  1521. $tech['store']['distance'] = LocationHelper::formatDistance((new LocationHelper())->getDistanceByGeo($lat, $lng,
  1522. $tech['store']['latitude'], $tech['store']['longitude']));
  1523. }
  1524. return $tech;
  1525. }
  1526. /**
  1527. * 执行退款
  1528. * @return void
  1529. * @throws \Exception
  1530. */
  1531. public function refund()
  1532. {
  1533. foreach (ReservationServiceOrder::find()->select('id, mall_id')->where(['is_refund' => StatusEnum::DISABLED])
  1534. ->andWhere(['>', 'refund_at', 0])->andWhere(['<=', 'refund_at', time()])
  1535. ->andWhere(['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING]])
  1536. ->each() as $item) {
  1537. // 这里操作退款
  1538. // 先申请退款
  1539. // 再执行退款
  1540. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER,
  1541. RabbitMqEnum::ORDER_QUEUE, ['mall_id' => $item->mall_id, 'id' => $item->id], self::class, 'createRefund');
  1542. // $this->createRefund(['mall_id' => $item->mall_id, 'id' => $item->id]);
  1543. }
  1544. }
  1545. /**
  1546. * 生成退款订单
  1547. * @param array $data
  1548. * @return bool
  1549. */
  1550. public function createRefund(array $data)
  1551. {
  1552. $rOrder = ReservationServiceOrder::findOne(['id' => $data['id']]);
  1553. if (empty($rOrder) || $rOrder->is_refund != StatusEnum::DISABLED) return true;
  1554. $order = Order::findOne(['id' => $rOrder->order_id]);
  1555. $order_detail_id = OrderDetail::find()->where(['order_id' => $order->id])->scalar();
  1556. // 申请退款
  1557. $t = Yii::$app->db->beginTransaction();
  1558. try {
  1559. $rOrder->is_refund = 1; // 退款中
  1560. if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage());
  1561. $params = [
  1562. 'order_detail_id' => $order_detail_id,
  1563. 'reason' => '预约订单超时自动售后退款',
  1564. 'remark' => '',
  1565. 'type' => RefundTypeEnum::MONEY,
  1566. 'refund_price' => $order->pay_money,
  1567. 'user_id' => $order->user_id,
  1568. 'mall_id' => $order->mall_id,
  1569. 'pic_list' => Json::encode([]),
  1570. ];
  1571. $res = OrderRefund::feedback($params);
  1572. if ($res === false) throw new \Exception(Order::getStaticError());
  1573. $t->commit();
  1574. $event = new \common\events\order\OrderRefundEvent();
  1575. $event->mall_id = $order->mall_id;
  1576. $order_detail['order_detail_id'] = $order_detail_id;
  1577. $order_detail['id'] = $res->id;
  1578. $order_detail['operator_id'] = 0;
  1579. $order_detail['operator_name'] = '系统自动申请';
  1580. Yii::$app->services->events->dispatch($event, $order_detail, $event->listeners);
  1581. \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_ORDER,
  1582. RabbitMqEnum::ORDER_QUEUE, ['mall_id' => $order->mall_id, 'id' => $res->id, 'r_order_id' => $rOrder->id],
  1583. self::class, 'refundPay');
  1584. // $this->refundPay(['mall_id' => $order->mall_id, 'id' => $res->id, 'r_order_id' => $rOrder->id]);
  1585. } catch (\Exception $e) {
  1586. $t->rollBack();
  1587. // var_dump($e->getMessage(), $e->getFile(), $e->getLine());
  1588. \Yii::error(FormatHelper::exception($e, __METHOD__));
  1589. return false;
  1590. }
  1591. return true;
  1592. }
  1593. /**
  1594. * 退款支付打款
  1595. * @param array $params
  1596. * @return bool
  1597. */
  1598. public function refundPay(array $params)
  1599. {
  1600. $rOrder = ReservationServiceOrder::findOne(['id' => $params['r_order_id']]);
  1601. if (empty($rOrder) || $rOrder->is_refund != StatusEnum::ENABLED) return true;
  1602. // 退货地址
  1603. $address = ['consignee' => '','mobile' => '','address' => ''];
  1604. // 换货物流信息
  1605. $express = ['saler_express' => '','saler_express_no' => '','customer_name' => ''];
  1606. $data = [
  1607. 'id' => $params['id'],
  1608. 'step_status' => RefundStatusEnum::STEP_6, // 直接打款操作
  1609. 'address' => $address,
  1610. 'express' => $express,
  1611. 'refund_reason' => '',
  1612. 'not_dec_fee' => StatusEnum::ENABLED, // 不需要手续费
  1613. ];
  1614. // 申请退款
  1615. $t = Yii::$app->db->beginTransaction();
  1616. try {
  1617. $rOrder->is_refund = 100; // 退款中
  1618. if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage());
  1619. $logic = new OrderRefundLogic();
  1620. $res = $logic->execute($rOrder->mall_id, $data);
  1621. if (!$res) throw new \Exception($logic->getError());
  1622. $t->commit();
  1623. } catch (\Exception $e) {
  1624. $t->rollBack();
  1625. // var_dump("1", $e->getMessage(), $e->getFile(), $e->getLine());
  1626. \Yii::error(FormatHelper::exception($e, __METHOD__));
  1627. return false;
  1628. }
  1629. return true;
  1630. }
  1631. /**
  1632. * 执行退款 废弃
  1633. * @param array $data
  1634. * @return bool
  1635. */
  1636. public function completeRefund(array $data)
  1637. {
  1638. $rOrder = ReservationServiceOrder::findOne(['id' => $data['id']]);
  1639. if (empty($rOrder) || $rOrder->is_refund != StatusEnum::DISABLED) return true;
  1640. $order = Order::findOne(['id' => $rOrder->order_id]);
  1641. // 申请退款
  1642. $t = Yii::$app->db->beginTransaction();
  1643. try {
  1644. $rOrder->is_refund = 100; // 退款中
  1645. if (!$rOrder->save()) throw new \Exception($rOrder->getErrorMessage());
  1646. $order_detail_id = OrderDetail::find()->where(['order_id' => $order->id])->scalar();
  1647. $wallet_type = UserWalletService::WALLET_TYPE_BALANCE;
  1648. if ($order->payment_type == PayTypeEnum::SCORE) $wallet_type = UserWalletService::WALLET_TYPE_SCORE;
  1649. OrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_6),
  1650. 'updated_at' => time()], ['order_id' => $order->id]);
  1651. $is_install = MallAddons::isInstall($order->mall_id, AddonsEnum::ADDONS_NAME_STORE);
  1652. Order::autoUpdateStatus($order);
  1653. if($is_install){
  1654. $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]);
  1655. if(!empty($store_order)){
  1656. $order['out_trade_no'] = $store_order['out_trade_no'];
  1657. StoreOrderDetail::updateAll(['is_feedback' => OrderStatusEnum::getIsFeedbackStatus(RefundStatusEnum::STEP_6), 'updated_at' => time()],
  1658. ['main_order_detail_id' => $order_detail_id]);
  1659. StoreOrder::autoUpdateStatus($store_order);
  1660. }
  1661. }
  1662. // 申请退款
  1663. if(in_array($order->payment_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])){
  1664. // 本地支付
  1665. // 如果是代付,那么就需要原路退回
  1666. $insert_wallet[] = [
  1667. 'mall_id' => $order->mall_id,
  1668. 'user_id' => $order->user_id,
  1669. 'is_frozen' => false,
  1670. 'wallet_type' => $wallet_type,// 暂定退回余额或积分
  1671. 'money' => $order->pay_money,
  1672. 'desc' => '预约订单超时自动售后退款',
  1673. 'source_table' => ReservationServiceOrder::tableName(),
  1674. 'source_table_id' => $rOrder->id,
  1675. 'from_type' => UserWalletEnum::REFUND,
  1676. 'capital_type' => UserWalletEnum::REFUND_ORDER,
  1677. 'order_no' => $order->order_no,
  1678. 'not_add_total' => true
  1679. ];
  1680. $res = UserWalletService::batchHandleByQueue($insert_wallet);
  1681. if (empty($res)) throw new \Exception(UserWalletService::getStaticError());
  1682. } elseif(in_array($order->payment_type,[PayTypeEnum::JOINPAY,PayTypeEnum::ALI,PayTypeEnum::JOINPAY_FAST_PAY,PayTypeEnum::WECHAT])){
  1683. //原路返回
  1684. $out_trade_no = $order['out_trade_no'];
  1685. $res = Yii::$app->services->pay->refund($order->pay_money,$order->pay_money, $out_trade_no, $order, '预约订单超时自动售后退款');
  1686. if ($res === false) throw new \Exception('退款失败');
  1687. }
  1688. elseif (
  1689. // 当res返回为false 说明没有相对于的退款方式
  1690. $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_ORDER_REFUND, $order->mall_id, [
  1691. 'id' => 0,
  1692. 'mall_id' => $order->mall_id,
  1693. 'refund' => [
  1694. 'order_id' => $order->id,
  1695. 'order_no' => $order->order_no,
  1696. 'refund_price' => $order->pay_money
  1697. ],
  1698. 'order_no' => $order['order_no'],
  1699. 'refund_order_no' => $order['order_no'],
  1700. 'params' => [],
  1701. 'pay_type' => $order->payment_type,
  1702. ])
  1703. ) {
  1704. // 当res不为空 进此判断
  1705. list($boolean, $msg) = $res;
  1706. if ($boolean === false) {
  1707. throw new \Exception($msg);
  1708. }
  1709. } else {
  1710. }
  1711. // 订单营销扣减返还
  1712. if(empty($order['store_id'])){
  1713. $res = OrderMarketing::deductBack($order['id'], [$order_detail_id],
  1714. [$order_detail_id],$order->mall_id,$order->user_id,'订单退款',
  1715. UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER);
  1716. if (!$res) throw new \Exception(OrderMarketing::getStaticError());
  1717. }else{
  1718. if(MallAddons::isInstall($order['mall_id'],AddonsEnum::ADDONS_NAME_STORE)){
  1719. $store_order = StoreOrder::findOne(['order_no'=>$order['order_no']]);
  1720. $store_order_detail_ids = array_column($store_order->detail,'id');
  1721. $store_order_detail_arr = array_column($store_order->detail,'id','main_order_detail_id');
  1722. $store_order_detail_id = $store_order_detail_arr[$order_detail_id]??0;
  1723. $res = StoreOrderMarketing::deductBack($store_order,$store_order_detail_ids,[$store_order_detail_id],$order->mall_id,
  1724. $order->user_id,'订单退款',UserWalletEnum::REFUND,UserWalletEnum::REFUND_ORDER);
  1725. if (!$res) throw new \Exception(StoreOrderMarketing::getStaticError());
  1726. }
  1727. }
  1728. $t->commit();
  1729. } catch (\Exception $e) {
  1730. $t->rollBack();
  1731. \Yii::error(FormatHelper::exception($e, __METHOD__));
  1732. return false;
  1733. }
  1734. return true;
  1735. }
  1736. /**
  1737. * 关闭预约订单
  1738. * @param int $mall_id
  1739. * @param int $order_id
  1740. * @return int
  1741. */
  1742. public function closed(int $mall_id, int $order_id)
  1743. {
  1744. return ReservationServiceOrder::updateAll(['service_status' => ReservationServiceEnum::RESERVE_ORDER_STATUS_CLOSED],
  1745. ['and', ['order_id' => $order_id], ['mall_id' => $mall_id], ['service_status' =>
  1746. [ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]]]);
  1747. }
  1748. /**
  1749. * 详情
  1750. * @param $params
  1751. * @return mixed
  1752. */
  1753. public function globalDetail($params)
  1754. {
  1755. if (empty($params['reserve'])) return $params['order'];
  1756. if ($params['order']['reserve']['reserve_type'] == StatusEnum::ENABLED) {
  1757. $params['order']['can_reserve'] = ReservationServiceOrder::find()->where(['order_id' => $params['order']['id']])
  1758. ->andWhere(['service_status' => [
  1759. ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL,
  1760. ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING,
  1761. ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER,
  1762. ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH,
  1763. ]])->count() == 0 ? StatusEnum::ENABLED : StatusEnum::DISABLED;
  1764. }
  1765. return $params['order'];
  1766. }
  1767. /**
  1768. * 列表
  1769. * @param $params
  1770. * @return mixed
  1771. */
  1772. public function globalList($params)
  1773. {
  1774. if (empty($params['reserve'])) return $params['order'];
  1775. if (!empty($params['order'])) {
  1776. foreach ($params['order'] as &$item) {
  1777. // 判断订单是否为预约订单
  1778. if ($item['reserve']['reserve_type'] == StatusEnum::ENABLED) {
  1779. $item['can_reserve'] = ReservationServiceOrder::find()->where(['order_id' => $item['id']])
  1780. ->andWhere(['service_status' => [
  1781. ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL,
  1782. ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING,
  1783. ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER,
  1784. ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH,
  1785. ]])->count() == 0 ? StatusEnum::ENABLED : StatusEnum::DISABLED;
  1786. }
  1787. if ($item['order_source']=='Reserve'){
  1788. $service_order = ReservationServiceOrder::find()->where(['order_id' => $item['id']])->one();
  1789. $item['staff_user_id'] = 0;
  1790. $item['nickname'] = '';
  1791. if(!empty($service_order['staff_user_id'])){
  1792. $user = User::findOne(['id'=>$service_order['staff_user_id']]);
  1793. $item['nickname'] = $user['nickname'];
  1794. $item['staff_user_id'] = $service_order['staff_user_id'];
  1795. }
  1796. }
  1797. }
  1798. }
  1799. return $params['order'];
  1800. }
  1801. /**
  1802. * 预约满员检测
  1803. * @param $goods_reserve_sku_id
  1804. * @param $store_id
  1805. * @param $date
  1806. * @return bool
  1807. * @throws \Exception
  1808. */
  1809. public function checkReserveFull($goods_reserve_sku_id,$store_id = 0,$date = null)
  1810. {
  1811. if (empty($date)) {
  1812. $time = time();
  1813. } else {
  1814. $time = strtotime($date . ':00');
  1815. }
  1816. $date = date('Y-m-d', $time);
  1817. $start_time = strtotime($date.' 00:00:00');
  1818. $end_time = strtotime($date.' 23:59:59');
  1819. if(empty($store_id)){
  1820. $query = OrderReserve::find()->where(['attr_id' => $goods_reserve_sku_id]);
  1821. $store_id = 0;
  1822. $class = GoodsReserveSku::class;
  1823. }else{
  1824. $query = StoreOrderReserve::find()->where(['attr_id' => $goods_reserve_sku_id]);
  1825. //门店
  1826. $class = StoreGoodsReserveSku::class;
  1827. }
  1828. $query->andWhere(['!=', 'order_status', -4]);
  1829. $goods_reserve_sku = $class::findOne(['id'=>$goods_reserve_sku_id]);
  1830. if(empty($goods_reserve_sku)){
  1831. throw new \Exception('预约商品不存在');
  1832. }
  1833. $counts = $query
  1834. ->andWhere(['>=', 'service_start_at', $start_time])->andWhere(['<=', 'service_start_at', $end_time])
  1835. ->andWhere(['store_id'=>$store_id])
  1836. ->count();
  1837. if ($goods_reserve_sku['reserve_max_buy'] > 0 && $counts >= $goods_reserve_sku['reserve_max_buy']) {
  1838. return false;
  1839. }
  1840. return true;
  1841. }
  1842. }