StoreOrderDeliveryServices.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\order;
  12. use app\jobs\MiniOrderJob;
  13. use app\services\activity\coupon\StoreCouponIssueServices;
  14. use app\services\activity\integral\StoreIntegralOrderServices;
  15. use app\services\BaseServices;
  16. use app\dao\order\StoreOrderDao;
  17. use app\services\message\MessageSystemServices;
  18. use app\services\product\sku\StoreProductAttrValueServices;
  19. use app\services\product\sku\StoreProductVirtualServices;
  20. use app\services\serve\ServeServices;
  21. use app\services\wechat\WechatUserServices;
  22. use crmeb\exceptions\AdminException;
  23. use crmeb\exceptions\ApiException;
  24. use crmeb\services\FormBuilder as Form;
  25. use app\services\shipping\ExpressServices;
  26. use think\facade\Log;
  27. /**
  28. * 订单发货
  29. * Class StoreOrderDeliveryServices
  30. * @package app\services\order
  31. */
  32. class StoreOrderDeliveryServices extends BaseServices
  33. {
  34. /**
  35. * 构造方法
  36. * StoreOrderDeliveryServices constructor.
  37. * @param StoreOrderDao $dao
  38. */
  39. public function __construct(StoreOrderDao $dao)
  40. {
  41. $this->dao = $dao;
  42. }
  43. /**
  44. * 订单发货
  45. * @param int $id
  46. * @param array $data
  47. * @return array
  48. */
  49. public function delivery(int $id, array $data)
  50. {
  51. $orderInfo = $this->dao->get($id, ['*'], ['pink']);
  52. if (!$orderInfo) {
  53. throw new AdminException('订单未能查到,不能发货');
  54. }
  55. if ($orderInfo->is_del) {
  56. throw new AdminException('订单已删除,不能发货');
  57. }
  58. if ($orderInfo->status) {
  59. throw new AdminException('订单已发货请勿重复操作');
  60. }
  61. if ($orderInfo->shipping_type == 2) {
  62. throw new AdminException('核销订单不能发货');
  63. }
  64. if (isset($orderInfo['pinkStatus']) && $orderInfo['pinkStatus'] != 2) {
  65. throw new AdminException('拼团未完成暂不能发货');
  66. }
  67. if ($data['type'] == 1) {
  68. // 检测快递公司编码
  69. /** @var ExpressServices $expressServices */
  70. $expressServices = app()->make(ExpressServices::class);
  71. if (!$expressServices->be(['code' => $data['delivery_code']])) {
  72. throw new AdminException('请核对快递公司编码');
  73. }
  74. }
  75. /** @var StoreOrderRefundServices $storeOrderRefundServices */
  76. $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
  77. if ($storeOrderRefundServices->count(['store_order_id' => $id, 'refund_type' => [1, 2, 4, 5], 'is_cancel' => 0, 'is_del' => 0])) {
  78. throw new AdminException('订单有售后申请请先处理');
  79. }
  80. return $this->doDelivery($id, $orderInfo, $data);
  81. }
  82. /**
  83. * 订单快递发货
  84. * @param int $id
  85. * @param array $data
  86. */
  87. public function orderDeliveryGoods(int $id, array $data, $orderInfo, $storeTitle)
  88. {
  89. /** @var StoreOrderCartInfoServices $orderInfoServices */
  90. $orderInfoServices = app()->make(StoreOrderCartInfoServices::class);
  91. if (!$data['delivery_name']) {
  92. throw new AdminException('请选择快递公司');
  93. }
  94. $data['delivery_type'] = 'express';
  95. if ($data['express_record_type'] == 2) {//电子面单
  96. if (!$data['delivery_code']) {
  97. throw new AdminException('快递公司编缺失');
  98. }
  99. if (!$data['express_temp_id']) {
  100. throw new AdminException('请选择电子面单模板');
  101. }
  102. if (!$data['to_name']) {
  103. throw new AdminException('请填写寄件人姓名');
  104. }
  105. if (!$data['to_tel']) {
  106. throw new AdminException('请填写寄件人电话');
  107. }
  108. if (!$data['to_addr']) {
  109. throw new AdminException('请填写寄件人地址');
  110. }
  111. /** @var ServeServices $expressService */
  112. $expressService = app()->make(ServeServices::class);
  113. $expData['com'] = $data['delivery_code'];
  114. $expData['to_name'] = $orderInfo->real_name;
  115. $expData['to_tel'] = $orderInfo->user_phone;
  116. $expData['to_addr'] = $orderInfo->user_address;
  117. $expData['from_name'] = $data['to_name'];
  118. $expData['from_tel'] = $data['to_tel'];
  119. $expData['from_addr'] = $data['to_addr'];
  120. $expData['siid'] = sys_config('config_export_siid');
  121. $expData['temp_id'] = $data['express_temp_id'];
  122. $expData['count'] = $orderInfo->total_num;
  123. $expData['cargo'] = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo->id, true);
  124. $expData['order_id'] = $orderInfo->order_id;
  125. if (!sys_config('config_export_open', 0)) {
  126. throw new AdminException('电子面单已关闭,请选择其他发货方式');
  127. }
  128. $dump = $expressService->express()->dump($expData);
  129. $orderInfo->delivery_id = $dump['kuaidinum'];
  130. $data['express_dump'] = json_encode([
  131. 'com' => $expData['com'],
  132. 'from_name' => $expData['from_name'],
  133. 'from_tel' => $expData['from_tel'],
  134. 'from_addr' => $expData['from_addr'],
  135. 'temp_id' => $expData['temp_id'],
  136. 'cargo' => $expData['cargo'],
  137. ]);
  138. $data['delivery_id'] = $dump['kuaidinum'];
  139. } else {
  140. if (!$data['delivery_id']) {
  141. throw new AdminException('请输入快递单号');
  142. }
  143. $orderInfo->delivery_id = $data['delivery_id'];
  144. }
  145. $data['status'] = 1;
  146. $orderInfo->delivery_type = $data['delivery_type'];
  147. $orderInfo->delivery_name = $data['delivery_name'];
  148. $orderInfo->status = $data['status'];
  149. /** @var StoreOrderStatusServices $services */
  150. $services = app()->make(StoreOrderStatusServices::class);
  151. $this->transaction(function () use ($id, $data, $services) {
  152. $res = $this->dao->update($id, $data);
  153. $res = $res && $services->save([
  154. 'oid' => $id,
  155. 'change_time' => time(),
  156. 'change_type' => 'delivery_goods',
  157. 'change_message' => '已发货 快递公司:' . $data['delivery_name'] . ' 快递单号:' . $data['delivery_id']
  158. ]);
  159. if (!$res) {
  160. throw new AdminException('发货失败');
  161. }
  162. });
  163. return true;
  164. }
  165. /**
  166. * 订单配送
  167. * @param int $id
  168. * @param array $data
  169. */
  170. public function orderDelivery(int $id, array $data, $orderInfo, string $storeTitle)
  171. {
  172. $data['delivery_type'] = 'send';
  173. $data['delivery_name'] = $data['sh_delivery_name'];
  174. $data['delivery_id'] = $data['sh_delivery_id'];
  175. $data['delivery_uid'] = $data['sh_delivery_uid'];
  176. $data['shipping_type'] = 1;
  177. //获取核销码
  178. /** @var StoreOrderCreateServices $storeOrderCreateService */
  179. $storeOrderCreateService = app()->make(StoreOrderCreateServices::class);
  180. $data['verify_code'] = $storeOrderCreateService->getStoreCode();
  181. unset($data['sh_delivery_name'], $data['sh_delivery_id'], $data['sh_delivery_uid']);
  182. if (!$data['delivery_name']) {
  183. throw new AdminException('请输入送货人姓名');
  184. }
  185. if (!$data['delivery_id']) {
  186. throw new AdminException('请输入送货人电话号码');
  187. }
  188. if (!$data['delivery_uid']) {
  189. throw new AdminException('请输入送货人信息');
  190. }
  191. if (!preg_match("/^1[3456789]{1}\d{9}$/", $data['delivery_id'])) {
  192. throw new AdminException('请输入正确的送货人电话号码');
  193. }
  194. $data['status'] = 1;
  195. $orderInfo->delivery_type = $data['delivery_type'];
  196. $orderInfo->delivery_name = $data['delivery_name'];
  197. $orderInfo->delivery_id = $data['delivery_id'];
  198. $orderInfo->status = $data['status'];
  199. /** @var StoreOrderStatusServices $services */
  200. $services = app()->make(StoreOrderStatusServices::class);
  201. $this->transaction(function () use ($id, $data, $services) {
  202. $this->dao->update($id, $data);
  203. //记录订单状态
  204. $services->save([
  205. 'oid' => $id,
  206. 'change_type' => 'delivery',
  207. 'change_time' => time(),
  208. 'change_message' => '已配送 发货人:' . $data['delivery_name'] . ' 发货人电话:' . $data['delivery_id']
  209. ]);
  210. });
  211. return true;
  212. }
  213. /**
  214. * 虚拟发货
  215. * @param int $id
  216. * @param array $data
  217. */
  218. public function orderVirtualDelivery(int $id, array $data)
  219. {
  220. $data['delivery_type'] = 'fictitious';
  221. $data['status'] = 1;
  222. unset($data['sh_delivery_name'], $data['sh_delivery_id'], $data['delivery_name'], $data['delivery_id']);
  223. //保存信息
  224. /** @var StoreOrderStatusServices $services */
  225. $services = app()->make(StoreOrderStatusServices::class);
  226. $this->transaction(function () use ($id, $data, $services) {
  227. $this->dao->update($id, $data);
  228. $services->save([
  229. 'oid' => $id,
  230. 'change_type' => 'delivery_fictitious',
  231. 'change_message' => '已虚拟发货',
  232. 'change_time' => time()
  233. ]);
  234. });
  235. }
  236. /**
  237. * 获取修改配送信息表单结构
  238. * @param int $id
  239. * @return array
  240. * @throws \FormBuilder\Exception\FormBuilderException
  241. */
  242. public function distributionForm(int $id)
  243. {
  244. if (!$orderInfo = $this->dao->get($id))
  245. throw new AdminException('订单不存在');
  246. $f[] = Form::input('order_id', '订单号', $orderInfo->getData('order_id'))->disabled(1);
  247. switch ($orderInfo['delivery_type']) {
  248. case 'send':
  249. $f[] = Form::input('delivery_name', '送货人姓名', $orderInfo->getData('delivery_name'))->required('请输入送货人姓名');
  250. $f[] = Form::input('delivery_id', '送货人电话', $orderInfo->getData('delivery_id'))->required('请输入送货人电话');
  251. break;
  252. case 'express':
  253. /** @var ExpressServices $expressServices */
  254. $expressServices = app()->make(ExpressServices::class);
  255. $f[] = Form::select('delivery_code', '快递公司', (string)$orderInfo->getData('delivery_code'))->setOptions($expressServices->expressSelectForm(['is_show' => 1]))->required('请选择快递公司')->filterable(true);
  256. $f[] = Form::input('delivery_id', '快递单号', $orderInfo->getData('delivery_id'))->required('请填写快递单号');
  257. break;
  258. }
  259. return create_form('配送信息', $f, $this->url('/order/distribution/' . $id), 'PUT');
  260. }
  261. /**
  262. * 修改配送信息
  263. * @param int $id 订单id
  264. * @return mixed
  265. */
  266. public function updateDistribution(int $id, array $data)
  267. {
  268. $order = $this->dao->get($id);
  269. if (!$order) {
  270. throw new AdminException('数据不存在');
  271. }
  272. switch ($order['delivery_type']) {
  273. case 'send':
  274. if (!$data['delivery_name']) {
  275. throw new AdminException('请输入送货人姓名');
  276. }
  277. if (!$data['delivery_id']) {
  278. throw new AdminException('请输入送货人电话号码');
  279. }
  280. if (!preg_match("/^1[3456789]{1}\d{9}$/", $data['delivery_id'])) {
  281. throw new AdminException('请输入正确的送货人电话号码');
  282. }
  283. break;
  284. case 'express':
  285. if (!$data['delivery_id']) {
  286. throw new AdminException('请输入快递单号');
  287. }
  288. // 检测快递公司编码
  289. /** @var ExpressServices $expressServices */
  290. $expressServices = app()->make(ExpressServices::class);
  291. if ($name = $expressServices->value(['code' => $data['delivery_code']], 'name')) {
  292. $data['delivery_name'] = $name;
  293. } else {
  294. throw new AdminException('请核对快递公司编码');
  295. }
  296. break;
  297. case 'fictitious':
  298. throw new AdminException('虚拟发货,无需修改发货信息');
  299. break;
  300. default:
  301. throw new AdminException('未发货,请先发货再修改配送信息');
  302. break;
  303. }
  304. /** @var StoreOrderStatusServices $statusService */
  305. $statusService = app()->make(StoreOrderStatusServices::class);
  306. $statusService->save([
  307. 'oid' => $id,
  308. 'change_type' => 'distribution',
  309. 'change_message' => '修改发货信息为' . $data['delivery_name'] . '号' . $data['delivery_id'],
  310. 'change_time' => time()
  311. ]);
  312. return $this->dao->update($id, $data);
  313. }
  314. /**订单发货后打印电子面单
  315. * @param $orderId
  316. * @return bool|mixed
  317. */
  318. public function orderDump($orderId, $type = 'order')
  319. {
  320. if (!$orderId) throw new AdminException('订单不存在');
  321. // /** @var StoreOrderServices $orderService */
  322. // $orderService = app()->make(StoreOrderServices::class);
  323. // $orderInfo = $orderService->getOne(['id' => $orderId]);
  324. if ($type == 'order') {
  325. /** @var StoreOrderServices $orderService */
  326. $orderService = app()->make(StoreOrderServices::class);
  327. $orderInfo = $orderService->getOne(['id' => $orderId]);
  328. } else {
  329. /** @var StoreIntegralOrderServices $integralOrderService */
  330. $integralOrderService = app()->make(StoreIntegralOrderServices::class);
  331. $orderInfo = $integralOrderService->getOne(['id' => $orderId]);
  332. }
  333. if (!$orderInfo) throw new AdminException('订单不存在');
  334. if ($orderInfo->shipping_type != 1) throw new AdminException('自提订单无法打印');
  335. if (!$orderInfo->express_dump) throw new AdminException('请先发货');
  336. if (!sys_config('config_export_open', 0)) {
  337. throw new AdminException('请先在系统设置中打开单子面单打印开关');
  338. }
  339. $dumpInfo = json_decode($orderInfo->express_dump, true);
  340. /** @var ServeServices $expressService */
  341. $expressService = app()->make(ServeServices::class);
  342. $expData['com'] = $dumpInfo['com'];
  343. $expData['to_name'] = $orderInfo->real_name;
  344. $expData['to_tel'] = $orderInfo->user_phone;
  345. $expData['to_addr'] = $orderInfo->user_address;
  346. $expData['from_name'] = $dumpInfo['from_name'];
  347. $expData['from_tel'] = $dumpInfo['from_tel'];
  348. $expData['from_addr'] = $dumpInfo['from_addr'];
  349. $expData['siid'] = sys_config('config_export_siid');
  350. $expData['temp_id'] = $dumpInfo['temp_id'];
  351. $expData['cargo'] = $dumpInfo['cargo'];
  352. $expData['count'] = $orderInfo->total_num;
  353. $expData['order_id'] = $orderInfo->order_id;
  354. $expData['weight'] = 1;
  355. return $expressService->express()->dump($expData);
  356. }
  357. /**
  358. * 订单拆单发货
  359. * @param int $id
  360. * @param array $data
  361. * @throws \think\db\exception\DataNotFoundException
  362. * @throws \think\db\exception\DbException
  363. * @throws \think\db\exception\ModelNotFoundException
  364. * @author 吴汐
  365. * @email 442384644@qq.com
  366. * @date 2023/02/21
  367. */
  368. public function splitDelivery(int $id, array $data, $delivery_code = true)
  369. {
  370. $orderInfo = $this->dao->get($id, ['*'], ['pink']);
  371. if (!$orderInfo) {
  372. throw new AdminException('订单未能查到,不能发货');
  373. }
  374. if ($orderInfo->is_del) {
  375. throw new AdminException('订单已删除,不能发货');
  376. }
  377. if ($orderInfo->shipping_type == 2) {
  378. throw new AdminException('核销订单不能发货');
  379. }
  380. if (isset($orderInfo['pinkStatus']) && $orderInfo['pinkStatus'] != 2) {
  381. throw new AdminException('拼团未完成暂不能发货');
  382. }
  383. /** @var StoreOrderRefundServices $storeOrderRefundServices */
  384. $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
  385. if ($storeOrderRefundServices->count(['store_order_id' => $id, 'refund_type' => [1, 2, 4, 5], 'is_cancel' => 0, 'is_del' => 0])) {
  386. throw new AdminException('订单有售后申请请先处理');
  387. }
  388. if ($data['type'] == 1 && $delivery_code) {
  389. // 检测快递公司编码
  390. /** @var ExpressServices $expressServices */
  391. $expressServices = app()->make(ExpressServices::class);
  392. if (!$expressServices->be(['code' => $data['delivery_code']])) {
  393. throw new AdminException('请核对快递公司编码');
  394. }
  395. }
  396. $cart_ids = $data['cart_ids'];
  397. unset($data['cart_ids']);
  398. return $this->transaction(function () use ($id, $cart_ids, $orderInfo, $data) {
  399. /** @var StoreOrderSplitServices $storeOrderSplitServices */
  400. $storeOrderSplitServices = app()->make(StoreOrderSplitServices::class);
  401. //订单拆单
  402. [$splitOrderInfo, $otherOrder] = $storeOrderSplitServices->equalSplit($id, $cart_ids, $orderInfo);
  403. if ($splitOrderInfo) {
  404. $splitOrderInfo['refund_status'] = 0;
  405. //拆分订单执行发货
  406. $res = $this->doDelivery((int)$splitOrderInfo->id, $splitOrderInfo, $data);
  407. /** @var StoreOrderStatusServices $services */
  408. $services = app()->make(StoreOrderStatusServices::class);
  409. //记录原订单状态
  410. $status_data = ['oid' => $id, 'change_time' => time()];
  411. $status_data['change_type'] = 'delivery_split';
  412. $status_data['change_message'] = '已拆分发货';
  413. $services->save($status_data);
  414. } else {
  415. $res = $this->doDelivery($id, $orderInfo, $data);
  416. }
  417. return $res;
  418. });
  419. }
  420. /**
  421. * 具体执行发货
  422. * @param int $id
  423. * @param $orderInfo
  424. * @param array $data
  425. * @return array
  426. */
  427. public function doDelivery(int $id, $orderInfo, array $data)
  428. {
  429. $type = (int)$data['type'];
  430. unset($data['type']);
  431. //获取购物车内的商品标题
  432. /** @var StoreOrderCartInfoServices $orderInfoServices */
  433. $orderInfoServices = app()->make(StoreOrderCartInfoServices::class);
  434. $storeName = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo->id);
  435. if (isset($data['pickup_time']) && count($data['pickup_time']) == 2) {
  436. $data['pickup_start_time'] = $data['pickup_time'][0];
  437. $data['pickup_end_time'] = $data['pickup_time'][1];
  438. } else {
  439. $data['pickup_start_time'] = '';
  440. $data['pickup_end_time'] = '';
  441. }
  442. // 发货信息录入
  443. $res = [];
  444. switch ($type) {
  445. case 1://快递发货
  446. $res = $this->orderDeliverGoods($id, $data, $orderInfo, $storeName);
  447. event('NoticeListener', [['orderInfo' => $orderInfo, 'storeName' => $storeName, 'data' => $data], 'order_postage_success']);
  448. //自定义消息-快递发货
  449. $orderInfo['storeName'] = $storeName;
  450. $orderInfo['delivery_name'] = $data['delivery_name'];
  451. $orderInfo['delivery_id'] = $data['delivery_id'];
  452. $orderInfo['time'] = date('Y-m-d H:i:s');
  453. $orderInfo['phone'] = $orderInfo['user_phone'];
  454. event('CustomNoticeListener', [$orderInfo['uid'], $orderInfo, 'order_express_success']);
  455. break;
  456. case 2://配送
  457. $this->orderDelivery($id, $data, $orderInfo, $storeName);
  458. event('NoticeListener', [['orderInfo' => $orderInfo, 'storeName' => $storeName, 'data' => $data], 'order_deliver_success']);
  459. //自定义消息-配送员配送
  460. $orderInfo['storeName'] = $storeName;
  461. $orderInfo['delivery_name'] = $data['delivery_name'];
  462. $orderInfo['delivery_id'] = $data['delivery_id'];
  463. $orderInfo['time'] = date('Y-m-d H:i:s');
  464. $orderInfo['phone'] = $orderInfo['user_phone'];
  465. event('CustomNoticeListener', [$orderInfo['uid'], $orderInfo, 'order_send_success']);
  466. break;
  467. case 3://虚拟发货
  468. $this->orderVirtualDelivery($id, $data, $orderInfo, $storeName);
  469. break;
  470. default:
  471. throw new AdminException('暂时不支持其他发货类型');
  472. }
  473. if (!$data['delivery_id'] && !empty($res['kuaidinum'])) {
  474. $data['delivery_id'] = $res['kuaidinum'];
  475. }
  476. if (!$data['delivery_id']) {
  477. $data['delivery_id'] = uniqid();
  478. }
  479. // 小程序订单管理
  480. event('OrderShippingListener', ['product', $orderInfo, $type, $data['delivery_id'], $data['delivery_name']]);
  481. //到期自动收货
  482. event('OrderDeliveryListener', [$orderInfo, $storeName, $data, $type]);
  483. //自定义事件-订单发货
  484. event('CustomEventListener', ['admin_order_express', [
  485. 'uid' => $orderInfo['uid'],
  486. 'real_name' => $orderInfo['real_name'],
  487. 'user_phone' => $orderInfo['user_phone'],
  488. 'user_address' => $orderInfo['user_address'],
  489. 'order_id' => $orderInfo['order_id'],
  490. 'delivery_name' => $orderInfo['delivery_name'],
  491. 'delivery_id' => $orderInfo['delivery_id'],
  492. 'express_time' => date('Y-m-d H:i:s'),
  493. ]]);
  494. return $res;
  495. }
  496. /**
  497. * 订单快递发货
  498. * @param int $id
  499. * @param array $data
  500. */
  501. public function orderDeliverGoods(int $id, array $data, $orderInfo, $storeTitle)
  502. {
  503. /** @var StoreOrderCartInfoServices $orderInfoServices */
  504. $orderInfoServices = app()->make(StoreOrderCartInfoServices::class);
  505. if (!$data['delivery_name']) {
  506. throw new AdminException('请选择快递公司');
  507. }
  508. $dump = [];
  509. $data['delivery_type'] = 'express';
  510. if ($data['express_record_type'] == 2) {//电子面单
  511. if (!$data['delivery_code']) {
  512. throw new AdminException('快递公司编缺失');
  513. }
  514. if (!$data['express_temp_id']) {
  515. throw new AdminException('请选择电子面单模板');
  516. }
  517. if (!$data['to_name']) {
  518. throw new AdminException('请填写寄件人姓名');
  519. }
  520. if (!$data['to_tel']) {
  521. throw new AdminException('请填写寄件人电话');
  522. }
  523. if (!$data['to_addr']) {
  524. throw new AdminException('请填写寄件人地址');
  525. }
  526. /** @var ServeServices $expressService */
  527. $expressService = app()->make(ServeServices::class);
  528. $expData['com'] = $data['delivery_code'];
  529. $expData['to_name'] = $orderInfo->real_name;
  530. $expData['to_tel'] = $orderInfo->user_phone;
  531. $expData['to_addr'] = $orderInfo->user_address;
  532. $expData['from_name'] = $data['to_name'];
  533. $expData['from_tel'] = $data['to_tel'];
  534. $expData['from_addr'] = $data['to_addr'];
  535. $expData['siid'] = sys_config('config_export_siid');
  536. $expData['temp_id'] = $data['express_temp_id'];
  537. $expData['count'] = $orderInfo->total_num;
  538. $expData['weight'] = $this->getOrderSumWeight($id);
  539. $expData['cargo'] = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo->id, true);
  540. $expData['order_id'] = $orderInfo->order_id;
  541. if (!sys_config('config_export_open', 0)) {
  542. throw new AdminException('电子面单已关闭,请选择其他发货方式');
  543. }
  544. $dump = $expressService->express()->dump($expData);
  545. $orderInfo->delivery_id = $dump['kuaidinum'];
  546. $data['express_dump'] = json_encode([
  547. 'com' => $expData['com'],
  548. 'from_name' => $expData['from_name'],
  549. 'from_tel' => $expData['from_tel'],
  550. 'from_addr' => $expData['from_addr'],
  551. 'temp_id' => $expData['temp_id'],
  552. 'cargo' => $expData['cargo'],
  553. ]);
  554. $data['delivery_id'] = $dump['kuaidinum'];
  555. if (!empty($dump['label'])) {
  556. $data['kuaidi_label'] = $dump['label'];
  557. }
  558. } else if ($data['express_record_type'] == 3) {
  559. //商家寄件
  560. if (!$data['delivery_code']) {
  561. throw new AdminException('快递公司编缺失');
  562. }
  563. if (!$data['express_temp_id']) {
  564. throw new AdminException('请选择电子面单模板');
  565. }
  566. if (!$data['to_name']) {
  567. throw new AdminException('请填写寄件人姓名');
  568. }
  569. if (!$data['to_tel']) {
  570. throw new AdminException('请填写寄件人电话');
  571. }
  572. if (!$data['to_addr']) {
  573. throw new AdminException('请填写寄件人地址');
  574. }
  575. /** @var ServeServices $expressService */
  576. $expressService = app()->make(ServeServices::class);
  577. $expData['kuaidicom'] = $data['delivery_code'];
  578. $expData['man_name'] = $orderInfo->real_name;
  579. $expData['phone'] = $orderInfo->user_phone;
  580. $expData['address'] = $orderInfo->user_address;
  581. $expData['send_real_name'] = $data['to_name'];
  582. $expData['send_phone'] = $data['to_tel'];
  583. $expData['send_address'] = $data['to_addr'];
  584. $expData['temp_id'] = $data['express_temp_id'];
  585. $expData['weight'] = $this->getOrderSumWeight($id);
  586. $expData['cargo'] = $orderInfoServices->getCarIdByProductTitle((int)$orderInfo->id, true);
  587. $expData['day_type'] = $data['day_type'];
  588. $expData['pickup_start_time'] = $data['pickup_start_time'];
  589. $expData['pickup_end_time'] = $data['pickup_end_time'];
  590. // if (!sys_config('config_shippment_open', 0)) {
  591. // throw new AdminException('商家寄件未开启无法寄件');
  592. // }
  593. $dump = $expressService->express()->shippmentCreateOrder($expData);
  594. Log::error('商家寄件返回数据:' . json_encode($dump));
  595. $orderInfo->delivery_id = $dump['kuaidinum'] ?? '';
  596. $data['express_dump'] = json_encode([
  597. 'com' => $expData['kuaidicom'],
  598. 'from_name' => $expData['send_real_name'],
  599. 'from_tel' => $expData['send_phone'],
  600. 'from_addr' => $expData['send_address'],
  601. 'temp_id' => $expData['temp_id'],
  602. 'cargo' => $expData['cargo'],
  603. ]);
  604. $data['delivery_id'] = $dump['kuaidinum'] ?? '';
  605. $data['kuaidi_label'] = $dump['label'] ?? '';
  606. $data['kuaidi_task_id'] = $dump['task_id'] ?? '';
  607. $data['kuaidi_order_id'] = $dump['order_id'] ?? '';
  608. } else {
  609. if (!$data['delivery_id']) {
  610. throw new AdminException('请输入快递单号');
  611. }
  612. $orderInfo->delivery_id = $data['delivery_id'];
  613. }
  614. if (true) {
  615. $data['status'] = 1;
  616. $orderInfo->delivery_type = $data['delivery_type'];
  617. $orderInfo->delivery_name = $data['delivery_name'];
  618. $orderInfo->status = $data['status'];
  619. /** @var StoreOrderStatusServices $services */
  620. $services = app()->make(StoreOrderStatusServices::class);
  621. $this->transaction(function () use ($id, $data, $services) {
  622. $res = $this->dao->update($id, $data);
  623. $res = $res && $services->save([
  624. 'oid' => $id,
  625. 'change_time' => time(),
  626. 'change_type' => 'delivery_goods',
  627. 'change_message' => '已发货 快递公司:' . $data['delivery_name'] . ' 快递单号:' . $data['delivery_id']
  628. ]);
  629. if (!$res) {
  630. throw new AdminException('发货失败');
  631. }
  632. });
  633. } else {
  634. $update = [
  635. 'is_stock_up' => 1,
  636. 'delivery_type' => $data['delivery_type'],
  637. 'delivery_name' => $data['delivery_name'],
  638. 'delivery_code' => $data['delivery_code'],
  639. 'delivery_id' => $data['delivery_id'],
  640. 'kuaidi_label' => $data['kuaidi_label'],
  641. 'kuaidi_task_id' => $data['kuaidi_task_id'],
  642. 'kuaidi_order_id' => $data['kuaidi_order_id'],
  643. 'express_dump' => $data['express_dump']
  644. ];
  645. /** @var StoreOrderStatusServices $services */
  646. $services = app()->make(StoreOrderStatusServices::class);
  647. $this->transaction(function () use ($id, $data, $services, $update) {
  648. $res = $this->dao->update($id, $update);
  649. $res = $res && $services->save([
  650. 'oid' => $id,
  651. 'change_time' => time(),
  652. 'change_type' => 'stock_up_goods',
  653. 'change_message' => '备货中 快递公司:' . $data['delivery_name'] . ' 快递单号:' . $data['delivery_id']
  654. ]);
  655. if (!$res) {
  656. throw new AdminException('发货失败');
  657. }
  658. });
  659. }
  660. return $dump;
  661. }
  662. /**
  663. * 返回订单商品总重量
  664. * @param int $id
  665. * @return int|string
  666. */
  667. public function getOrderSumWeight(int $id, $default = false)
  668. {
  669. /** @var StoreOrderCartInfoServices $services */
  670. $services = app()->make(StoreOrderCartInfoServices::class);
  671. $orderGoodInfo = $services->getOrderCartInfo((int)$id);
  672. $weight = 0;
  673. foreach ($orderGoodInfo as $cartInfo) {
  674. $cart = $cartInfo['cart_info'] ?? [];
  675. if ($cart) {
  676. $weight = bcadd((string)$weight, (string)bcmul((string)$cart['cart_num'] ?? '0', (string)$cart['productInfo']['attrInfo']['weight'] ?? '0', 4), 2);
  677. }
  678. }
  679. return $weight ?: ($default === false ? 0 : $default);
  680. }
  681. /**
  682. * 虚拟商品自动发货
  683. * @param $orderInfo
  684. * @throws \ReflectionException
  685. */
  686. public function virtualSend($orderInfo)
  687. {
  688. /** @var StoreOrderStatusServices $statusService */
  689. $statusService = app()->make(StoreOrderStatusServices::class);
  690. /** @var StoreOrderCartInfoServices $services */
  691. $services = app()->make(StoreOrderCartInfoServices::class);
  692. $orderInfo['cart_info'] = $services->getOrderCartInfo((int)$orderInfo['id']);
  693. $activityStatus = $orderInfo['combination_id'] || $orderInfo['seckill_id'] || $orderInfo['bargain_id'];
  694. if ($orderInfo['virtual_type'] == 1) {
  695. /** @var StoreOrderServices $orderService */
  696. $orderService = app()->make(StoreOrderServices::class);
  697. $sku = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['attrInfo']['suk'];
  698. if ($activityStatus) {
  699. $product_id = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['product_id'];
  700. /** @var StoreProductAttrValueServices $attrValue */
  701. $attrValue = app()->make(StoreProductAttrValueServices::class);
  702. $disk_info = $attrValue->value(['product_id' => $product_id, 'suk' => $sku, 'type' => 0, 'is_virtual' => 1], 'disk_info');
  703. } else {
  704. $disk_info = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['attrInfo']['disk_info'];
  705. }
  706. if ($disk_info != '') {
  707. $orderService->update(['id' => $orderInfo['id']], ['status' => 1, 'delivery_type' => 'fictitious', 'virtual_info' => $disk_info, 'remark' => '密钥自动发放:' . $disk_info]);
  708. $this->SystemSend($orderInfo['uid'], [
  709. 'mark' => 'virtual_info',
  710. 'title' => '虚拟密钥发放',
  711. 'content' => '您购买的密钥商品已支付成功,支付金额' . $orderInfo['pay_price'] . '元,订单号:' . $orderInfo['order_id'] . ',密钥:' . $disk_info . ',感谢您的光临!'
  712. ]);
  713. } else {
  714. if ($activityStatus) {
  715. $product_id = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['product_id'];
  716. /** @var StoreProductAttrValueServices $attrValue */
  717. $attrValue = app()->make(StoreProductAttrValueServices::class);
  718. $unique = $attrValue->value(['product_id' => $product_id, 'suk' => $sku, 'type' => 0, 'is_virtual' => 1], 'unique');
  719. } else {
  720. $unique = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['attrInfo']['unique'];
  721. }
  722. /** @var StoreProductVirtualServices $virtualService */
  723. $virtualService = app()->make(StoreProductVirtualServices::class);
  724. $virtual = $virtualService->get(['attr_unique' => $unique, 'uid' => 0]);
  725. if (!$virtual) throw new ApiException('数据不存在');
  726. $virtual->order_id = $orderInfo['order_id'];
  727. $virtual->uid = $orderInfo['uid'];
  728. $virtual->save();
  729. $orderService->update(['id' => $orderInfo['id']], ['status' => 1, 'delivery_type' => 'fictitious', 'virtual_info' => $virtual->card_unique, 'remark' => '卡密已自动发放,卡号:' . $virtual->card_no . ';密码:' . $virtual->card_pwd]);
  730. $this->SystemSend($orderInfo['uid'], [
  731. 'mark' => 'virtual_info',
  732. 'title' => '虚拟卡密发放',
  733. 'content' => '您购买的卡密商品已支付成功,支付金额' . $orderInfo['pay_price'] . '元,订单号:' . $orderInfo['order_id'] . ',卡号:' . $virtual->card_no . ';密码:' . $virtual->card_pwd . ',感谢您的光临!'
  734. ]);
  735. }
  736. $statusService->save([
  737. 'oid' => $orderInfo['id'],
  738. 'change_type' => 'delivery_fictitious',
  739. 'change_message' => '卡密自动发货',
  740. 'change_time' => time()
  741. ]);
  742. } elseif ($orderInfo['virtual_type'] == 2) {
  743. if ($activityStatus) {
  744. $sku = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['attrInfo']['suk'];
  745. $product_id = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['product_id'];
  746. /** @var StoreProductAttrValueServices $attrValue */
  747. $attrValue = app()->make(StoreProductAttrValueServices::class);
  748. $coupon_id = $attrValue->value(['product_id' => $product_id, 'suk' => $sku, 'type' => 0, 'is_virtual' => 1], 'coupon_id');
  749. } else {
  750. $coupon_id = $orderInfo['cart_info'][$orderInfo['cart_id'][0]]['cart_info']['productInfo']['attrInfo']['coupon_id'];
  751. }
  752. /** @var StoreCouponIssueServices $issueService */
  753. $issueService = app()->make(StoreCouponIssueServices::class);
  754. $coupon = $issueService->get($coupon_id);
  755. if ($issueService->setCoupon($coupon, [$orderInfo['uid']])) {
  756. /** @var StoreOrderServices $orderService */
  757. $orderService = app()->make(StoreOrderServices::class);
  758. $orderService->update(['id' => $orderInfo['id']], ['status' => 1, 'delivery_type' => 'fictitious', 'virtual_info' => $coupon_id, 'remark' => '优惠券已自动发放']);
  759. $this->SystemSend($orderInfo['uid'], [
  760. 'mark' => 'virtual_info',
  761. 'title' => '购买优惠券发放',
  762. 'content' => '您购买的优惠券已支付成功,支付金额' . $orderInfo['pay_price'] . '元,订单号' . $orderInfo['order_id'] . '请在个人中心优惠券中查看,感谢您的光临!'
  763. ]);
  764. } else {
  765. throw new ApiException('您已有这张优惠券,请勿重复购买');
  766. }
  767. $statusService->save([
  768. 'oid' => $orderInfo['id'],
  769. 'change_type' => 'delivery_fictitious',
  770. 'change_message' => '优惠券自动发货',
  771. 'change_time' => time()
  772. ]);
  773. }
  774. if ($orderInfo['is_channel'] == 1 && $orderInfo['pay_type'] == 'weixin') {
  775. MiniOrderJob::dispatchSecs(10, 'doJob', [
  776. $orderInfo['order_id'],
  777. 3,
  778. [['item_desc' => $orderInfo['virtual_type'] == 1 ? '卡密自动发货' : '优惠券自动发货']],
  779. app()->make(WechatUserServices::class)->uidToOpenid($orderInfo['uid'], 'routine'),
  780. 'pages/goods/order_details/index?order_id=' . $orderInfo['order_id']
  781. ]);
  782. }
  783. }
  784. /**
  785. * 虚拟商品站内信
  786. * @param int $uid
  787. * @param array $noticeInfo
  788. */
  789. public function SystemSend(int $uid, array $noticeInfo)
  790. {
  791. /** @var MessageSystemServices $MessageSystemServices */
  792. $MessageSystemServices = app()->make(MessageSystemServices::class);
  793. $data = [];
  794. $data['mark'] = $noticeInfo['mark'];
  795. $data['uid'] = $uid;
  796. $data['title'] = $noticeInfo['title'];
  797. $data['content'] = $noticeInfo['content'];
  798. $data['type'] = 1;
  799. $data['add_time'] = time();
  800. $MessageSystemServices->save($data);
  801. }
  802. }