LocalDeliveryController.php 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. /**
  8. * @file LocalDeliveryController
  9. * @editor Created by vscode
  10. * @author WPing丶
  11. * @date 2023/07/06
  12. * @time 11:56:13
  13. *
  14. * 备注:同城配送服务端相关接口
  15. */
  16. namespace app\modules\client\controllers\v1;
  17. use app\constants\OptionSetting;
  18. use app\models\DeliveryInfo;
  19. use app\models\District;
  20. use app\models\Lg;
  21. use app\models\LocalDeliveryCash;
  22. use app\models\LocalDeliveryCourier;
  23. use app\models\LocalDeliveryCourierComment;
  24. use app\models\LocalDeliveryCourierCommentExt;
  25. use app\models\LocalDeliveryCourierTag;
  26. use app\models\LocalDeliveryFreight;
  27. use app\models\LocalDeliveryLog;
  28. use app\models\Option;
  29. use app\models\Order;
  30. use app\models\OrderDetail;
  31. use app\models\Store;
  32. use app\models\WorkerOrderExt;
  33. use app\modules\alliance\controllers\BaseController;
  34. use app\modules\admin\models\OrderListForm;
  35. use app\utils\OrderNo;
  36. use app\utils\Tools;
  37. use yii\helpers\Json;
  38. class LocalDeliveryController extends BaseController
  39. {
  40. //获取配送首页状态
  41. public function actionGetCourierInfo() {
  42. $saas_user = get_saas_user();
  43. $rider = LocalDeliveryCourier::find()->where(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2])->asArray()->one();
  44. if(!empty($rider)) {
  45. if (intval($rider['store_id']) === intval(get_store_id())) {
  46. $area = Json::decode($rider['area'], true);
  47. $village = District::findOne($area[0]['village_id']);
  48. $town = District::findOne($area[0]['town_id']);
  49. $district = District::findOne($area[0]['district_id']);
  50. $city = District::findOne($area[0]['city_id']);
  51. $province = District::findOne($area[0]['province_id']);
  52. if ($village) {
  53. $rider['area_name'] = $province->name . '/' . $city->name . '/' . $district->name . '/' . $town->name . '/' . $village->name;
  54. } elseif ($town) {
  55. $rider['area_name'] = $province->name . '/' . $city->name . '/' . $district->name . '/' . $town->name;
  56. } elseif ($district) {
  57. $rider['area_name'] = $province->name . '/' . $city->name . '/' . $district->name;
  58. } else {
  59. $rider['area_name'] = '';
  60. }
  61. } else {
  62. return $this->asJson([
  63. 'code' => 1,
  64. 'msg' => '非当前店铺骑手',
  65. 'data' => $rider,
  66. ]);
  67. }
  68. }else{
  69. $rider = LocalDeliveryCourier::find()->where(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 1, 'store_id' => get_store_id()])->asArray()->one();
  70. if($rider){
  71. $rider = [
  72. 'code' => 101,
  73. 'msg' => '正在审核,暂时无法操作',
  74. 'data' => $rider,
  75. ];
  76. } else {
  77. $rider = [
  78. 'code' => 100,
  79. 'msg' => '需要申请店铺骑手'
  80. ];
  81. }
  82. }
  83. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'store')['value'];
  84. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'pay', $local_type)['value'];
  85. $store_id = 0;
  86. if ($local_type === 'self_store') {
  87. $store_id = get_store_id();
  88. }
  89. //同城配送设置相关
  90. $values = Option::find()->where(['store_id' => $store_id,
  91. 'group' => OptionSetting::LOCAL_DELIVERY_GROUP_NAME, 'name' => OptionSetting::LOCAL_DELIVERY_SETTING])->select('value')->one();
  92. if($values){
  93. $local_setting = json_decode($values->value, true);
  94. }else{
  95. $local_setting = null;
  96. }
  97. return $this->asJson([
  98. 'code' => 0,
  99. 'msg' => 'success',
  100. 'data' => [
  101. 'courier' => $rider,
  102. 'local_setting' => $local_setting
  103. ]
  104. ]);
  105. }
  106. //抢单
  107. public function actionOrderBind()
  108. {
  109. $order_id = input_params('order_id');
  110. $type = input_params('type', 1);
  111. $saas_user = get_saas_user();
  112. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  113. if (!$courier) {
  114. return $this->asJson([
  115. 'code' => 1,
  116. 'msg' => '当前用户不是骑手',
  117. ]);
  118. }
  119. if($type == 2){
  120. $cacheV = WorkerOrderExt::cacheIgnoreOrderId($courier->id, $order_id);
  121. return $this->asJson([
  122. 'code' => 0,
  123. 'msg' => 'success',
  124. ]);
  125. }
  126. $cacheK = 'DeliveryTypeSelf_OrderBind' . $order_id;
  127. $cacheV = cache()->get($cacheK);
  128. if($cacheV){
  129. return $this->asJson([
  130. 'code' => 1,
  131. 'msg' => '抢单失败0,请稍后再试~',
  132. ]);
  133. }
  134. cache()->set($cacheK, 1, 10);
  135. $rider_id = $courier->id; //骑手ID
  136. $now_num = DeliveryInfo::find()->alias('di')
  137. ->leftJoin(['o' => Order::tableName()], 'di.order_no = o.order_no')
  138. ->where(['o.trade_status' => Order::ORDER_FLOW_SEND, 'is_local' => 1, 'rider_id' => $rider_id])
  139. ->count();
  140. if ($courier->max_num != 0 && $now_num >= $courier->max_num) {
  141. return $this->asJson([
  142. 'code' => 1,
  143. 'msg' => '当前配送订单已达到上限,请稍后再试',
  144. ]);
  145. }
  146. $t = \Yii::$app->db->beginTransaction();
  147. try{
  148. $order = Order::findOne($order_id);
  149. $delivery_info = DeliveryInfo::findOne(['order_no' => $order->order_no]);
  150. if (!$delivery_info) {
  151. $local_delivery_setting = Option::get(OptionSetting::LOCAL_DELIVERY_SETTING, get_store_id(), OptionSetting::LOCAL_DELIVERY_GROUP_NAME);
  152. $local_delivery_setting = json_decode($local_delivery_setting['value'], true);
  153. $default_time = time() + (($local_delivery_setting['default_time']['value'] ?? 0) * 60);
  154. $goods_list = OrderDetail::find()->where(['order_id' => $order_id, 'is_delete' => 0])
  155. ->select('num, total_price')->asArray()->all();
  156. foreach ($goods_list as &$goods_item) {
  157. $goods_item['price'] = $goods_item['total_price'] / $goods_item['num'];
  158. }
  159. $address_data = $order->address_data;
  160. $address_data = json_decode($address_data, true);
  161. $getFreight = LocalDeliveryFreight::getFreight(get_store_id(), [
  162. 'latitude' => $address_data['latitude'],
  163. 'longitude' => $address_data['longitude']
  164. ], $default_time, LocalDeliveryFreight::TYPE_STORE_LOCAL, $goods_list, LocalDeliveryFreight::IS_SCAN_YES);
  165. if($getFreight['code'] != 0){
  166. throw new \Exception($getFreight['msg']);
  167. }
  168. $delivery_info = new DeliveryInfo();
  169. $delivery_info->store_id = get_store_id();
  170. $delivery_info->order_no = $order->order_no;
  171. $delivery_info->fee = $getFreight['data'];
  172. $delivery_info->delivery_type = 0;
  173. $delivery_info->created_at = time();
  174. $delivery_info->is_local = DeliveryInfo::IS_LOCAL_YSE;
  175. $delivery_info->is_store_delivery_type = 1;
  176. $serial_num = DeliveryInfo::find()->where(['>','created_at',strtotime(date('Y-m-d'))])->orderBy('serial_num desc')->asArray()->one()['serial_num'];
  177. $delivery_info->serial_num = $serial_num > 0 ? $serial_num + 1 : 1;
  178. $delivery_info->save();
  179. }
  180. if (intval($delivery_info->is_store_delivery_type) === 0) {
  181. throw new \Exception('当前配送订单只能由平台配送员配送');
  182. }
  183. $delivery_info->rider_id = $rider_id;
  184. $delivery_info->rider_name = $courier->real_name;
  185. $delivery_info->rider_mobile = $courier->mobile;
  186. $delivery_info->local_status = DeliveryInfo::LOCAL_STATUS_WAITING;
  187. if (!$delivery_info->save()) {
  188. throw new \Exception('delivery_info保存失败' . array_shift($delivery_info->getFirstErrors()));
  189. }
  190. $order->send_time = time();
  191. $order->trade_status = Order::ORDER_FLOW_SEND;
  192. if (!$order->save()) {
  193. throw new \Exception('order保存失败' . array_shift($order->getFirstErrors()));
  194. }
  195. $t->commit();
  196. return $this->asJson([
  197. 'code' => 0,
  198. 'msg' => '操作成功',
  199. ]);
  200. } catch (\Exception $ex) {
  201. \Yii::error($ex);
  202. $t->rollBack();
  203. return $this->asJson([
  204. 'code' => 1,
  205. 'msg' => '操作失败,' . $ex->getMessage() . $ex->getLine(),
  206. ]);
  207. }
  208. }
  209. /**
  210. * 模块名:actionGetOrderList
  211. * 代码描述:获取订单列表
  212. * 作者:WPing丶
  213. * 请求方式:POST
  214. * 创建时间:2023/07/06 15:19:43
  215. * @param int status 1=新任务,2=待取货,3=配送中
  216. */
  217. public function actionGetOrderList()
  218. {
  219. $status = post_params('status'); //1=新任务,2=待取货,3=配送中,4=历史订单(已完成)
  220. $start_time = post_params('start_time');
  221. $end_time = post_params('end_time');
  222. $lng = input_params('lng');
  223. $lat = input_params('lat');
  224. $order_no = input_params('order_no');
  225. $order_id = input_params('order_id');
  226. $saas_user = get_saas_user();
  227. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  228. if (!$courier) {
  229. return $this->asJson([
  230. 'code' => 1,
  231. 'msg' => '当前用户不是骑手',
  232. ]);
  233. }
  234. if ($order_id) {
  235. $order = Order::findOne($order_id);
  236. if ($order) {
  237. $order_no = $order->order_no;
  238. }
  239. }
  240. $query = Order::find()->alias('o')
  241. ->leftJoin(['di' => DeliveryInfo::tableName()], 'o.order_no = di.order_no')
  242. ->where(['o.order_type' => [Order::ORDER_TYPE_STORE, 3], 'di.is_local' => 1])
  243. ->select('o.*, di.id d_order_id, di.fee,di.rider_id,di.rider_name,di.rider_mobile,di.arrive_time,di.rush_time,di.confirm_time,di.serial_num')->orderBy('o.created_at DESC');
  244. if (intval($courier->type) === 1) {
  245. $query->andWhere(['di.is_store_delivery_type' => 0]);
  246. } else {
  247. $query->andWhere(['di.is_store_delivery_type' => 1]);
  248. }
  249. switch ($status) {
  250. case 1:
  251. $query->andWhere([
  252. 'o.trade_status' => Order::ORDER_FLOW_NO_SEND,
  253. 'o.is_delete' => Order::IS_DELETE_FALSE,
  254. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_NO_SEND,
  255. 'di.rider_id' => 0,
  256. ])->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]]);
  257. $courierArea = json_decode($courier['area'], true);
  258. // $courierCity = $courierArea[0]['city_id'] ?? 0;
  259. $courierDistrict = $courierArea[0]['district_id'] ?? 0;
  260. if(empty($courierDistrict)){
  261. return $this->asJson([
  262. 'code' => 1,
  263. 'msg' => '请先配置自己的常驻地区',
  264. ]);
  265. }
  266. $query->andWhere(['o.district_id' => $courierDistrict]);
  267. $query->andWhere(['<', 'o.delivery_time', time() + 3600 * 1.5]);
  268. break;
  269. case 2:
  270. $query->andWhere([
  271. 'o.trade_status' => Order::ORDER_FLOW_SEND,
  272. 'o.is_delete' => Order::IS_DELETE_FALSE,
  273. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_WAITING,
  274. 'di.rider_id' => $courier->id,
  275. ])->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]]);
  276. break;
  277. case 3:
  278. $query->andWhere([
  279. 'o.trade_status' => Order::ORDER_FLOW_SEND,
  280. 'o.is_delete' => Order::IS_DELETE_FALSE,
  281. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_SENDING,
  282. 'di.rider_id' => $courier->id,
  283. ])->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]]);
  284. break;
  285. case 4:
  286. $query->andWhere([
  287. // 'o.trade_status' => Order::ORDER_FLOW_CONFIRM,//暂时注释
  288. 'o.is_delete' => Order::IS_DELETE_FALSE,
  289. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_CONFIRM,
  290. 'di.rider_id' => $courier->id,
  291. ])->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]]);
  292. break;
  293. default:
  294. return $this->asJson([
  295. 'code' => 1,
  296. 'msg' => 'status参数错误'
  297. ]);
  298. break;
  299. }
  300. if ($start_time) {
  301. $query->andWhere(['>=', 'di.confirm_time', strtotime($start_time . ' 00:00:00')]);
  302. }
  303. if ($end_time) {
  304. $query->andWhere(['<=', 'di.confirm_time', strtotime($end_time . ' 23:59:59')]);
  305. }
  306. if ($order_no) {
  307. $query->andWhere(['di.order_no' => $order_no]);
  308. }
  309. // $sql = $query->createCommand()->getRawSql();
  310. // return $this->asJson([
  311. // 'code' => 0,
  312. // 'msg' => 'success',
  313. // 'data' => $sql
  314. // ]);
  315. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'store')['value'];
  316. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'pay', $local_type)['value'];
  317. $store_id = 0;
  318. if ($local_type === 'self_store') {
  319. $store_id = get_store_id();
  320. }
  321. debug_log($query->createCommand()->getRawSql(), 'courier.log');
  322. $setting = json_decode(Option::get(OptionSetting::LOCAL_DELIVERY_SETTING, $store_id, '', '{}')['value'], true);
  323. $list = pagination_make($query);
  324. foreach ($list['list'] as &$val) {
  325. $form = new OrderListForm();
  326. $val['goods_list'] = $form->getOrderGoodsList($val['id']);
  327. $store = Store::findOne($val['store_id']);
  328. $val['store_name'] = $val['store_id'] > 0 ? $store->name : '';
  329. $address_data = json::decode($val['address_data'], true);
  330. $val['user_latitude'] = $address_data['latitude'];
  331. $val['user_longitude'] = $address_data['longitude'];
  332. $val['store_latitude'] = $store->latitude;
  333. $val['store_longitude'] = $store->longitude;
  334. $val['distance'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $store->latitude, $store->longitude);
  335. $val['contact_tel'] = $store->contact_tel;
  336. $val['store_address'] = $store->address;
  337. if($lng){
  338. $val['distance1'] = Tools::getDistance($store->latitude, $store->longitude, $lat, $lng);
  339. $val['distance2'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $lat, $lng);
  340. }else{
  341. $val['distance1'] = '';
  342. $val['distance2'] = '';
  343. }
  344. if($val['mch_id']){
  345. $mch = \app\models\Mch::findOne($val['mch_id']);
  346. $val['store_name'] .= '-入驻商:' . $mch->name;
  347. $val['store_latitude'] = $mch->latitude;
  348. $val['store_longitude'] = $mch->longitude;
  349. $val['distance'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $mch->latitude, $mch->longitude);
  350. $val['contact_tel'] = $mch->tel;
  351. $val['store_address'] = $mch->address;
  352. if($lng){
  353. $val['distance1'] = Tools::getDistance($mch->latitude, $mch->longitude, $lat, $lng);
  354. }
  355. }
  356. $default_cost = 0;
  357. if(!empty($setting['default_cost']) && !empty($setting['default_cost']['value'])){
  358. $default_cost = $setting['default_cost']['value'];
  359. }
  360. if($default_cost == -1){
  361. $default_cost = $val['fee'];
  362. }
  363. $val['fee_cost'] = $default_cost;
  364. if (in_array($status, [2, 3])) {
  365. $delivery_info = DeliveryInfo::findOne($val['d_order_id']);
  366. if ($delivery_info) {
  367. if ($lat > 0) {
  368. $delivery_info->last_latitude = $lat;
  369. }
  370. if ($lng > 0) {
  371. $delivery_info->last_longitude = $lng;
  372. }
  373. $delivery_info->save();
  374. }
  375. }
  376. }
  377. $data = [
  378. 'data' => $list['list'],
  379. 'pageNo' => $list['pageNo'],
  380. 'totalCount' => $list['totalCount']
  381. ];
  382. return $this->asJson([
  383. 'code' => 0,
  384. 'msg' => 'success',
  385. 'data' => $data
  386. ]);
  387. }
  388. //扫码获取订单
  389. public function actionScanGetOrder() {
  390. $lng = input_params('lng');
  391. $lat = input_params('lat');
  392. $order_no = input_params('order_no');
  393. $order_id = input_params('order_id');
  394. $saas_user = get_saas_user();
  395. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  396. if (!$courier) {
  397. return $this->asJson([
  398. 'code' => 1,
  399. 'msg' => '当前用户不是骑手',
  400. ]);
  401. }
  402. if ($order_id) {
  403. $order = Order::findOne($order_id);
  404. if ($order) {
  405. $order_no = $order->order_no;
  406. }
  407. }
  408. $query = Order::find()
  409. ->where(['order_type' => Order::ORDER_TYPE_STORE])
  410. ->andWhere(['OR', ['trade_status' => Order::ORDER_FLOW_NO_SEND], ['trade_status' => [Order::ORDER_FLOW_DEFAULT, Order::ORDER_FLOW_NO_SEND], 'pay_type' => Order::PAY_TYPE_COD]])//增加扫码后可以抢其他类型(快递、自提、收银台等)的订单逻辑
  411. ->select('id, order_no, store_id, total_price, pay_price, name, mobile, address, created_at, trade_status, delivery_time, pay_time, address_data, remark')->orderBy('created_at DESC');
  412. if ($order_no) {
  413. $query->andWhere(['order_no' => $order_no]);
  414. }
  415. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'store')['value'];
  416. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'pay', $local_type)['value'];
  417. $store_id = get_store_id();
  418. $setting = json_decode(Option::get(OptionSetting::LOCAL_DELIVERY_SETTING, $store_id, '', '{}')['value'], true);
  419. $list = pagination_make($query);
  420. foreach ($list['list'] as &$val) {
  421. $form = new OrderListForm();
  422. $val['goods_list'] = $form->getOrderGoodsList($val['id']);
  423. $store = Store::findOne($val['store_id']);
  424. $val['store_name'] = $val['store_id'] > 0 ? $store->name : '';
  425. $address_data = json::decode($val['address_data'], true);
  426. $val['user_latitude'] = $address_data['latitude'];
  427. $val['user_longitude'] = $address_data['longitude'];
  428. $delivery_info = DeliveryInfo::findOne(['order_no' => $val['order_no']]);
  429. // di.id d_order_id, di.fee,di.rider_id,di.rider_name,di.rider_mobile,di.arrive_time,di.rush_time,di.confirm_time,di.serial_num
  430. $val['d_order_id'] = $delivery_info->id ?? 0;
  431. $val['fee'] = $delivery_info->fee ?? null;
  432. $val['rider_id'] = $delivery_info->rider_id ?? '';
  433. $val['rider_name'] = $delivery_info->rider_name ?? '';
  434. $val['rider_mobile'] = $delivery_info->rider_mobile ?? '';
  435. $val['arrive_time'] = $delivery_info->arrive_time ?? '';
  436. $val['rush_time'] = $delivery_info->rush_time ?? '';
  437. $val['confirm_time'] = $delivery_info->confirm_time ?? '';
  438. $val['serial_num'] = $delivery_info->serial_num ?? '';
  439. if ($val['delivery_time'] <= 0) {
  440. $val['delivery_time'] = $val['created_at'] + (($setting['default_time']['value'] ?? 0) * 60);
  441. }
  442. if (!isset($val['fee'])) {
  443. $local_delivery_setting = Option::get(OptionSetting::LOCAL_DELIVERY_SETTING, $store_id, OptionSetting::LOCAL_DELIVERY_GROUP_NAME);
  444. $local_delivery_setting = json_decode($local_delivery_setting['value'], true);
  445. $default_time = time() + (($local_delivery_setting['default_time']['value'] ?? 0) * 60);
  446. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, $this->store_id, 'store')['value'];
  447. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, $this->store_id, 'pay', $local_type)['value'];
  448. $type = 0;
  449. $goods_list = OrderDetail::find()->where(['order_id' => $val['id'], 'is_delete' => 0])
  450. ->select('num, total_price')->asArray()->all();
  451. foreach ($goods_list as &$goods_item) {
  452. $goods_item['price'] = $goods_item['total_price'] / $goods_item['num'];
  453. }
  454. $getFreight = LocalDeliveryFreight::getFreight($store_id, [
  455. 'latitude' => $address_data['latitude'],
  456. 'longitude' => $address_data['longitude']
  457. ], $default_time, LocalDeliveryFreight::TYPE_STORE_LOCAL, $goods_list, LocalDeliveryFreight::IS_SCAN_YES);
  458. if($getFreight['code'] != 0){
  459. return $getFreight;
  460. }
  461. $val['fee'] = $getFreight['data'];
  462. }
  463. $val['store_latitude'] = $store->latitude;
  464. $val['store_longitude'] = $store->longitude;
  465. $val['distance'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $store->latitude, $store->longitude);
  466. $val['contact_tel'] = $store->contact_tel;
  467. $val['store_address'] = $store->address;
  468. if($lng){
  469. $val['distance1'] = Tools::getDistance($store->latitude, $store->longitude, $lat, $lng);
  470. $val['distance2'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $lat, $lng);
  471. }else{
  472. $val['distance1'] = '';
  473. $val['distance2'] = '';
  474. }
  475. $default_cost = 0;
  476. if(!empty($setting['default_cost']) && !empty($setting['default_cost']['value'])){
  477. $default_cost = $setting['default_cost']['value'];
  478. }
  479. if($default_cost == -1){
  480. $default_cost = $val['fee'];
  481. }
  482. $val['fee_cost'] = $default_cost;
  483. }
  484. $data = [
  485. 'data' => $list['list'],
  486. 'pageNo' => $list['pageNo'],
  487. 'totalCount' => $list['totalCount']
  488. ];
  489. return $this->asJson([
  490. 'code' => 0,
  491. 'msg' => 'success',
  492. 'data' => $data
  493. ]);
  494. }
  495. /**
  496. * 模块名:actionCourierStatus
  497. * 代码描述:骑手上下线
  498. * 作者:WPing丶
  499. * 请求方式:POST
  500. * 创建时间:2023/07/06 18:20:19
  501. * @param int status 0=离线 1=在线
  502. */
  503. public function actionCourierStatus()
  504. {
  505. $status = (int)post_params('status'); //0=离线 1=在线
  506. if ($status != 0 && $status != 1) {
  507. return $this->asJson([
  508. 'code' => 1,
  509. 'msg' => 'status参数错误',
  510. ]);
  511. }
  512. $saas_user = get_saas_user();
  513. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  514. if (!$courier) {
  515. return $this->asJson([
  516. 'code' => 1,
  517. 'msg' => '当前用户不是骑手',
  518. ]);
  519. }
  520. if ($courier->status == $status) {
  521. $msg = $status == 0 ? '已离线,请勿重复操作' : '已上线,请勿重复操作';
  522. return $this->asJson([
  523. 'code' => 1,
  524. 'msg' => $msg,
  525. 'status' => $status
  526. ]);
  527. }
  528. if ($status == 0) { //离线时需要查询一下,是否有未配送订单
  529. $count = Order::find()->alias('o')
  530. ->leftJoin(['di' => DeliveryInfo::tableName()], 'o.order_no = di.order_no')
  531. ->where(['o.order_type' => Order::ORDER_TYPE_STORE, 'di.is_local' => 1])
  532. ->andWhere([
  533. 'o.trade_status' => Order::ORDER_FLOW_SEND,
  534. 'o.is_delete' => Order::IS_DELETE_FALSE,
  535. 'di.rider_id' => $courier->id,
  536. ])
  537. ->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]])
  538. ->andWhere([
  539. 'or',
  540. ['di.local_status' => DeliveryInfo::LOCAL_STATUS_WAITING],
  541. ['di.local_status' => DeliveryInfo::LOCAL_STATUS_SENDING],
  542. ])
  543. ->select('o.id,o.order_no,o.store_id,o.total_price,o.pay_price,o.name,o.mobile,o.address,o.created_at,o.trade_status,o.delivery_time,o.pay_time,o.address_data,di.fee,di.rider_id,di.rider_name,di.rider_mobile,di.serial_num')
  544. ->count();
  545. if ($count > 0) {
  546. $courier->status = $status;
  547. if (!$courier->save()) {
  548. return $this->asJson([
  549. 'code' => 1,
  550. 'msg' => $courier->errors[0],
  551. ]);
  552. }
  553. return $this->asJson([
  554. 'code' => 0,
  555. 'msg' => '已下线停止接单,请继续完成未完成订单。',
  556. ]);
  557. }
  558. }
  559. $courier->status = $status;
  560. if (!$courier->save()) {
  561. return $this->asJson([
  562. 'code' => 1,
  563. 'msg' => $courier->errors[0],
  564. ]);
  565. }
  566. return $this->asJson([
  567. 'code' => 0,
  568. 'msg' => '操作成功',
  569. ]);
  570. }
  571. /**
  572. * 模块名:actionArriveStore
  573. * 代码描述:上报到店
  574. * 作者:WPing丶
  575. * 请求方式:POST
  576. * 创建时间:2023/07/06 19:13:17
  577. * @param int id 订单ID
  578. */
  579. public function actionArriveStore()
  580. {
  581. $id = post_params('id'); //订单ID
  582. $saas_user = get_saas_user();
  583. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  584. if (!$courier) {
  585. return $this->asJson([
  586. 'code' => 1,
  587. 'msg' => '当前用户不是骑手',
  588. ]);
  589. }
  590. $order = Order::findOne($id);
  591. $delivery_info = DeliveryInfo::findOne(['order_no' => $order->order_no]);
  592. if ($delivery_info->rider_id != $courier->id) {
  593. return $this->asJson([
  594. 'code' => 1,
  595. 'msg' => '订单骑手不一致,请刷新列表'
  596. ]);
  597. }
  598. if ($delivery_info->local_status != DeliveryInfo::LOCAL_STATUS_WAITING) {
  599. return $this->asJson([
  600. 'code' => 1,
  601. 'msg' => '订单状态发生变化,请刷新列表',
  602. ]);
  603. }
  604. $delivery_info->local_status = DeliveryInfo::LOCAL_STATUS_SENDING;
  605. $delivery_info->arrive_time = time();
  606. if (!$delivery_info->save()) {
  607. return $this->asJson([
  608. 'code' => 1,
  609. 'msg' => $delivery_info->errors[0],
  610. ]);
  611. }
  612. return $this->asJson([
  613. 'code' => 0,
  614. 'msg' => '取货成功',
  615. ]);
  616. }
  617. /**
  618. * 模块名:actionOrderConfirm
  619. * 代码描述:订单完成
  620. * 作者:WPing丶
  621. * 请求方式:POST
  622. * 创建时间:2023/07/06 19:13:17
  623. * @param int id 订单ID
  624. */
  625. public function actionOrderConfirm()
  626. {
  627. $id = post_params('id'); //订单ID
  628. $saas_user = get_saas_user();
  629. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  630. if (!$courier) {
  631. return $this->asJson([
  632. 'code' => 1,
  633. 'msg' => '当前用户不是骑手',
  634. ]);
  635. }
  636. $order = Order::findOne($id);
  637. $delivery_info = DeliveryInfo::findOne(['order_no' => $order->order_no]);
  638. if ($delivery_info->rider_id != $courier->id) {
  639. return $this->asJson([
  640. 'code' => 1,
  641. 'msg' => '订单骑手不一致,请刷新列表',
  642. ]);
  643. }
  644. if ($delivery_info->local_status != DeliveryInfo::LOCAL_STATUS_SENDING) {
  645. return $this->asJson([
  646. 'code' => 1,
  647. 'msg' => '订单状态发生变化,请刷新列表',
  648. ]);
  649. }
  650. $t = \Yii::$app->db->beginTransaction(); //开始事务
  651. $delivery_info->local_status = DeliveryInfo::LOCAL_STATUS_CONFIRM;
  652. $delivery_info->confirm_time = time();
  653. if (!$delivery_info->save()) {
  654. $t->rollBack(); //事务回滚
  655. return $this->asJson([
  656. 'code' => 1,
  657. 'msg' => $delivery_info->errors[0],
  658. ]);
  659. }
  660. $store_id = 0;
  661. if (intval($delivery_info->is_store_delivery_type)) {
  662. $store_id = get_store_id();
  663. }
  664. $set = Option::get(OptionSetting::LOCAL_DELIVERY_SETTING, $store_id, OptionSetting::LOCAL_DELIVERY_GROUP_NAME, '{}')['value'];
  665. $local_setting = json_decode($set, true);
  666. if($local_setting['confirm_type'] && $local_setting['confirm_type']['value']){
  667. $order->trade_status = Order::ORDER_FLOW_CONFIRM;
  668. $order->confirm_time = time();
  669. if (!$order->save()) {
  670. $t->rollBack(); //事务回滚
  671. return $this->asJson([
  672. 'code' => 1,
  673. 'msg' => array_shift($order->getFirstErrors()),
  674. ]);
  675. }
  676. // /* 骑手完成订单后发放收入 */
  677. if ($store_id > 0) {
  678. $local_setting['default_cost']['value'] = -1;
  679. }
  680. $amount = (float)$local_setting['default_cost']['value'] == -1 ? $delivery_info->fee : (float)$local_setting['default_cost']['value'];
  681. $log = LocalDeliveryLog::saveLog($saas_user->id, $amount, 1, 1, $id, "骑手配送收入:" . $amount . "元");
  682. if (!$log) {
  683. $t->rollBack(); //事务回滚
  684. return $this->asJson([
  685. 'code' => 1,
  686. 'msg' => '发放骑手佣金报错',
  687. ]);
  688. }
  689. }
  690. $t->commit(); //事务执行
  691. return $this->asJson([
  692. 'code' => 0,
  693. 'msg' => '订单已完成',
  694. ]);
  695. }
  696. /**
  697. * 模块名:actionSetting
  698. * 代码描述:骑手设置
  699. * 作者:WPing丶
  700. * 请求方式:POST
  701. * 创建时间:2023/07/06 20:38:45
  702. * @param int max_num
  703. */
  704. public function actionSetting()
  705. {
  706. $params = post_params(); //设置项
  707. $saas_user = get_saas_user();
  708. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  709. if (!$courier) {
  710. return $this->asJson([
  711. 'code' => 1,
  712. 'msg' => '当前用户不是骑手',
  713. ]);
  714. }
  715. if (array_key_exists('max_num', $params)) {
  716. $courier->max_num = $params['max_num'];
  717. }
  718. if (array_key_exists('work_time', $params)) {
  719. $courier->work_time = $params['work_time'];
  720. }
  721. if (array_key_exists('is_auto', $params)) {
  722. $courier->is_auto = $params['is_auto'];
  723. }
  724. // if (array_key_exists('store_id', $params)) {
  725. // $courier->store_id = $params['store_id'];
  726. // }
  727. if (array_key_exists('real_name', $params)) {
  728. $courier->real_name = $params['real_name'];
  729. }
  730. if (array_key_exists('real_code', $params)) {
  731. $courier->real_code = $params['real_code'];
  732. }
  733. if (array_key_exists('avatar', $params)) {
  734. $courier->avatar = $params['avatar'];
  735. }
  736. if (array_key_exists('area', $params)) {
  737. $courier->area = $params['area'];
  738. }
  739. if (!$courier->save()) {
  740. return $this->asJson([
  741. 'code' => 1,
  742. 'msg' => $courier->errors[0],
  743. ]);
  744. }
  745. return $this->asJson([
  746. 'code' => 0,
  747. 'msg' => '修改成功',
  748. ]);
  749. }
  750. /**
  751. * 模块名:actionTotalOrder
  752. * 代码描述:订单统计
  753. * 作者:WPing丶
  754. * 请求方式:GET
  755. * 创建时间:2023/07/06 15:19:43
  756. * @param int start_time 时间范围
  757. * @param int end_time 时间范围
  758. */
  759. public function actionTotalOrder()
  760. {
  761. $start_time = get_params('start_time', get_params('begin_time'));
  762. $end_time = get_params('end_time');
  763. $saas_user = get_saas_user();
  764. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  765. if (!$courier) {
  766. return $this->asJson([
  767. 'code' => 1,
  768. 'msg' => '当前用户不是骑手',
  769. ]);
  770. }
  771. $query = Order::find()->alias('o')
  772. ->leftJoin(['di' => DeliveryInfo::tableName()], 'o.order_no = di.order_no')
  773. ->where(['o.order_type' => Order::ORDER_TYPE_STORE, 'di.is_local' => 1])
  774. ->select('o.id,o.order_no,o.store_id,o.total_price,o.pay_price,o.name,o.mobile,o.address,o.created_at,o.trade_status,o.delivery_time,o.pay_time,o.address_data,o.remark,di.fee,di.rider_id,di.rider_name,di.rider_mobile,di.arrive_time,di.rush_time,di.confirm_time,di.serial_num')->orderBy('o.created_at DESC');
  775. if ($start_time) {
  776. $query->andWhere(['>=', 'di.confirm_time', strtotime($start_time . ' 00:00:00')]);
  777. }
  778. if ($end_time) {
  779. $query->andWhere(['<=', 'di.confirm_time', strtotime($end_time . ' 23:59:59')]);
  780. }
  781. //完成订单
  782. $confirm_query = clone $query;
  783. $confirm_query->andWhere([
  784. 'o.trade_status' => Order::ORDER_FLOW_CONFIRM,
  785. 'o.is_delete' => Order::IS_DELETE_FALSE,
  786. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_CONFIRM,
  787. 'di.rider_id' => $courier->id,
  788. ])->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]]);
  789. $list = pagination_make($confirm_query);
  790. $total_distance = 0;
  791. foreach ($list['list'] as &$val) {
  792. $form = new OrderListForm();
  793. $val['goods_list'] = $form->getOrderGoodsList($val['id']);
  794. $store = Store::findOne($val['store_id']);
  795. $val['store_name'] = $val['store_id'] > 0 ? $store->name : '';
  796. $address_data = json::decode($val['address_data'], true);
  797. $val['user_latitude'] = $address_data['latitude'];
  798. $val['user_longitude'] = $address_data['longitude'];
  799. $val['store_latitude'] = $store->latitude;
  800. $val['store_longitude'] = $store->longitude;
  801. $val['distance'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $store->latitude, $store->longitude);
  802. $val['contact_tel'] = $store->contact_tel;
  803. $val['store_address'] = $store->address;
  804. //处理距离
  805. $distance_str = $val['distance'];
  806. if (strpos($distance_str, 'km') !== false) {
  807. // 如果包含 'km' 则将字符串转换为浮点数并乘以 1000
  808. $distance = (float) str_replace('km', '', $distance_str) * 1000;
  809. } elseif (strpos($distance_str, 'm') !== false) {
  810. // 如果包含 'm' 则将字符串转换为整数
  811. $distance = (int) str_replace('m', '', $distance_str);
  812. }
  813. $distance = bcdiv($distance, 1000, 2);
  814. $total_distance += $distance;
  815. }
  816. $confirm_data = [
  817. 'q' => $confirm_query->createCommand()->getRawSql(),
  818. 'data' => $list['list'],
  819. 'pageNo' => $list['pageNo'],
  820. 'totalCount' => $list['totalCount']
  821. ];
  822. //取消订单
  823. $cancel_query = clone $query;
  824. $cancel_query->andWhere([
  825. 'o.trade_status' => Order::ORDER_FLOW_CANCEL,
  826. 'o.is_delete' => Order::IS_DELETE_FALSE,
  827. 'di.rider_id' => $courier->id,
  828. ]);
  829. $list = pagination_make($cancel_query);
  830. foreach ($list['list'] as &$val) {
  831. $form = new OrderListForm();
  832. $val['goods_list'] = $form->getOrderGoodsList($val['id']);
  833. $store = Store::findOne($val['store_id']);
  834. $val['store_name'] = $val['store_id'] > 0 ? $store->name : '';
  835. $address_data = json::decode($val['address_data'], true);
  836. $val['user_latitude'] = $address_data['latitude'];
  837. $val['user_longitude'] = $address_data['longitude'];
  838. $val['store_latitude'] = $store->latitude;
  839. $val['store_longitude'] = $store->longitude;
  840. $val['distance'] = Tools::getDistance($address_data['latitude'], $address_data['longitude'], $store->latitude, $store->longitude);
  841. $val['contact_tel'] = $store->contact_tel;
  842. $val['store_address'] = $store->address;
  843. }
  844. $cancel_data = [
  845. 'data' => $list['list'],
  846. 'pageNo' => $list['pageNo'],
  847. 'totalCount' => $list['totalCount']
  848. ];
  849. //统计
  850. $total = [
  851. 'confirm_num' => $confirm_data['totalCount'], //完成订单数
  852. 'cancel_num' => $cancel_data['totalCount'], //取消订单数
  853. 'total_distance' => bcdiv($total_distance, 1)
  854. ];
  855. return $this->asJson([
  856. 'code' => 0,
  857. 'msg' => 'success',
  858. 'data' => [
  859. 'confirm_list' => $confirm_data, //已完成订单列表
  860. 'cancel_list' => $cancel_data, //已取消订单列表
  861. 'total' => $total,
  862. ]
  863. ]);
  864. }
  865. /**
  866. * 模块名:actionCashInfo
  867. * 代码描述:提现基础设置
  868. * 作者:WPing丶
  869. * 请求方式:POST
  870. * 创建时间:2023/07/11 09:32:30
  871. */
  872. public function actionCashInfo()
  873. {
  874. $saas_user = get_saas_user();
  875. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  876. if (!$courier) {
  877. return $this->asJson([
  878. 'code' => 1,
  879. 'msg' => '当前用户不是骑手',
  880. ]);
  881. }
  882. //今日收入
  883. $today_money = LocalDeliveryLog::find()->where(['saas_user_id' => $saas_user->id, 'log_type' => 1])->andWhere(['>' ,'order_id', 0])->andWhere(['>', 'created_at', strtotime(date('Y-m-d'))])->select('sum(amount) as today_money')->asArray()->all();
  884. //今日订单数
  885. $today_order = LocalDeliveryLog::find()->where(['saas_user_id' => $saas_user->id, 'log_type' => 1])->andWhere(['>' ,'order_id', 0])->andWhere(['>', 'created_at', strtotime(date('Y-m-d'))])->count();
  886. //今日提现
  887. // $today_cash = LocalDeliveryLog::find()->where(['saas_user_id' => $saas_user->id, 'log_type' => 2])->andWhere(['>', 'created_at', strtotime(date('Y-m-d'))])->select('sum(amount) as today_cash')->asArray()->all();
  888. $today_cash = LocalDeliveryCash::find()->where(['saas_user_id' => $saas_user->id])->andWhere(['<>' ,'status', 2])->andWhere(['>', 'created_at', strtotime(date('Y-m-d'))])->select('sum(price) as today_cash')->asArray()->all();
  889. //同城配送设置相关
  890. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'store')['value'];
  891. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'pay', $local_type);
  892. $store_id = $local_type['value'] === 'self_store' ? get_store_id() : 0;
  893. $values = Option::find()->where([
  894. 'store_id' => $store_id,
  895. 'group' => OptionSetting::LOCAL_DELIVERY_GROUP_NAME, 'name' => OptionSetting::LOCAL_DELIVERY_SETTING
  896. ])->select('value')->one();
  897. $local_setting = json_decode($values->value, true);
  898. if ($store_id > 0) {
  899. (float)$local_setting['default_cost']['value'] = -1;
  900. }
  901. //今日未到账收入(配送中)
  902. $query = Order::find()->alias('o')
  903. ->leftJoin(['di' => DeliveryInfo::tableName()], 'o.order_no = di.order_no')
  904. ->where(['o.order_type' => Order::ORDER_TYPE_STORE, 'di.is_local' => 1])
  905. ->andWhere([
  906. 'o.trade_status' => Order::ORDER_FLOW_SEND,
  907. 'o.is_delete' => Order::IS_DELETE_FALSE,
  908. 'di.local_status' => DeliveryInfo::LOCAL_STATUS_SENDING,
  909. 'di.rider_id' => $courier->id,
  910. ])
  911. ->andWhere(['or', ['o.is_pay' => Order::IS_PAY_TRUE], ['o.pay_type' => Order::PAY_TYPE_COD]])
  912. ->andWhere(['>', 'di.created_at', strtotime(date('Y-m-d'))]);
  913. if ((float)$local_setting['default_cost']['value'] == -1) {
  914. $frozen_money = $query->select('sum(di.fee) as frozen_money')->asArray()->all()['frozen_money'];
  915. } else {
  916. $frozen_money = bcmul((float)$local_setting['default_cost']['value'], $query->count(), 2);
  917. }
  918. return $this->asJson([
  919. 'code' => 0,
  920. 'data' => [
  921. 'money' => $courier->money ?: 0, //账户余额
  922. 'total_money' => $courier->total_money ?: 0, //账户总收入
  923. 'today_money' => $today_money[0]['today_money'] ?: 0, //今日收入
  924. 'today_cash' => $today_cash[0]['today_cash'] ?: 0, //今日提现支出
  925. 'today_order' => $today_order ?: 0, //今日订单数
  926. 'frozen_money' => $frozen_money ?: 0, //未到账
  927. 'service_charge' => $local_setting['cash_service_charge']['value'] ?: 0, //提现手续费
  928. 'pay_type_list' => $local_setting['pay_type']['value'],
  929. 'data' => LocalDeliveryLog::find()->alias('l')->where(['l.saas_user_id' => $saas_user->id])->orderBy('l.id DESC')->limit(3)->asArray()->all(),
  930. ],
  931. 'msg' => 'success',
  932. ]);
  933. }
  934. /**
  935. * 模块名:actionCashList
  936. * 代码描述:提现记录
  937. * 作者:WPing丶
  938. * 请求方式:POST
  939. * 创建时间:2023/07/11 11:04:47
  940. * @param int id
  941. * @param string str
  942. * @param bool bool
  943. */
  944. public function actionCashList()
  945. {
  946. $status = get_params('status');
  947. $saas_user = get_saas_user();
  948. $query = LocalDeliveryCash::find()->where(['saas_user_id' => $saas_user->id, 'is_delete' => 0]);
  949. if ($status > -1) { //状态,0:待审核,1:审核通过,2:审核驳回
  950. $query->andWhere(['status' => $status]);
  951. }
  952. $query->orderBy('id DESC');
  953. $pagination = pagination_make($query);
  954. $list = $pagination['list'];
  955. foreach ($list as &$value) {
  956. $value['created_at'] = $value['created_at'] > 0 ? date('Y-m-d H:i:s', $value['created_at']) : '';
  957. $value['updated_at'] = $value['updated_at'] > 0 ? date('Y-m-d H:i:s', $value['updated_at']) : '';
  958. $value['pay_time'] = $value['pay_time'] > 0 ? date('Y-m-d H:i:s', $value['pay_time']) : '';
  959. }
  960. return $this->asJson([
  961. 'code' => 0,
  962. 'msg' => 'success',
  963. 'data' => [
  964. 'list' => $list,
  965. 'pageNo' => $pagination['pageNo'],
  966. 'totalCount' => $pagination['totalCount']
  967. ]
  968. ]);
  969. }
  970. /**
  971. * 模块名:actionCashApply
  972. * 代码描述:提现申请
  973. * 作者:WPing丶
  974. * 请求方式:POST
  975. * 创建时间:2023/07/11 15:13:16
  976. * @param int id
  977. * @param string str
  978. * @param bool bool
  979. */
  980. public function actionCashApply()
  981. {
  982. $saas_user = get_saas_user();
  983. $courier = LocalDeliveryCourier::findOne(['saas_user_id' => $saas_user->id, 'is_delete' => 0, 'state' => 2]);
  984. if (!$courier) {
  985. return $this->asJson([
  986. 'code' => 1,
  987. 'msg' => '当前用户不是骑手',
  988. ]);
  989. }
  990. $price = post_params('cash');
  991. $type = post_params('type');
  992. if (!$price || !in_array($type, ['alipay', 'bank_card', 'wechat','lg'])) {
  993. return $this->asJson([
  994. 'code' => 1,
  995. 'msg' => '参数非法',
  996. ]);
  997. }
  998. //商城余额是否充足
  999. if ($price > $courier->money) {
  1000. \Yii::error([__METHOD__, $price, $courier->money]);
  1001. return $this->asJson([
  1002. 'code' => 1,
  1003. 'msg' => '可提现金额不足'
  1004. ]);
  1005. }
  1006. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'store')['value'];
  1007. $local_type = Option::get(OptionSetting::STORE_LOCAL_TYPE, get_store_id(), 'pay', $local_type)['value'];
  1008. $store_id = 0;
  1009. if ($local_type === 'self_store') {
  1010. $store_id = get_store_id();
  1011. }
  1012. //同城配送设置相关
  1013. $values = Option::find()->where([
  1014. 'store_id' => $store_id,
  1015. 'group' => OptionSetting::LOCAL_DELIVERY_GROUP_NAME, 'name' => OptionSetting::LOCAL_DELIVERY_SETTING
  1016. ])->select('value')->one();
  1017. $local_setting = json_decode($values->value, true);
  1018. $cash_max_day = $local_setting['cash_max_day']['value'];
  1019. $min_money = $local_setting['min_money']['value'];
  1020. //今日提现金额
  1021. $today_cash = LocalDeliveryCash::find()
  1022. ->where(['<>', 'status', LocalDeliveryCash::CASH_STATUS_FAIL])
  1023. ->andWhere(['saas_user_id' => $saas_user->id])
  1024. ->andWhere(['>', 'created_at', strtotime(date('Y-m-d'))])
  1025. ->sum('price');
  1026. if ($cash_max_day > 0 && ($price > $cash_max_day || bcadd($price, (float)$today_cash, 2) > $cash_max_day)) {
  1027. \Yii::error([__METHOD__, $price, $cash_max_day]);
  1028. return $this->asJson([
  1029. 'code' => 1,
  1030. 'msg' => '今日提现金额已超过每天提现最大额度' . $cash_max_day . '元'
  1031. ]);
  1032. }
  1033. if ($price <= $min_money) {
  1034. \Yii::error([__METHOD__, $price, $min_money]);
  1035. return $this->asJson([
  1036. 'code' => 1,
  1037. 'msg' => '提现金额不能小于' . $min_money . '元'
  1038. ]);
  1039. }
  1040. $exit = LocalDeliveryCash::find()->andWhere(['=', 'status', 0])->andWhere(['saas_user_id' => $saas_user->id])->exists();
  1041. if ($exit) {
  1042. \Yii::error([__METHOD__, $saas_user->id, $exit]);
  1043. // return $this->asJson([
  1044. // 'code' => 1,
  1045. // 'msg' => '尚有未完成的提现申请'
  1046. // ]);
  1047. }
  1048. $t = \Yii::$app->db->beginTransaction();
  1049. $cash = new LocalDeliveryCash();
  1050. $cash->order_no = OrderNo::getOrderNo(OrderNo::ORDER_LOCAL_CASH);
  1051. $cash->is_delete = 0;
  1052. $cash->status = 0;
  1053. $cash->price = $price;
  1054. $cash->created_at = time();
  1055. $cash->saas_user_id = $saas_user->id;
  1056. $cash->store_id = $courier->store_id ?: 0;
  1057. $cash->service_charge = bcmul(bcdiv($local_setting['cash_service_charge']['value'], 100, 4), $price, 2);
  1058. $withdraw_method = json_decode($saas_user->withdraw_method, true);
  1059. $withdraw_method = array_column($withdraw_method, null, 'type');
  1060. if ($type == 'wechat') {
  1061. $cash->type = 0;
  1062. $cash->name = $withdraw_method['wechat']['name'];
  1063. $cash->mobile = $withdraw_method['wechat']['account'];
  1064. }
  1065. if ($type == 'alipay') {
  1066. $cash->type = 1;
  1067. $cash->name = $withdraw_method['alipay']['name'];
  1068. $cash->mobile = $withdraw_method['alipay']['account'];
  1069. }
  1070. if ($type == 'bank_card') {
  1071. $cash->type = 2;
  1072. $cash->name = $withdraw_method['bank_card']['name'];
  1073. $cash->mobile = $withdraw_method['bank_card']['account'];
  1074. $cash->bank_name = $withdraw_method['bank_card']['bank'];
  1075. }
  1076. if ($type == 'lg') {
  1077. //灵工提现
  1078. $lg_info = Lg::find()->where(['user_id'=>$saas_user->id,'is_delete'=>0,'status'=>1])->one();
  1079. $cash->type = 4;
  1080. $cash->name = $lg_info->name;
  1081. $cash->mobile = $lg_info->mobile;
  1082. }
  1083. $cash->pay_time = 0;
  1084. if ($cash->save()) {
  1085. $subMoney = \app\models\LocalDeliveryCourier::subMoney($courier, $price, '配送员提现');
  1086. if (!$subMoney) {
  1087. $t->rollBack();
  1088. \Yii::error([__METHOD__, $subMoney, $cash]);
  1089. return $this->asJson([
  1090. 'code' => 1,
  1091. 'msg' => '扣款失败',
  1092. ]);
  1093. }
  1094. $t->commit();
  1095. return $this->asJson([
  1096. 'code' => 0,
  1097. 'msg' => '申请成功'
  1098. ]);
  1099. } else {
  1100. $t->rollBack();
  1101. return $this->asJson([
  1102. 'code' => 1,
  1103. 'msg' => $cash->errors
  1104. ]);
  1105. }
  1106. }
  1107. /**
  1108. * 模块名:actionAccountLogList
  1109. * 代码描述:佣金明细
  1110. * 作者:WPing丶
  1111. * 请求方式:GET
  1112. * 创建时间:2023/07/12 09:03:52
  1113. * @param int id
  1114. * @param string str
  1115. * @param bool bool
  1116. */
  1117. public function actionAccountLogList()
  1118. {
  1119. $start_time = get_params('start_time');
  1120. $end_time = get_params('end_time');
  1121. $type = get_params('type');
  1122. $saas_user = get_saas_user();
  1123. $query = LocalDeliveryLog::find()->alias('l')->where(['l.saas_user_id' => $saas_user->id]);
  1124. if ($start_time) {
  1125. $query->andWhere(['>=', 'l.created_at', strtotime($start_time . ' 00:00:00')]);
  1126. }
  1127. if ($end_time) {
  1128. $query->andWhere(['<=', 'l.created_at', strtotime($end_time . ' 23:59:59')]);
  1129. }
  1130. if ($type > 0) {
  1131. $query->andWhere(['l.type' => $type]);
  1132. }
  1133. $query->orderBy('l.id DESC');
  1134. $pagination = pagination_make($query);
  1135. $list = $pagination['list'];
  1136. return $this->asJson([
  1137. 'code' => 0,
  1138. 'msg' => 'success',
  1139. 'data' => [
  1140. 'data' => $list,
  1141. 'pageNo' => $pagination['pageNo'],
  1142. 'totalCount' => $pagination['totalCount']
  1143. ],
  1144. ]);
  1145. }
  1146. /**
  1147. * 模块名:actionApplyCourier
  1148. * 代码描述:骑手申请
  1149. * 作者:WPing丶
  1150. * 请求方式:GET
  1151. * 创建时间:2023/07/13 17:31:20
  1152. * @param int id
  1153. * @param string str
  1154. * @param bool bool
  1155. */
  1156. public function actionApplyCourier()
  1157. {
  1158. $saas_user = get_saas_user();
  1159. $store_id = get_store_id();
  1160. if (\Yii::$app->request->isGet) {
  1161. $courier = LocalDeliveryCourier::findOne(['is_delete' => 0, 'saas_user_id' => $saas_user->id, 'store_id' => $store_id]);
  1162. if (empty($courier)) {
  1163. $courier = LocalDeliveryCourier::findOne(['is_delete' => 0, 'saas_user_id' => $saas_user->id]);
  1164. if ($courier) {
  1165. return $this->asJson([
  1166. 'code' => 1,
  1167. 'msg' => '当前账户已在其他店铺申请'
  1168. ]);
  1169. }
  1170. }
  1171. $area = json_decode($courier->area, true);
  1172. if (!empty($area)) {
  1173. $area = $area[0];
  1174. $province = District::findOne($area['province_id'])->name ?: '';
  1175. $city = District::findOne($area['city_id'])->name ?: '';
  1176. $district = District::findOne($area['district_id'])->name ?: '';
  1177. $area_name = [
  1178. 'province' => $province,
  1179. 'city' => $city,
  1180. 'district' => $district
  1181. ];
  1182. $area = array_merge($area, $area_name);
  1183. $courier->area = json_encode([$area], JSON_UNESCAPED_UNICODE);
  1184. }
  1185. return $this->asJson([
  1186. 'code' => 0,
  1187. 'msg' => '',
  1188. 'data' => [
  1189. 'real_name' => $courier->real_name ?: '',
  1190. 'mobile' => $courier->mobile ?: '',
  1191. 'real_code' => $courier->real_code ?: '',
  1192. 'real_just_pic' => $courier->real_just_pic ?: '',
  1193. 'real_back_pic' => $courier->real_back_pic ?: '',
  1194. 'area' => $courier->area ?: '[{"province_id":0,"city_id":0,"district_id":0,"town_id":0,"village_id":0,"province":"","city":"","district":""}]',
  1195. 'address' => $courier->address ?: '',
  1196. 'state' => intval($courier->state) ?: 0
  1197. ]
  1198. ]);
  1199. }
  1200. $params = post_params();
  1201. $courier = LocalDeliveryCourier::findOne(['is_delete' => 0, 'saas_user_id' => $saas_user->id, 'store_id' => $store_id]);
  1202. if ($courier) {
  1203. if ($courier->state == 1) {
  1204. return $this->asJson([
  1205. 'code' => 1,
  1206. 'msg' => '正在审核中,请耐心等待'
  1207. ]);
  1208. } elseif ($courier->state == 2) {
  1209. return $this->asJson([
  1210. 'code' => 1,
  1211. 'msg' => '审核已通过'
  1212. ]);
  1213. }
  1214. } else {
  1215. $courier = LocalDeliveryCourier::findOne(['is_delete' => 0, 'saas_user_id' => $saas_user->id]);
  1216. if ($courier) {
  1217. return $this->asJson([
  1218. 'code' => 1,
  1219. 'msg' => '当前账户已在其他店铺申请'
  1220. ]);
  1221. }
  1222. $courier = new LocalDeliveryCourier;
  1223. }
  1224. /* 参数验证begin */
  1225. if (!$params['real_name']) {
  1226. return $this->asJson([
  1227. 'code' => 1,
  1228. 'msg' => '请填写骑手姓名'
  1229. ]);
  1230. }
  1231. if (!$params['mobile']) {
  1232. return $this->asJson([
  1233. 'code' => 1,
  1234. 'msg' => '请填写手机号'
  1235. ]);
  1236. }
  1237. if (!$params['real_code']) {
  1238. return $this->asJson([
  1239. 'code' => 1,
  1240. 'msg' => '请填写身份证号'
  1241. ]);
  1242. }
  1243. if (!$params['real_just_pic']) {
  1244. return $this->asJson([
  1245. 'code' => 1,
  1246. 'msg' => '请上传身份证正面照'
  1247. ]);
  1248. }
  1249. if (!$params['real_back_pic']) {
  1250. return $this->asJson([
  1251. 'code' => 1,
  1252. 'msg' => '请上传身份证反面照'
  1253. ]);
  1254. }
  1255. /* end */
  1256. $courier->store_id = get_store_id();
  1257. $courier->real_name = $params['real_name'];
  1258. $courier->mobile = $params['mobile'];
  1259. $courier->real_code = $params['real_code'];
  1260. $courier->real_just_pic = $params['real_just_pic'];
  1261. $courier->real_back_pic = $params['real_back_pic'];
  1262. $courier->type = 2;
  1263. $courier->saas_user_id = $saas_user->id;
  1264. $courier->work_time = '[{"begin_time":"00:00","end_time":"00:00"}]';
  1265. $courier->area = $params['area'] ?: '[{"province_id":0,"city_id":0,"district_id":0,"town_id":0,"village_id":0}]';
  1266. $courier->state = 1;
  1267. $courier->address = $params['address'];
  1268. $courier->avatar = $saas_user->avatar;
  1269. if (!$courier->save()) {
  1270. return $this->asJson([
  1271. 'code' => 1,
  1272. 'msg' => $courier->errors
  1273. ]);
  1274. }
  1275. return $this->asJson([
  1276. 'code' => 0,
  1277. 'msg' => '申请已提交'
  1278. ]);
  1279. }
  1280. //订单骑手评价
  1281. public function actionOrderRiverComment() {
  1282. $order_no = post_params('order_no');
  1283. $star = post_params('star');
  1284. $tag_ids = post_params('tag_ids');
  1285. $delivery_info = DeliveryInfo::findOne(['order_no' => $order_no, 'is_delete' => 0]);
  1286. if (empty($delivery_info)) {
  1287. return $this->asJson([
  1288. 'code' => 1,
  1289. 'msg' => '订单查询失败'
  1290. ]);
  1291. }
  1292. if ($delivery_info->local_status !== DeliveryInfo::LOCAL_STATUS_CONFIRM) {
  1293. return $this->asJson([
  1294. 'code' => 1,
  1295. 'msg' => '订单未送达 不可操作'
  1296. ]);
  1297. }
  1298. $courier = LocalDeliveryCourier::findOne($delivery_info->rider_id);
  1299. if (empty($courier)) {
  1300. return $this->asJson([
  1301. 'code' => 1,
  1302. 'msg' => '骑手未找到'
  1303. ]);
  1304. }
  1305. $courierComment = LocalDeliveryCourierComment::findOne(['d_order_id' => $delivery_info->id]);
  1306. if (!empty($courierComment)) {
  1307. return $this->asJson([
  1308. 'code' => 1,
  1309. 'msg' => '已评价不可重复操作'
  1310. ]);
  1311. }
  1312. if (!in_array($star, range(1, 5))) {
  1313. return $this->asJson([
  1314. 'code' => 1,
  1315. 'msg' => '星级错误'
  1316. ]);
  1317. }
  1318. $tag_ids = explode(',', $tag_ids);
  1319. $new_tag_ids = [];
  1320. foreach ($tag_ids as $tag_id) {
  1321. $courierTag = LocalDeliveryCourierTag::findOne($tag_id);
  1322. if ($courierTag) {
  1323. $new_tag_ids[] = $tag_id;
  1324. }
  1325. }
  1326. $t = \Yii::$app->db->beginTransaction();
  1327. try {
  1328. $courierComment = new LocalDeliveryCourierComment();
  1329. $courierComment->d_order_id = $delivery_info->id;
  1330. $courierComment->rider_id = $courier->id;
  1331. $courierComment->store_id = get_store_id();
  1332. $courierComment->star = $star;
  1333. if (!$courierComment->save()) {
  1334. throw new \Exception(json_encode($courierComment->errors, JSON_UNESCAPED_UNICODE));
  1335. }
  1336. foreach ($new_tag_ids as $new_tag_id) {
  1337. $courierCommentTag = new LocalDeliveryCourierCommentExt();
  1338. $courierCommentTag->comment_id = $courierComment->id;
  1339. $courierCommentTag->tag_id = $new_tag_id;
  1340. $courierCommentTag->rider_id = $courier->id;
  1341. if (!$courierCommentTag->save()) {
  1342. throw new \Exception(json_encode($courierCommentTag->errors, JSON_UNESCAPED_UNICODE));
  1343. }
  1344. }
  1345. $t->commit();
  1346. return $this->asJson([
  1347. 'code' => 0,
  1348. 'msg' => '操作成功'
  1349. ]);
  1350. } catch (\Exception $e) {
  1351. $t->rollBack();
  1352. return $this->asJson([
  1353. 'code' => 1,
  1354. 'msg' => $e->getMessage() . $e->getLine()
  1355. ]);
  1356. }
  1357. }
  1358. //订单骑手信息
  1359. public function actionRiderInfo() {
  1360. $rider_id = get_params('rider_id');
  1361. $courier = LocalDeliveryCourier::findOne($rider_id);
  1362. if (empty($courier)) {
  1363. return $this->asJson([
  1364. 'code' => 1,
  1365. 'msg' => '骑手不存在'
  1366. ]);
  1367. }
  1368. $rider = [
  1369. 'real_name' => $courier->real_name,
  1370. 'avatar' => $courier->avatar,
  1371. 'mobile' => $courier->mobile,
  1372. 'pass_rate' => ($courier->pass_rate * 100) . "%",
  1373. 'star' => ($courier->star * 100) . "%"
  1374. ];
  1375. //总里程
  1376. $rider['distance'] = DeliveryInfo::find()->where(['rider_id' => $rider_id])->sum('distance') ?: '0.00';
  1377. //标签
  1378. $tags = LocalDeliveryCourierCommentExt::find()->where(['rider_id' => $rider_id, 'is_delete' => 0])
  1379. ->select('tag_id, COUNT(tag_id) as num')->groupBy('tag_id')->asArray()->all();
  1380. $rider['tags'] = [];
  1381. foreach ($tags as $tag) {
  1382. $courierTag = LocalDeliveryCourierTag::findOne($tag['tag_id']);
  1383. if ($courierTag) {
  1384. $rider['tags'][] = [
  1385. 'tag' => $courierTag->tag,
  1386. 'num' => $tag['num'],
  1387. 'star' => $courierTag->star
  1388. ];
  1389. }
  1390. }
  1391. return $this->asJson([
  1392. 'code' => 0,
  1393. 'msg' => '获取成功',
  1394. 'data' => [
  1395. 'rider_info' => $rider
  1396. ]
  1397. ]);
  1398. }
  1399. }