AfterSaleLogic.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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\after_sale;
  20. use app\common\enum\AfterSaleEnum;
  21. use app\common\enum\AfterSaleLogEnum;
  22. use app\common\enum\DeliveryEnum;
  23. use app\common\enum\NoticeEnum;
  24. use app\common\enum\OrderEnum;
  25. use app\common\enum\YesNoEnum;
  26. use app\common\logic\BaseLogic;
  27. use app\common\logic\RefundLogic;
  28. use app\common\model\AfterSale;
  29. use app\common\model\AfterSaleGoods;
  30. use app\common\model\AfterSaleLog;
  31. use app\common\model\GoodsSupplier;
  32. use app\common\model\Order;
  33. use app\common\model\OrderGoods;
  34. use app\common\model\User;
  35. use app\common\service\after_sale\AfterSaleService;
  36. use think\facade\Db;
  37. /**
  38. * 售后逻辑层
  39. * Class AfterSaleLogic
  40. * @package app\adminapi\logic\after_sale
  41. */
  42. class AfterSaleLogic extends BaseLogic
  43. {
  44. /**
  45. * @notes 卖家同意售后
  46. * @param $params
  47. * @return bool
  48. * @author Tab
  49. * @date 2021/8/2 19:51
  50. */
  51. public static function agree($params)
  52. {
  53. Db::startTrans();
  54. try{
  55. $afterSale = AfterSale::findOrEmpty($params['id']);
  56. if($afterSale->isEmpty()) {
  57. throw new \think\Exception('售后订单不存在');
  58. }
  59. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  60. throw new \think\Exception('不在售后中状态,不能进行同意售后操作');
  61. }
  62. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_AGREE) {
  63. throw new \think\Exception('不是等待卖家同意状态,不能进行同意售后操作');
  64. }
  65. $after_sale_status = 2;
  66. switch($afterSale->refund_method) {
  67. // 仅退款
  68. case AfterSaleEnum::METHOD_ONLY_REFUND:
  69. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_WAIT_SELLER_REFUND;
  70. AfterSaleService::createAfterLog($afterSale->id, '卖家已同意,等待退款', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  71. $after_sale_status = 5;
  72. break;
  73. // 退货退款
  74. case AfterSaleEnum::METHOD_REFUND_GOODS:
  75. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_WAIT_BUYER_RETURN;
  76. AfterSaleService::createAfterLog($afterSale->id, '卖家已同意售后,等待买家退货', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  77. $after_sale_status = 4;
  78. break;
  79. }
  80. $afterSale->admin_id = $params['admin_id'];
  81. $afterSale->admin_remark = $params['admin_remark'] ?? '';
  82. $afterSale->save();
  83. Order::update([ 'after_sale_status' => $after_sale_status ], [
  84. [ 'id', '=', $afterSale['order_id'] ],
  85. ]);
  86. Db::commit();
  87. return true;
  88. } catch(\Exception $e) {
  89. Db::rollback();
  90. self::setError($e->getMessage());
  91. return false;
  92. }
  93. }
  94. /**
  95. * @notes 卖家拒绝售后
  96. * @param $params
  97. * @return bool
  98. * @author Tab
  99. * @date 2021/8/2 20:01
  100. */
  101. public static function refuse($params)
  102. {
  103. Db::startTrans();
  104. try{
  105. $afterSale = AfterSale::findOrEmpty($params['id']);
  106. if($afterSale->isEmpty()) {
  107. throw new \think\Exception('售后订单不存在');
  108. }
  109. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  110. throw new \think\Exception('不在售后中状态,不能进行拒绝售后操作');
  111. }
  112. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_AGREE) {
  113. throw new \think\Exception('不是等待卖家同意状态,不能进行拒绝售后操作');
  114. }
  115. $afterSale->status = AfterSaleEnum::STATUS_FAIL;
  116. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_SELLER_REFUSE_AFTER_SALE;
  117. $afterSale->admin_id = $params['admin_id'];
  118. $afterSale->admin_remark = $params['admin_remark'] ?? '';
  119. $afterSale->save();
  120. AfterSaleService::createAfterLog($afterSale->id, '卖家拒绝售后', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  121. // 消息通知
  122. event('Notice', [
  123. 'scene_id' => NoticeEnum::REFUND_REFUSE_NOTICE,
  124. 'params' => [
  125. 'user_id' => $afterSale->user_id,
  126. 'after_sale_sn' => $afterSale->sn
  127. ]
  128. ]);
  129. Order::update([ 'after_sale_status' => 3 ], [
  130. [ 'id', '=', $afterSale['order_id'] ],
  131. ]);
  132. Db::commit();
  133. return true;
  134. } catch(\Exception $e) {
  135. Db::rollback();
  136. self::setError($e->getMessage());
  137. return false;
  138. }
  139. }
  140. /**
  141. * @notes 卖家拒绝收货
  142. * @param $params
  143. * @return bool
  144. * @author Tab
  145. * @date 2021/8/3 12:02
  146. */
  147. public static function refuseGoods($params)
  148. {
  149. Db::startTrans();
  150. try {
  151. $afterSale = AfterSale::findOrEmpty($params['id']);
  152. if($afterSale->isEmpty()) {
  153. throw new \think\Exception('售后单不存在');
  154. }
  155. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  156. throw new \think\Exception('不是售后中状态,不能进行拒绝收货操作');
  157. }
  158. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_RECEIPT) {
  159. throw new \think\Exception('不是等待卖家收货状态,不允许进行拒绝收货操作');
  160. }
  161. $afterSale->status = AfterSaleEnum::STATUS_FAIL;
  162. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_SELLER_REFUSE_RECEIPT;
  163. $afterSale->admin_remark = $params['admin_remark'] ?? '';
  164. $afterSale->save();
  165. // 记录日志
  166. AfterSaleService::createAfterLog($afterSale->id, '卖家拒绝收货,售后失败', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  167. Db::commit();
  168. return true;
  169. } catch(\Exception $e) {
  170. Db::rollback();
  171. self::setError($e->getMessage());
  172. return false;
  173. }
  174. }
  175. /**
  176. * @notes 卖家确认收货
  177. * @param $params
  178. * @return bool
  179. * @author Tab
  180. * @date 2021/8/3 14:04
  181. */
  182. public static function confirmGoods($params)
  183. {
  184. Db::startTrans();
  185. try {
  186. $afterSale = AfterSale::findOrEmpty($params['id']);
  187. if($afterSale->isEmpty()) {
  188. throw new \think\Exception('售后单不存在');
  189. }
  190. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  191. throw new \think\Exception('不是售后中状态,不能进行确认收货操作');
  192. }
  193. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_RECEIPT) {
  194. throw new \think\Exception('不是等待卖家收货状态,不允许进行确认收货操作');
  195. }
  196. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_WAIT_SELLER_HANDLE;
  197. $afterSale->save();
  198. // 记录日志
  199. AfterSaleService::createAfterLog($afterSale->id, '卖家确认收货,等待卖家处理', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  200. Db::commit();
  201. return true;
  202. } catch(\Exception $e) {
  203. Db::rollback();
  204. self::setError($e->getMessage());
  205. return false;
  206. }
  207. }
  208. /**
  209. * @notes 卖家同意退款
  210. * @param $params
  211. * @return bool
  212. * @author Tab
  213. * @date 2021/8/3 14:24
  214. */
  215. public static function agreeRefund($params)
  216. {
  217. Db::startTrans();
  218. try {
  219. $afterSale = AfterSale::findOrEmpty($params['id']);
  220. if($afterSale->isEmpty()) {
  221. throw new \think\Exception('售后单不存在');
  222. }
  223. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  224. throw new \think\Exception('不是售后中状态,不能进行同意退款操作');
  225. }
  226. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_HANDLE) {
  227. throw new \think\Exception('不是等待卖家处理状态,不允许进行同意退款操作');
  228. }
  229. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_WAIT_SELLER_REFUND;
  230. $afterSale->save();
  231. // 记录日志
  232. AfterSaleService::createAfterLog($afterSale->id, '卖家已同意,等待退款', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  233. Db::commit();
  234. return true;
  235. } catch(\Exception $e) {
  236. Db::rollback();
  237. self::setError($e->getMessage());
  238. return false;
  239. }
  240. }
  241. /** 卖家拒绝退款
  242. * @notes
  243. * @param $params
  244. * @return bool
  245. * @author Tab
  246. * @date 2021/8/3 14:33
  247. */
  248. public static function refuseRefund($params)
  249. {
  250. Db::startTrans();
  251. try {
  252. $afterSale = AfterSale::findOrEmpty($params['id']);
  253. if($afterSale->isEmpty()) {
  254. throw new \think\Exception('售后单不存在');
  255. }
  256. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  257. throw new \think\Exception('不是售后中状态,不能进行拒绝退款操作');
  258. }
  259. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_HANDLE) {
  260. throw new \think\Exception('不是等待卖家处理状态,不允许进行拒绝退款操作');
  261. }
  262. $afterSale->status = AfterSaleEnum::STATUS_FAIL;
  263. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_SELLER_REFUSE_REFUND;
  264. $afterSale->save();
  265. // 记录日志
  266. AfterSaleService::createAfterLog($afterSale->id, '卖家拒绝退款,售后失败', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  267. Db::commit();
  268. return true;
  269. } catch(\Exception $e) {
  270. Db::rollback();
  271. self::setError($e->getMessage());
  272. return false;
  273. }
  274. }
  275. /**
  276. * @notes 卖家确认退款
  277. * @param $params
  278. * @return bool
  279. * @author Tab
  280. * @date 2021/8/3 10:59
  281. */
  282. public static function confirmRefund($params)
  283. {
  284. Db::startTrans();
  285. try {
  286. $afterSale = AfterSale::findOrEmpty($params['id']);
  287. if($afterSale->isEmpty()) {
  288. throw new \think\Exception('售后单不存在');
  289. }
  290. if($afterSale->status != AfterSaleEnum::STATUS_ING) {
  291. throw new \think\Exception('不是售后中状态,不能进行确认退款操作');
  292. }
  293. if($afterSale->sub_status != AfterSaleEnum::SUB_STATUS_WAIT_SELLER_REFUND) {
  294. throw new \think\Exception('不是等待卖家退款状态,不允许进行确认退款操作');
  295. }
  296. if($afterSale->refund_total_amount < $params['refund_total_amount']) {
  297. throw new \think\Exception('退款金额不能大于订单实付金额');
  298. }
  299. $afterSale->refund_total_amount = $params['refund_total_amount'];
  300. $afterSale->refund_way = $params['refund_way'];
  301. $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_SELLER_REFUND_ING;
  302. $afterSale->save();
  303. // 更新售后商品记录中的退款金额
  304. AfterSaleGoods::where('after_sale_id', $afterSale->id)->update(['refund_amount' => $params['refund_total_amount']]);
  305. // 记录日志
  306. AfterSaleService::createAfterLog($afterSale->id, '卖家已确认退款,售后退款中', $params['admin_id'], AfterSaleLogEnum::ROLE_SELLER);
  307. // 退款
  308. $order = Order::findOrEmpty($afterSale->order_id)->toArray();
  309. outFileLog($order,'refund_money','$order');
  310. RefundLogic::refund($afterSale->refund_way, $order, $afterSale->id, $afterSale->refund_total_amount);
  311. //更新订单状态
  312. RefundLogic::afterSaleRefundUpdate($afterSale->order_id);
  313. Order::update([ 'after_sale_status' => 6], [
  314. [ 'id', '=', $order['id'] ],
  315. ]);
  316. Db::commit();
  317. return true;
  318. } catch (\Exception $e) {
  319. Db::rollback();
  320. self::setError($e->getMessage());
  321. return false;
  322. }
  323. }
  324. /**
  325. * @notes 查看售后详情
  326. * @param $params
  327. * @return string[]
  328. * @author Tab
  329. * @date 2021/8/9 18:55
  330. */
  331. public static function detail($params)
  332. {
  333. // 售后信息
  334. $afterSale = self::afterSaleInfo($params);
  335. // 退货信息
  336. $returnGoodsInfo = self::returnGoodsInfo($afterSale);
  337. // 订单信息
  338. $orderInfo = self::orderInfo($afterSale);
  339. // 商品信息
  340. $goodsInfo = self::goodsInfo($afterSale);
  341. // 售后日志
  342. $afterSaleLog= self::afterSaleLog($afterSale);
  343. // 退款按钮
  344. $btns = self::btns($afterSale);
  345. return [
  346. 'after_sale' => $afterSale,
  347. 'return_goods_info' => $returnGoodsInfo,
  348. 'order_info' => $orderInfo,
  349. 'goods_info' => $goodsInfo,
  350. 'after_sale_log' => $afterSaleLog,
  351. 'btns' => $btns
  352. ];
  353. }
  354. /**
  355. * @notes 售后信息
  356. * @param $params
  357. * @return array
  358. * @author Tab
  359. * @date 2021/8/9 20:36
  360. */
  361. public static function afterSaleInfo($params)
  362. {
  363. $field = 'id,order_id,user_id,sn,refund_type,refund_type as refund_type_desc,refund_method,refund_method as refund_method_desc,status,status as status_desc,sub_status,refund_reason,refund_remark,refund_image,create_time,express_name,invoice_no,express_remark,express_image,voucher,express_time,admin_remark';
  364. $afterSale = AfterSale::field($field)->findOrEmpty($params['id'])->toArray();
  365. return $afterSale;
  366. }
  367. /**
  368. * @notes 退货信息
  369. * @param $afterSale
  370. * @return array
  371. * @author Tab
  372. * @date 2021/8/9 20:36
  373. */
  374. public static function returnGoodsInfo($afterSale)
  375. {
  376. $user = User::field('sn,nickname,mobile')->findOrEmpty($afterSale['user_id'])->toArray();
  377. return [
  378. 'user_sn' => $user['sn'],
  379. 'user_nickname' => $user['nickname'],
  380. 'user_mobile' => $user['mobile']
  381. ];
  382. }
  383. /**
  384. * @notes 订单信息
  385. * @param $afterSale
  386. * @return array
  387. * @author Tab
  388. * @date 2021/8/9 20:36
  389. */
  390. public static function orderInfo($afterSale)
  391. {
  392. $field = 'order_status,order_status as order_status_desc,sn,order_type,order_type as order_type_desc,order_terminal,order_terminal as order_terminal_desc,create_time,pay_status,pay_status as pay_status_desc,pay_way,pay_way as pay_way_desc,pay_time,confirm_take_time,express_status,delivery_type,verification_status';
  393. return Order::field($field)->append(['express_status_desc'])->findOrEmpty($afterSale['order_id'])->toArray();
  394. }
  395. /**
  396. * @notes 商品信息
  397. * @param $afterSale
  398. * @return array
  399. * @author Tab
  400. * @date 2021/8/9 20:39
  401. */
  402. public static function goodsInfo($afterSale)
  403. {
  404. // 商品信息
  405. $field = 'gi.goods_id,gi.image as item_image,gi.spec_value_str';
  406. $field .= ',g.name as goods_name,g.image as goods_image';
  407. $field .= ',og.goods_price,og.goods_num,og.original_price,og.total_price,og.change_price,og.discount_price,og.member_price,og.integral_price,og.total_pay_price';
  408. $field .= ',asg.refund_amount';
  409. $orderGoods = AfterSaleGoods::alias('asg')
  410. ->leftJoin('goods g', 'g.id = asg.goods_id')
  411. ->leftJoin('goods_item gi', 'gi.id = asg.item_id')
  412. ->leftJoin('order_goods og', 'og.id = asg.order_goods_id')
  413. ->field($field)
  414. ->where('asg.after_sale_id', $afterSale['id'])
  415. ->select()
  416. ->toArray();
  417. $goodsIds = array_column($orderGoods,'goods_id');
  418. $goodsSupplier = GoodsSupplier::alias('GS')
  419. ->join('goods G','G.supplier_id = GS.id')
  420. ->where(['G.id'=>$goodsIds])
  421. ->column('GS.name','G.id');
  422. // 商品合计信息
  423. $orderGoodsSum['sum_goods_num'] = $orderGoodsSum['sum_total_price'] = $orderGoodsSum['sum_discount_price'] = $orderGoodsSum['sum_total_pay_price'] = $orderGoodsSum['sum_refund_amount'] = 0;
  424. foreach($orderGoods as &$item) {
  425. $orderGoodsSum['sum_goods_num'] += $item['goods_num'];
  426. $orderGoodsSum['sum_total_price'] += $item['total_price'];
  427. $orderGoodsSum['sum_discount_price'] += $item['discount_price'];
  428. $orderGoodsSum['sum_total_pay_price'] += $item['total_pay_price'];
  429. $orderGoodsSum['sum_refund_amount'] += $item['refund_amount'];
  430. $item['goods_image'] = get_image([$item['item_image'], $item['goods_image']]);
  431. $item['supplier_name'] = $goodsSupplier[$item['goods_id']] ?? '';
  432. $item['member_discount'] = 0;
  433. if($item['member_price'] > 0){
  434. $item['member_discount'] = round(($item['original_price'] - $item['member_price']) * $item['goods_num'],2);
  435. }
  436. $item['coupon_discount'] = $item['discount_price'];
  437. $item['integral_discount'] = $item['integral_price'];
  438. $item['total_discount'] = round( $item['member_discount']+$item['coupon_discount']+$item['integral_discount'],2);
  439. $item['total_amount'] = round($item['original_price'] * $item['goods_num'],2);
  440. }
  441. return [
  442. 'order_goods' => $orderGoods,
  443. 'order_goods_sum' => $orderGoodsSum,
  444. ];
  445. }
  446. /**
  447. * @notes 售后日志
  448. * @param $afterSale
  449. * @return array
  450. * @throws \think\db\exception\DataNotFoundException
  451. * @throws \think\db\exception\DbException
  452. * @throws \think\db\exception\ModelNotFoundException
  453. * @author Tab
  454. * @date 2021/8/9 20:42
  455. */
  456. public static function afterSaleLog($afterSale)
  457. {
  458. $field = 'operator_role,operator_id,content,create_time';
  459. $afterSaleLog = AfterSaleLog::field($field)
  460. ->where('after_sale_id', $afterSale['id'])
  461. ->order('id', 'desc')
  462. ->select()
  463. ->toArray();
  464. foreach($afterSaleLog as &$item) {
  465. $item['operator_name'] = AfterSaleLogEnum::getOpertorName($item['operator_id'], $item['operator_role']);
  466. }
  467. return $afterSaleLog;
  468. }
  469. /**
  470. * @notes 退款按钮
  471. * @param $afterSale
  472. * @return mixed
  473. * @author Tab
  474. * @date 2021/8/10 9:40
  475. */
  476. public static function btns($afterSale)
  477. {
  478. return AfterSaleEnum::getBtns($afterSale);
  479. }
  480. }