OrderLogic.php 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | likeshop100%开源免费商用商城系统
  4. // +----------------------------------------------------------------------
  5. // | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
  6. // | 开源版本可自由商用,可去除界面版权logo
  7. // | 商业版本务必购买商业授权,以免引起法律纠纷
  8. // | 禁止对系统程序代码以任何目的,任何形式的再发布
  9. // | gitee下载:https://gitee.com/likeshop_gitee
  10. // | github下载:https://github.com/likeshop-github
  11. // | 访问官网:https://www.likeshop.cn
  12. // | 访问社区:https://home.likeshop.cn
  13. // | 访问手册:http://doc.likeshop.cn
  14. // | 微信公众号:likeshop技术社区
  15. // | likeshop团队 版权所有 拥有最终解释权
  16. // +----------------------------------------------------------------------
  17. // | author: likeshopTeam
  18. // +----------------------------------------------------------------------
  19. namespace app\adminapi\logic\order;
  20. use app\common\cache\YlyPrinterCache;
  21. use app\common\enum\AfterSaleEnum;
  22. use app\common\enum\AfterSaleLogEnum;
  23. use app\common\enum\DeliveryEnum;
  24. use app\common\enum\GoodsEnum;
  25. use app\common\enum\NoticeEnum;
  26. use app\common\enum\OrderEnum;
  27. use app\common\enum\OrderLogEnum;
  28. use app\common\enum\UserTerminalEnum;
  29. use app\common\enum\PayEnum;
  30. use app\common\enum\YesNoEnum;
  31. use app\common\logic\BaseLogic;
  32. use app\common\logic\PayNotifyLogic;
  33. use app\common\model\AddressLibrary;
  34. use app\common\model\AfterSale;
  35. use app\common\model\Delivery;
  36. use app\common\model\DeliveryTime;
  37. use app\common\model\Express;
  38. use app\common\model\GoodsSupplier;
  39. use app\common\model\Order;
  40. use app\common\model\OrderGoods;
  41. use app\common\model\OrderLog;
  42. use app\common\model\SelffetchShop;
  43. use app\common\service\after_sale\AfterSaleService;
  44. use app\common\service\ConfigService;
  45. use app\common\service\printer\YlyPrinterService;
  46. use app\common\service\RegionService;
  47. use app\common\service\WechatMiniExpressSendSyncService;
  48. use app\shopapi\logic\TeamLogic;
  49. use expressage\Kd100;
  50. use expressage\Kdniao;
  51. use think\Exception;
  52. use think\facade\Db;
  53. class OrderLogic extends BaseLogic
  54. {
  55. /**
  56. * @notes 查看其他列表
  57. * @return array
  58. * @author ljj
  59. * @date 2021/8/5 10:09 上午
  60. */
  61. public function otherLists()
  62. {
  63. $other_lists = [
  64. 'order_terminal_lists' => UserTerminalEnum::getTermInalDesc(true),
  65. 'order_type_lists' => OrderEnum::getOrderTypeDesc(true),
  66. 'pay_way_lists' => PayEnum::getPayDesc(true),
  67. 'pay_status_lists' => PayEnum::getPayStatusDesc(true),
  68. 'delivery_type_lists' => DeliveryEnum::getDeliveryTypeDesc(true),
  69. 'refund_status_lists' => [],
  70. ];
  71. return $other_lists;
  72. }
  73. /**
  74. * @notes 查看订单详情
  75. * @param $params
  76. * @return mixed
  77. * @author ljj
  78. * @date 2021/8/9 5:27 下午
  79. */
  80. public function detail($params)
  81. {
  82. $info = Order::withTrashed()->alias('o')
  83. ->join('user u', 'o.user_id = u.id')
  84. ->leftjoin('selffetch_shop ss', 'ss.id = o.selffetch_shop_id')
  85. ->leftjoin('delivery d', 'd.id = o.delivery_id')
  86. ->leftjoin('verification v', 'v.order_id = o.id')
  87. ->where('o.id',$params['id'])
  88. ->with(['order_goods' => function($query){
  89. $query->field('id,order_id,goods_id,goods_snap,goods_name,goods_price,goods_num,total_price,discount_price as coupon_discount,member_price,integral_price,change_price,total_pay_price,original_price,express_price')->append(['goods_image','spec_value_str','code','supplier_name']);
  90. },'order_log' => function($query){
  91. $query->field('order_id,type,operator_id,channel,create_time')->append(['operator','channel_desc'])->hidden(['operator_id','channel'])->order('id','desc');
  92. },'selffetch_shop' => function($query){
  93. $query->field('id,name,contact,mobile,province,city,district,address')->append(['detailed_address'])->hidden(['province','city','district','address']);
  94. }])
  95. ->field('o.id,o.order_status,o.sn,o.order_type,o.order_terminal,o.create_time,o.pay_status,o.pay_way,o.pay_time,confirm_take_time,u.id as user_id,
  96. u.sn as user_sn,u.nickname,o.address,o.express_status,o.delivery_type,o.express_time,o.express_again,o.user_remark,o.order_remarks,
  97. o.discount_amount,o.member_amount,o.change_price,o.express_price,o.order_amount,o.integral_amount,o.is_team_success,d.express_name,d.invoice_no,
  98. o.pickup_code,v.create_time as verification_time,o.verification_status,o.delivery_content,o.delivery_content1,o.delivery_content_type,d.send_type,o.selffetch_shop_id')
  99. ->append(['order_status_desc','order_type_desc','order_terminal_desc','pay_status_desc','pay_way_desc','delivery_address','express_status_desc','delivery_type_desc','admin_order_btn'])
  100. ->find()
  101. ->toArray();
  102. //显示供应商名称
  103. $goodsIds = array_column($info['order_goods'],'goods_id');
  104. $goodsSupplier = GoodsSupplier::alias('GS')
  105. ->join('goods G','G.supplier_id = GS.id')
  106. ->where(['G.id'=>$goodsIds])
  107. ->column('GS.name','G.id');
  108. $totalDiscount = 0;
  109. $goodsAmount = 0;
  110. foreach ($info['order_goods'] as $key => $orderGoods){
  111. $info['order_goods'][$key]['supplier_name'] = $goodsSupplier[$orderGoods['goods_id']] ?? '';
  112. $info['order_goods'][$key]['member_discount'] = 0;
  113. if($orderGoods['member_price'] > 0){
  114. $info['order_goods'][$key]['member_discount'] = round(($orderGoods['original_price'] - $orderGoods['member_price']) * $orderGoods['goods_num'],2);
  115. }
  116. unset($info['order_goods'][$key]['member_price']);
  117. $info['order_goods'][$key]['integral_discount'] = round($orderGoods['integral_price'] * $orderGoods['goods_num'],2);
  118. unset($info['order_goods'][$key]['integral_price']);
  119. $info['order_goods'][$key]['total_discount'] = round($info['order_goods'][$key]['member_discount']+ $info['order_goods'][$key]['coupon_discount'] +$info['order_goods'][$key]['integral_discount'],2);
  120. $info['order_goods'][$key]['total_amount'] = round($orderGoods['original_price'] * $orderGoods['goods_num'],2);
  121. // $totalDiscount = round($totalDiscount + $info['order_goods'][$key]['total_discount'],2);
  122. $goodsAmount += $info['order_goods'][$key]['total_amount'];
  123. //售后状态
  124. $info['order_goods'][$key]['after_sale_status_desc'] = '无售后';
  125. $after_sale = AfterSale::where(['order_goods_id' => $orderGoods['id'], 'order_id' => $orderGoods['order_id']])->findOrEmpty();
  126. if (!$after_sale->isEmpty()) {
  127. $info['order_goods'][$key]['after_sale_status_desc'] = AfterSaleEnum::getStatusDesc($after_sale->status);
  128. }
  129. }
  130. // $info['total_discount'] = $totalDiscount;//订单总优惠金额
  131. $info['total_discount'] = $info['discount_amount'] + $info['member_amount'] + $info['integral_amount'];
  132. unset($info['discount_amount']);unset($info['member_amount']);unset($info['integral_amount']);
  133. $info['total_goods_amount'] = $goodsAmount;//订单商品总价
  134. //TODO 计算订单商品实付总额(订单商品总价-优惠券金额-积分抵扣金额-商品改价)
  135. // $info['total_goods_pay_price'] = round($info['total_goods_price'] - $info['discount_amount'] - $info['integral_amount'] - $info['change_price'],2);
  136. // if ($info['total_goods_pay_price'] < 0) {
  137. // $info['total_goods_pay_price'] = 0;
  138. // }
  139. //收货信息
  140. $info['contact'] = $info['address']->contact;
  141. $info['mobile'] = $info['address']->mobile;
  142. unset($info['address']);
  143. //拼团订单显示拼团状态
  144. if(OrderEnum::TEAM_ORDER == $info['order_type'] && 1 != $info['is_team_success']){
  145. 0 == $info['is_team_success'] ? $tips = '(拼团中)' : $tips = '(拼团失败)';
  146. $info['order_type_desc'] .=$tips;
  147. }
  148. //提货时间
  149. $info['verification_time'] = empty($info['verification_time']) ? '-' : date('Y-m-d H:i:s',$info['verification_time']);
  150. //快递包裹信息
  151. $info['express_parcel'] = Delivery::field('id,order_id,order_goods_info,express_name,invoice_no,send_type,remark,create_time')
  152. ->where(['order_id'=>$info['id']])
  153. ->append(['send_type_desc'])
  154. ->select()->toArray();
  155. return $info;
  156. }
  157. /**
  158. * @notes 修改地址
  159. * @param $params
  160. * @throws \think\db\exception\DataNotFoundException
  161. * @throws \think\db\exception\DbException
  162. * @throws \think\db\exception\ModelNotFoundException
  163. * @author ljj
  164. * @date 2021/8/10 11:34 上午
  165. */
  166. public function addressEdit($params)
  167. {
  168. $order = Order::find($params['id']);
  169. $address = [
  170. 'contact' => $params['contact'],
  171. 'mobile' => $params['mobile'],
  172. 'province' => $params['province_id'],
  173. 'city' => $params['city_id'],
  174. 'district' => $params['district_id'],
  175. 'address' => $params['address'],
  176. ];
  177. $order->address = $address;
  178. $order->save();
  179. $change_address= RegionService::getAddress(
  180. [
  181. $params['province_id'] ?? '',
  182. $params['city_id'] ?? '',
  183. $params['district_id'] ?? ''
  184. ],
  185. $params['address'] ?? '',
  186. );
  187. //订单日志
  188. (new OrderLog())->record([
  189. 'type' => OrderLogEnum::TYPE_SHOP,
  190. 'channel' => OrderLogEnum::SHOP_ADDRESS_EDIT,
  191. 'order_id' => $params['id'],
  192. 'operator_id' => $params['admin_id'],
  193. 'content' => '商家修改收货地址为:'.$change_address,
  194. ]);
  195. return true;
  196. }
  197. /**
  198. * @notes 设置商家备注
  199. * @param $params
  200. * @throws \think\db\exception\DataNotFoundException
  201. * @throws \think\db\exception\DbException
  202. * @throws \think\db\exception\ModelNotFoundException
  203. * @author ljj
  204. * @date 2021/8/10 11:49 上午
  205. */
  206. public function orderRemarks($params)
  207. {
  208. foreach ($params['id'] as $id) {
  209. $order = Order::find($id);
  210. if (!$order) {
  211. continue;
  212. }
  213. $order->order_remarks = $params['order_remarks'] ?? '';
  214. $order->save();
  215. //订单日志
  216. (new OrderLog())->record([
  217. 'type' => OrderLogEnum::TYPE_SHOP,
  218. 'channel' => OrderLogEnum::SHOP_ORDER_REMARKS,
  219. 'order_id' => $id,
  220. 'operator_id' => $params['admin_id'],
  221. 'content' => '商家备注:'.$order->order_remarks,
  222. ]);
  223. }
  224. return true;
  225. }
  226. /**
  227. * @notes 修改价格(订单详情)
  228. * @param $params
  229. * @return bool
  230. * @author ljj
  231. * @date 2021/8/10 2:53 下午
  232. */
  233. public function changePrice($params)
  234. {
  235. // 启动事务
  236. Db::startTrans();
  237. try {
  238. //更新订单商品表
  239. $order_goods = OrderGoods::find($params['order_goods_id']);
  240. $order_goods->change_price = $params['change_price'];
  241. $order = Order::findOrEmpty($order_goods['order_id'] ?? 0);
  242. if ($order->order_status != OrderEnum::STATUS_WAIT_PAY) {
  243. throw new \Exception('订单已支付或者已关闭了,不能再进行改价');
  244. }
  245. // TODO 实际支付商品金额(商品总价-优惠券金额-积分抵扣的金额-商品改价+运费)
  246. $order_goods->total_pay_price = $order_goods->total_price - $order_goods->discount_price - $order_goods->integral_price + $params['change_price'] + $order_goods->express_price;
  247. if ($order_goods->total_pay_price - $order_goods->express_price < 0) {
  248. $discountPrice = round($order_goods->total_price - $order_goods->discount_price - $order_goods->integral_price, 2);
  249. throw new Exception('减少的优惠价格不能大于'. $discountPrice . '元');
  250. }
  251. $order_goods->save();
  252. //更新订单表
  253. $total_change_price = OrderGoods::where('order_id',$order_goods->order_id)->sum('change_price');
  254. $order->change_price = $total_change_price;
  255. // TODO 应付款金额(订单商品总价-优惠券金额-积分抵扣金额-商品改价+运费)
  256. $order->order_amount = $order->goods_price - $order->discount_amount - $order->integral_amount + $total_change_price + $order->express_price;
  257. if ($order->order_amount < 0) {
  258. $order->order_amount = 0;
  259. }
  260. $order->save();
  261. //订单日志
  262. (new OrderLog())->record([
  263. 'type' => OrderLogEnum::TYPE_SHOP,
  264. 'channel' => OrderLogEnum::SHOP_CHANGE_PRICE,
  265. 'order_id' => $order_goods->order_id,
  266. 'operator_id' => $params['admin_id'],
  267. 'content' => '商家修改订单商品【'.$order_goods->goods_name.'】的商品改价为:'.$params['change_price'],
  268. ]);
  269. // 提交事务
  270. Db::commit();
  271. return true;
  272. } catch (\Exception $e) {
  273. // 回滚事务
  274. Db::rollback();
  275. self::$error = $e->getMessage();
  276. return false;
  277. }
  278. }
  279. /**
  280. * @notes 修改运费(订单详情)
  281. * @param $params
  282. * @throws \think\db\exception\DataNotFoundException
  283. * @throws \think\db\exception\DbException
  284. * @throws \think\db\exception\ModelNotFoundException
  285. * @author ljj
  286. * @date 2021/8/10 3:11 下午
  287. */
  288. public function changeExpressPrice($params)
  289. {
  290. // 启动事务
  291. Db::startTrans();
  292. try {
  293. if ($params['express_price'] < 0) {
  294. throw new Exception('运费最低可改为 0 元');
  295. }
  296. $order_goods = OrderGoods::find($params['order_goods_id']);
  297. $order_goods->express_price = $params['express_price'];
  298. $order = Order::findOrEmpty($order_goods['order_id'] ?? 0);
  299. if ($order->order_status != OrderEnum::STATUS_WAIT_PAY) {
  300. throw new \Exception('订单已支付或者已关闭了,不能再进行改价');
  301. }
  302. // TODO 实际支付商品金额(商品总价-优惠券金额-积分抵扣的金额-商品改价+运费)
  303. $order_goods->total_pay_price = $order_goods->total_price - $order_goods->discount_price - $order_goods->integral_price + $order_goods->change_price + $params['express_price'];
  304. $order_goods->save();
  305. //更新订单表
  306. $total_express_price = OrderGoods::where('order_id',$order_goods->order_id)->sum('express_price');
  307. $order->express_price = $total_express_price;
  308. // TODO 订单总价(订单商品总价+运费)
  309. $order->total_amount = $order->goods_price + $order->express_price;
  310. // TODO 应付款金额(订单商品总价-优惠券金额-积分抵扣金额-商品改价+运费)
  311. $order->order_amount = $order->goods_price - $order->discount_amount - $order->integral_amount + $order->change_price + $order->express_price;
  312. if ($order->order_amount < 0) {
  313. $order->order_amount = 0;
  314. }
  315. $order->save();
  316. //订单日志
  317. (new OrderLog())->record([
  318. 'type' => OrderLogEnum::TYPE_SHOP,
  319. 'channel' => OrderLogEnum::SHOP_EXPRESS_PRICE,
  320. 'order_id' => $order_goods->order_id,
  321. 'operator_id' => $params['admin_id'],
  322. 'content' => '商家修改订单商品【'.$order_goods->goods_name.'】的商品运费为:'.$params['express_price'],
  323. ]);
  324. // 提交事务
  325. Db::commit();
  326. return true;
  327. } catch (\Exception $e) {
  328. // 回滚事务
  329. Db::rollback();
  330. self::$error = $e->getMessage();
  331. return false;
  332. }
  333. }
  334. /**
  335. * @notes 取消订单
  336. * @param $params
  337. * @return bool
  338. * @author ljj
  339. * @date 2021/8/10 4:50 下午
  340. */
  341. public function cancel($params)
  342. {
  343. Db::startTrans();
  344. try {
  345. $order = Order::find($params['id']);
  346. if ($order['order_type'] == OrderEnum::TEAM_ORDER) {
  347. TeamLogic::signFailTeam($order['id']);
  348. } else {
  349. //更新订单表
  350. $order->order_status = OrderEnum::STATUS_CLOSE;
  351. $order->cancel_time = time();
  352. //TODO 处于已支付状态的发起整单售后
  353. if ($order->pay_status == PayEnum::ISPAID) {
  354. AfterSaleService::orderRefund([
  355. 'order_id' => $params['id'],
  356. 'scene' => AfterSaleLogEnum::SELLER_CANCEL_ORDER
  357. ]);
  358. }
  359. $order->save();
  360. $returnInventory = ConfigService::get('transaction', 'return_inventory');
  361. if ($returnInventory) {
  362. // 需退还库存
  363. AfterSaleService::returnInventory(['order_id' => $order['id']]);
  364. }
  365. $returnCoupon = ConfigService::get('transaction', 'return_coupon');
  366. if ($returnCoupon) {
  367. // 需退还优惠券
  368. AfterSaleService::returnCoupon($order);
  369. }
  370. //订单日志
  371. (new OrderLog())->record([
  372. 'type' => OrderLogEnum::TYPE_SHOP,
  373. 'channel' => OrderLogEnum::SHOP_CANCEL_ORDER,
  374. 'order_id' => $params['id'],
  375. 'operator_id' => $params['admin_id'],
  376. ]);
  377. }
  378. Db::commit();
  379. return true;
  380. } catch (\Exception $e) {
  381. Db::rollback();
  382. self::$error = $e->getMessage();
  383. return false;
  384. }
  385. }
  386. function confirmOfflinePay($params): bool|string
  387. {
  388. try {
  389. $order = Order::where('id', $params['id'])->append([ 'admin_order_btn', 'businesse_btn' ])->findOrEmpty()->toArray();
  390. if (empty($order)) {
  391. throw new \Exception('订单不存在');
  392. }
  393. if (! $order['admin_order_btn']['confirm_pay_btn']) {
  394. throw new \Exception('订单已不能确认线下付款');
  395. }
  396. PayNotifyLogic::handle('order', $order['sn']);
  397. return true;
  398. } catch(\Throwable $e) {
  399. self::$error = $e->getMessage();
  400. return false;
  401. }
  402. }
  403. /**
  404. * @notes 发货
  405. * @param $params
  406. * @return bool
  407. * @author ljj
  408. * @date 2021/8/10 6:25 下午
  409. */
  410. public function delivery($params)
  411. {
  412. Db::startTrans();
  413. try {
  414. $order = Order::find($params['id']);
  415. //消息通知
  416. $notice[] = [
  417. 'express_name' => '无需快递',
  418. 'invoice_no' => '',
  419. ];
  420. //虚拟发货和实物发货
  421. if(OrderEnum::VIRTUAL_ORDER != $order['order_type']){
  422. $delivery = new Delivery;
  423. $deliveryData = [];
  424. $orderGoodsInfo = [];
  425. $orderGoodsData = [];
  426. //新建批次发货时间记录
  427. $deliveryTime = DeliveryTime::create(['order_id' => $params['id']]);
  428. //快递发货
  429. $deliveryAddressInfo = AddressLibrary::where(['id'=>$params['delivery_address_id']])->append(['province','city','district','complete_address'])->findOrEmpty()->toArray();
  430. $returnAddressInfo = AddressLibrary::where(['id'=>$params['return_address_id']])->append(['province','city','district','complete_address'])->findOrEmpty()->toArray();
  431. if ($params['send_type'] == DeliveryEnum::EXPRESS) {
  432. $parcelOrderGoodsData = [];
  433. $notice = [];
  434. foreach ($params['parcel'] as $parcel) {
  435. //处理包裹数据
  436. $orderGoodsInfo = [];
  437. foreach ($parcel['order_goods_info'] as $value) {
  438. $orderGoodsInfo[] = [
  439. 'order_goods_id' => $value['order_goods_id'],
  440. 'delivery_num' => $value['delivery_num']
  441. ];
  442. $parcelOrderGoodsData[$value['order_goods_id']] = ($parcelOrderGoodsData[$value['order_goods_id']] ?? 0) + $value['delivery_num'];
  443. }
  444. //添加发货单记录
  445. $express_id = $parcel['express_id'];
  446. $invoice_no = $parcel['invoice_no'];
  447. $express_name = Express::where('id',$express_id)->value('name');
  448. $deliveryData[] = [
  449. 'delivery_time_id' => $deliveryTime->id,
  450. 'order_id' => $params['id'],
  451. 'order_sn' => $order['sn'],
  452. 'order_goods_info' => json_encode($orderGoodsInfo),
  453. 'user_id' => $order['user_id'],
  454. 'admin_id' => $params['admin_id'],
  455. 'delivery_address_info' => json_encode($deliveryAddressInfo),
  456. 'return_address_info' => json_encode($returnAddressInfo),
  457. 'contact' => $order['address']->contact,
  458. 'mobile' => $order['address']->mobile,
  459. 'province' => $order['address']->province,
  460. 'city' => $order['address']->city,
  461. 'district' => $order['address']->district,
  462. 'address' => $order['address']->address,
  463. 'express_status' => DeliveryEnum::SHIPPED,
  464. 'express_id' => $express_id,
  465. 'express_name' => $express_name,
  466. 'invoice_no' => $invoice_no,
  467. 'send_type' => $params['send_type'],
  468. 'remark' => $params['remark'] ?? '',
  469. ];
  470. $notice[] = [
  471. 'express_name' => $express_name,
  472. 'invoice_no' => $invoice_no,
  473. ];
  474. }
  475. foreach ($parcelOrderGoodsData as $key=>$val) {
  476. $orderGoods = OrderGoods::where(['id'=>$key])->field('goods_num,delivery_num')->findOrEmpty()->toArray();
  477. $delivery_num = $val + $orderGoods['delivery_num'];
  478. $is_shipped = $delivery_num >= $orderGoods['goods_num'] ? true : false;
  479. $orderGoodsData[] = [
  480. 'id' => $key,
  481. 'delivery_num' => $is_shipped ? $orderGoods['goods_num'] : $delivery_num,
  482. 'express_status' => $is_shipped ? DeliveryEnum::SHIPPED : DeliveryEnum::PART_SHIPPED,
  483. ];
  484. }
  485. } else {
  486. //无需快递
  487. //添加发货单记录
  488. $orderGoods = OrderGoods::where(['id'=>$params['order_goods_ids']])->field('id,goods_num,delivery_num')->select()->toArray();
  489. foreach ($orderGoods as $goods) {
  490. $delivery_num = $goods['goods_num'] - $goods['delivery_num'];
  491. $delivery_num = $delivery_num > 0 ? $delivery_num : 0;
  492. $already_delivery_num = $goods['delivery_num'] + $delivery_num;
  493. $orderGoodsInfo[] = [
  494. 'order_goods_id' => $goods['id'],
  495. 'delivery_num' => $delivery_num
  496. ];
  497. $orderGoodsData[] = [
  498. 'id' => $goods['id'],
  499. 'delivery_num' => $already_delivery_num,
  500. 'express_status' => $already_delivery_num >= $goods['goods_num'] ? DeliveryEnum::SHIPPED : DeliveryEnum::PART_SHIPPED,
  501. ];
  502. }
  503. $deliveryData[] = [
  504. 'delivery_time_id' => $deliveryTime->id,
  505. 'order_id' => $params['id'],
  506. 'order_sn' => $order['sn'],
  507. 'order_goods_info' => json_encode($orderGoodsInfo),
  508. 'user_id' => $order['user_id'],
  509. 'admin_id' => $params['admin_id'],
  510. 'delivery_address_info' => json_encode($deliveryAddressInfo),
  511. 'return_address_info' => json_encode($returnAddressInfo),
  512. 'contact' => $order['address']->contact,
  513. 'mobile' => $order['address']->mobile,
  514. 'province' => $order['address']->province,
  515. 'city' => $order['address']->city,
  516. 'district' => $order['address']->district,
  517. 'address' => $order['address']->address,
  518. 'express_status' => DeliveryEnum::NOT_SHIPPED,
  519. 'send_type' => $params['send_type'],
  520. 'remark' => $params['remark'] ?? '',
  521. ];
  522. }
  523. //保存发货单记录
  524. $delivery->saveAll($deliveryData);
  525. //更新订单商品信息
  526. (new OrderGoods())->saveAll($orderGoodsData);
  527. //获取最新订单商品信息
  528. $orderGoodsIds = OrderGoods::where(['order_id'=>$params['id'],'express_status'=>[DeliveryEnum::NOT_SHIPPED,DeliveryEnum::PART_SHIPPED]])->column('id');
  529. if (!empty($orderGoodsIds)) {
  530. foreach ($orderGoodsIds as $key=>$orderGoodsId) {
  531. $afterSale = AfterSale::where(['order_goods_id'=>$orderGoodsId,'status'=>AfterSaleEnum::STATUS_SUCCESS])->findOrEmpty();
  532. if (!$afterSale->isEmpty()) {
  533. unset($orderGoodsIds[$key]);
  534. }
  535. }
  536. }
  537. $order_status = OrderEnum::STATUS_WAIT_DELIVERY;
  538. $express_status = DeliveryEnum::PART_SHIPPED;
  539. if (empty($orderGoodsIds)) {
  540. $order_status = OrderEnum::STATUS_WAIT_RECEIVE;
  541. $express_status = DeliveryEnum::SHIPPED;
  542. }
  543. //更新订单表
  544. $order->order_status = $order_status;
  545. $order->express_status = $express_status;
  546. $order->express_time = time();
  547. $order->delivery_id = 0;
  548. $order->save();
  549. }else{
  550. $orderGoods = OrderGoods::where(['order_id'=>$order['id']])->find();
  551. //自动完成订单
  552. $order->order_status = OrderEnum::STATUS_FINISH;
  553. if(GoodsEnum::AFTER_DELIVERY_HANDOPERSTION == $orderGoods->goods_snap->after_delivery){
  554. $order->order_status = OrderEnum::STATUS_WAIT_RECEIVE;
  555. }
  556. //更新订单表
  557. $order->express_status = DeliveryEnum::NOT_SHIPPED;
  558. $order->delivery_content = $params['delivery_content'] ?? '';
  559. $order->delivery_content1 = $params['delivery_content1'] ?? [];
  560. $order->delivery_content_type = $params['delivery_content_type'] ?? 0;
  561. $order->express_time = time();
  562. $order->delivery_id = 0;
  563. if(GoodsEnum::AFTER_DELIVERY_AUTO == $orderGoods->goods_snap->after_delivery){
  564. $order->confirm_take_time = time();
  565. }
  566. $order->save();
  567. }
  568. //订单日志
  569. (new OrderLog())->record([
  570. 'type' => OrderLogEnum::TYPE_SHOP,
  571. 'channel' => OrderLogEnum::SHOP_DELIVERY_ORDER,
  572. 'order_id' => $params['id'],
  573. 'operator_id' => $params['admin_id'],
  574. ]);
  575. // 消息通知
  576. foreach ($notice as $value) {
  577. event('Notice', [
  578. 'scene_id' => NoticeEnum::ORDER_SHIP_NOTICE,
  579. 'params' => [
  580. 'user_id' => $order->user_id,
  581. 'order_id' => $order->id,
  582. 'express_name' => $value['express_name'],
  583. 'invoice_no' => $value['invoice_no'],
  584. 'ship_time' => date('Y-m-d H:i:s')
  585. ]
  586. ]);
  587. }
  588. Db::commit();
  589. return true;
  590. } catch (\Exception $e) {
  591. Db::rollback();
  592. self::$error = $e->getMessage();
  593. return false;
  594. }
  595. }
  596. /**
  597. * @notes 发货信息
  598. * @param $params
  599. * @return array
  600. * @throws \think\db\exception\DataNotFoundException
  601. * @throws \think\db\exception\DbException
  602. * @throws \think\db\exception\ModelNotFoundException
  603. * @author ljj
  604. * @date 2021/8/10 7:16 下午
  605. */
  606. public function deliveryInfo($params)
  607. {
  608. $info = Order::field('id,order_type,address,delivery_content,pay_way,sn,pay_time')
  609. ->with(['order_goods'=> function($query){
  610. $query->field('id,order_id,goods_snap,goods_name,goods_price,discount_price,goods_num,total_pay_price,delivery_num')
  611. ->append(['goods_image','spec_value_str','surplus_delivery_num'])
  612. ->where(['express_status'=>[DeliveryEnum::NOT_SHIPPED,DeliveryEnum::PART_SHIPPED]]);
  613. }])
  614. ->where('id',$params['id'])
  615. ->append(['delivery_address'])
  616. ->find()
  617. ->toArray();
  618. //计算单个商品实付价格
  619. foreach ($info['order_goods'] as $key=>&$val) {
  620. $val['pay_price'] = $val['total_pay_price'] / $val['goods_num'];
  621. //售后状态
  622. $val['after_sale_status_desc'] = '无售后';
  623. $val['after_sale_status'] = 0;
  624. $val['after_sale_id'] = 0;
  625. $after_sale = AfterSale::where(['order_goods_id' => $val['id'], 'order_id' => $val['order_id']])->findOrEmpty();
  626. if ($after_sale->status == AfterSaleEnum::STATUS_SUCCESS) {
  627. unset($info['order_goods'][$key]);
  628. continue;
  629. }
  630. if (!$after_sale->isEmpty()) {
  631. $val['after_sale_status_desc'] = AfterSaleEnum::getStatusDesc($after_sale->status);
  632. $val['after_sale_status'] = $after_sale->status;
  633. $val['after_sale_id'] = $after_sale->id;
  634. }
  635. }
  636. $info['order_goods'] = array_values($info['order_goods']);
  637. if(OrderEnum::VIRTUAL_ORDER == $info['order_type']){
  638. $info['delivery_content'] = $val['goods_snap']->delivery_content;
  639. }
  640. //处理收货信息
  641. $info['contact'] = $info['address']->contact;
  642. $info['mobile'] = $info['address']->mobile;
  643. unset($info['address']);
  644. //获取物流公司
  645. $info['express'] = Express::field('id,name,code')->select()->toArray();
  646. //发货地址、退货地址信息 如果有发过货的,使用上一次发货的地址
  647. $lastDelivery = Delivery::where(['order_id'=>$info['id']])->field('delivery_address_info,return_address_info')->order(['id'=>'desc'])->findOrEmpty()->toArray();
  648. $deliveryAddress = !empty($lastDelivery['delivery_address_info']) ? json_decode($lastDelivery['delivery_address_info'],true) : '';
  649. if(empty($deliveryAddress)) {
  650. $deliveryAddress = AddressLibrary::order(['is_deliver_default'=>'desc','id'=>'asc'])->append(['province','city','district'])->findOrEmpty()->toArray();
  651. }
  652. $returnAddress = !empty($lastDelivery['return_address_info']) ? json_decode($lastDelivery['return_address_info'],true) : '';
  653. if(empty($returnAddress)) {
  654. $returnAddress = AddressLibrary::order(['is_return_default'=>'desc','id'=>'asc'])->append(['province','city','district'])->findOrEmpty()->toArray();
  655. }
  656. $info['company_address'] = [
  657. 'delivery_address' => $deliveryAddress,
  658. 'return_address' => $returnAddress,
  659. ];
  660. return $info;
  661. }
  662. /**
  663. * @notes 确认收货
  664. * @param $params
  665. * @return bool
  666. * @author ljj
  667. * @date 2021/8/11 10:37 上午
  668. */
  669. public function confirm($params)
  670. {
  671. // 启动事务
  672. Db::startTrans();
  673. try {
  674. //更新订单状态
  675. $order = Order::find($params['id']);
  676. $order->order_status = OrderEnum::STATUS_FINISH;
  677. $order->confirm_take_time = time();
  678. $order->after_sale_deadline = self::getAfterSaleDeadline();
  679. $order->save();
  680. //订单日志
  681. (new OrderLog())->record([
  682. 'type' => OrderLogEnum::TYPE_SHOP,
  683. 'channel' => OrderLogEnum::SHOP_CONFIRM_ORDER,
  684. 'order_id' => $params['id'],
  685. 'operator_id' => $params['admin_id'],
  686. ]);
  687. // 提交事务
  688. Db::commit();
  689. return true;
  690. } catch (\Exception $e) {
  691. // 回滚事务
  692. Db::rollback();
  693. self::$error = $e->getMessage();
  694. return false;
  695. }
  696. }
  697. /**
  698. * @notes 获取当前售后
  699. * @return float|int
  700. * @author ljj
  701. * @date 2021/9/1 3:09 下午
  702. */
  703. public static function getAfterSaleDeadline()
  704. {
  705. //是否关闭维权
  706. $afterSale = ConfigService::get('transaction', 'after_sales');
  707. //可维权时间
  708. $afterSaleDays = ConfigService::get('transaction', 'after_sales_days');
  709. if ($afterSale == YesNoEnum::NO) {
  710. $afterSaleDeadline = time();
  711. } else {
  712. $afterSaleDeadline = ($afterSaleDays * 24 * 60 * 60) + time();
  713. }
  714. return $afterSaleDeadline;
  715. }
  716. /**
  717. * @notes 物流查询
  718. * @param $params
  719. * @return mixed
  720. * @author ljj
  721. * @date 2021/8/13 3:48 下午
  722. */
  723. public function logistics($params)
  724. {
  725. $result = [];
  726. //发货批次时间
  727. $result['delivery_time'] = DeliveryTime::where(['order_id'=>$params['id']])->field('id,order_id,create_time')->select()->toArray();
  728. if (empty($result['delivery_time'])) {
  729. //处理旧数据
  730. $result['delivery_time'][] = [
  731. 'id' => 0,
  732. 'order_id' => $params['id'],
  733. 'create_time' => time()
  734. ];
  735. }
  736. //订单信息
  737. $order = Order::field('id,sn,pay_time,address,order_type')
  738. ->append(['delivery_address'])
  739. ->where('id',$params['id'])
  740. ->find()
  741. ->toArray();
  742. //物流配置
  743. $express_type = ConfigService::get('logistics_config', 'express_type', '');
  744. $express_bird = unserialize(ConfigService::get('logistics_config', 'express_bird', ''));
  745. $express_hundred = unserialize(ConfigService::get('logistics_config', 'express_hundred', ''));
  746. $deliveryInfo = [];
  747. foreach ($result['delivery_time'] as $value) {
  748. $parcelInfo = Delivery::field('id,order_id,order_goods_info,express_name,express_id,invoice_no,send_type,remark,create_time,delivery_address_info,return_address_info')
  749. ->where(['order_id'=>$order['id'],'delivery_time_id'=>$value['id']])
  750. ->append(['send_type_desc'])
  751. ->select()->toArray();
  752. if (empty($parcelInfo)) {
  753. //处理旧数据
  754. $result['delivery_time'] = [];
  755. continue;
  756. } else {
  757. if ($value['id'] == 0) {
  758. $result['delivery_time'][0]['create_time'] = $parcelInfo[0]['create_time'];
  759. }
  760. }
  761. foreach ($parcelInfo as $key=>$parcel) {
  762. //查询物流信息
  763. $logisticsInfo = [];
  764. if ($parcel['send_type'] == DeliveryEnum::NO_EXPRESS) {
  765. $logisticsInfo['traces'] = ['无需物流'];
  766. } else {
  767. if (empty($express_type)) {
  768. $logisticsInfo['traces'] = ['暂无物流信息'];
  769. }
  770. //快递配置设置为快递鸟时
  771. if($express_type === 'express_bird') {
  772. $expressage = (new Kdniao($express_bird['ebussiness_id'], $express_bird['app_key']));
  773. $express_field = 'codebird';
  774. } elseif($express_type === 'express_hundred') {
  775. $expressage = (new Kd100($express_hundred['customer'], $express_hundred['app_key']));
  776. $express_field = 'code100';
  777. }
  778. //快递编码
  779. $express_code = Express::where('id',$parcel['express_id'])->value($express_field);
  780. //获取物流轨迹
  781. if (in_array(strtolower($express_code), [ 'sf', 'shunfeng' ])) {
  782. if ($express_type === 'express_bird') {
  783. $expressage->logistics($express_code, $parcel['invoice_no'], substr($order['address']->mobile, -4));
  784. } else {
  785. $expressage->logistics($express_code, $parcel['invoice_no'], $order['address']->mobile);
  786. }
  787. }else {
  788. $expressage->logistics($express_code, $parcel['invoice_no']);
  789. }
  790. $logisticsInfo['traces'] = $expressage->logisticsFormat();
  791. if ($logisticsInfo['traces'] == false) {
  792. $logisticsInfo['traces'] = ['暂无物流信息'];
  793. } else {
  794. foreach ($logisticsInfo['traces'] as &$item) {
  795. $item = array_values(array_unique($item));
  796. }
  797. }
  798. }
  799. $parcelInfo[$key]['logistics_info'] = $logisticsInfo;
  800. }
  801. $deliveryAddressInfo = !empty($parcelInfo[0]['delivery_address_info']) ? json_decode($parcelInfo[0]['delivery_address_info'],true) : '';
  802. $returnAddressInfo = !empty($parcelInfo[0]['return_address_info']) ? json_decode($parcelInfo[0]['return_address_info'],true) : '';
  803. $deliveryInfo[] = [
  804. 'delivery_time_id' => $value['id'],
  805. 'order_id' => $order['id'],
  806. 'order_sn' => $order['sn'],
  807. 'order_type' => $order['order_type'],
  808. 'pay_time' => $order['pay_time'],
  809. 'receipt_address_info' => [
  810. 'addresss' => $order['delivery_address'],
  811. 'contact' => $order['address']->contact,
  812. 'mobile' => $order['address']->mobile,
  813. ],
  814. 'delivery_address_info' => [
  815. 'addresss' => $deliveryAddressInfo['complete_address'] ?? '',
  816. 'contact' => $deliveryAddressInfo['contact'] ?? '',
  817. 'mobile' => $deliveryAddressInfo['mobile'] ?? '',
  818. ],
  819. 'return_address_info' => [
  820. 'addresss' => $returnAddressInfo['complete_address'] ?? '',
  821. 'contact' => $returnAddressInfo['contact'] ?? '',
  822. 'mobile' => $returnAddressInfo['mobile'] ?? '',
  823. ],
  824. 'remark' => $parcelInfo[0]['remark'],
  825. 'parcel_info' => $parcelInfo,
  826. ];
  827. }
  828. $result['delivery_info'] = $deliveryInfo;
  829. return $result;
  830. }
  831. /**
  832. * @notes 小票打印
  833. * @param $params
  834. * @return bool
  835. * @author Tab
  836. * @date 2021/11/16 11:16
  837. */
  838. public function orderPrint($params)
  839. {
  840. try {
  841. $order = $this->getOrderInfo($params['id']);
  842. if(! (new YlyPrinterService())->startPrint($order)){
  843. static::setError('打印机离线');
  844. return false;
  845. }
  846. return true;
  847. } catch (\Exception $e) {
  848. return $this->handleCatch($e);
  849. }
  850. }
  851. /**
  852. * @notes 获取商品信息
  853. * @param $orderId
  854. * @return array
  855. * @throws \Exception
  856. * @author Tab
  857. * @date 2021/11/16 11:16
  858. */
  859. public function getOrderInfo($orderId)
  860. {
  861. $field = [
  862. 'id',
  863. 'sn',
  864. 'order_type',
  865. 'pay_way',
  866. 'delivery_type',
  867. 'goods_price',
  868. 'order_amount',
  869. 'discount_amount',
  870. 'express_price',
  871. 'user_remark',
  872. 'pickup_code',
  873. 'address',
  874. 'selffetch_shop_id',
  875. 'create_time',
  876. 'pickup_code',
  877. 'change_price',
  878. 'member_amount',
  879. ];
  880. $order = Order::field($field)->with(['orderGoods' => function($query) {
  881. $query->field(['goods_num', 'order_id', 'goods_price', 'goods_snap', 'original_price' ]);
  882. }])
  883. ->append(['delivery_address', 'pay_way_desc', 'delivery_type_desc'])
  884. ->findOrEmpty($orderId);
  885. if ($order->isEmpty()) {
  886. throw new \Exception("订单不存在");
  887. }
  888. // 门店自提
  889. if ($order->delivery_type == DeliveryEnum::SELF_DELIVERY) {
  890. $field = [
  891. 'id',
  892. 'name',
  893. 'contact',
  894. 'province',
  895. 'city',
  896. 'district',
  897. 'address',
  898. ];
  899. $selffetchShop = SelffetchShop::field($field)
  900. ->append(['detailed_address'])
  901. ->findOrEmpty($order->selffetch_shop_id);
  902. $order->selffetch_shop = $selffetchShop;
  903. }
  904. return $order->toArray();
  905. }
  906. /**
  907. * @notes 统一处理涉及易联云的错误
  908. * @param $e
  909. * @return false
  910. * @author Tab
  911. * @date 2021/11/16 17:30
  912. */
  913. public function handleCatch($e)
  914. {
  915. $msg = json_decode($e->getMessage(),true);
  916. if(18 === $e->getCode()){
  917. //access_token过期,清除缓存中的access_token
  918. (new YlyPrinterCache())->deleteTag();
  919. };
  920. if($msg && isset($msg['error'])){
  921. self::$error = '易联云:'.$msg['error_description'];
  922. return false;
  923. }
  924. self::$error = $e->getMessage();
  925. return false;
  926. }
  927. /**
  928. * @notes 重新修改物流信息
  929. * @param array $params
  930. * @return bool|string
  931. * @author cjhao
  932. * @date 2022/9/5 14:27
  933. */
  934. public function changeDelivery(array $params){
  935. try{
  936. if(empty($params['id'])){
  937. throw new \Exception('请选择发货单');
  938. }
  939. if(empty($params['express_id']) && empty($params['invoice_no'])){
  940. throw new \Exception("请选择物流或者输入要修改的单号");
  941. }
  942. $delivery = Delivery::findOrEmpty($params['id']);
  943. if($delivery->isEmpty()){
  944. throw new \Exception('发货单不存在');
  945. }
  946. if($delivery->send_type == DeliveryEnum::NO_EXPRESS){
  947. throw new \Exception('发货单无需快递');
  948. }
  949. $order = Order::field('id,order_status')->findOrEmpty($delivery->order_id);
  950. if($order->isEmpty()){
  951. throw new \Exception('订单不存在');
  952. }
  953. if($order->order_status > OrderEnum::STATUS_WAIT_RECEIVE){
  954. throw new \Exception('订单已完成或已关闭');
  955. }
  956. $experssName = Express::where('id',$params['express_id'])->value('name');
  957. $delivery->express_id = $params['express_id'];
  958. $delivery->express_name = $experssName;
  959. $delivery->invoice_no = $params['invoice_no'];
  960. $delivery->save();
  961. // $order->express_again = 1;
  962. // $order->express_time = time();
  963. // $order->delivery_id = $expressId ? $delivery->id : 0;
  964. // $order->delivery_content = $params['delivery_content'] ?? '';
  965. // $order->save();
  966. // WechatMiniExpressSendSyncService::_sync_order($order->toArray());
  967. return true;
  968. }catch (\Exception $e){
  969. return $e->getMessage();
  970. }
  971. }
  972. }