AfterSaleService.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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\common\service\after_sale;
  20. use app\adminapi\logic\marketing\CouponLogic;
  21. use app\common\enum\AfterSaleEnum;
  22. use app\common\enum\AfterSaleLogEnum;
  23. use app\common\enum\DeliveryEnum;
  24. use app\common\enum\OrderEnum;
  25. use app\common\enum\YesNoEnum;
  26. use app\common\logic\RefundLogic;
  27. use app\common\model\AfterSale;
  28. use app\common\model\AfterSaleLog;
  29. use app\common\model\AfterSaleGoods;
  30. use app\common\model\Coupon;
  31. use app\common\model\CouponList;
  32. use app\common\model\Goods;
  33. use app\common\model\GoodsItem;
  34. use app\common\model\Order;
  35. use app\common\model\OrderGoods;
  36. use app\common\service\ConfigService;
  37. /**
  38. * 售后服务类
  39. * Class AfterSaleService
  40. * @package app\common\service
  41. */
  42. class AfterSaleService
  43. {
  44. /**
  45. * @notes 整单退款
  46. * 调用者需开启事务以保证数据写入的一致性
  47. * @param $params array order_id 订单号 、 scene 场景 1-买家取消订单 2-卖家取消订单 3-支付加调时订单已取消
  48. * @throws \think\Exception
  49. * @throws \think\db\exception\DataNotFoundException
  50. * @throws \think\db\exception\DbException
  51. * @throws \think\db\exception\ModelNotFoundException
  52. * @author Tab
  53. * @date 2021/8/2 10:36
  54. */
  55. public static function orderRefund($params)
  56. {
  57. // 校验是否允许发起整单退款
  58. self::checkCondition($params);
  59. // 生成售后记录
  60. self::createAfterSale($params);
  61. }
  62. /**
  63. * @notes 校验是否允许发起整单退款
  64. * @param $orderId 订单号
  65. * @throws \think\Exception
  66. * @throws \think\db\exception\DataNotFoundException
  67. * @throws \think\db\exception\DbException
  68. * @throws \think\db\exception\ModelNotFoundException
  69. * @author Tab
  70. * @date 2021/8/2 9:26
  71. */
  72. public static function checkCondition($params)
  73. {
  74. $order = Order::findOrEmpty($params['order_id']);
  75. if($order->isEmpty()) {
  76. throw new \think\Exception('订单不存在,无法发起整单退款');
  77. }
  78. $order = $order->toArray();
  79. if($order['pay_status'] != YesNoEnum::YES) {
  80. throw new \think\Exception('订单未付款,不允许发起整单退款');
  81. }
  82. if($order['order_status'] != OrderEnum::STATUS_WAIT_DELIVERY && $order['order_status'] != OrderEnum::STATUS_CLOSE && $order['delivery_type'] != DeliveryEnum::SELF_DELIVERY) {
  83. // 订单已关闭的情况之一:用户完成支付完后但第三方未及时调用我方支付回调,有可能此时用户手动或后台手动取消订单了订单
  84. throw new \think\Exception('订单已发货,不允许发起整单退款');
  85. }
  86. $aferSale = AfterSale::where([
  87. ['order_id', '=', $order['id']],
  88. ['status', '=', AfterSaleEnum::STATUS_SUCCESS]
  89. ])->select()->toArray();
  90. if($aferSale) {
  91. throw new \think\Exception('该订单已售后成功, 不能重复发起售后');
  92. }
  93. $aferSale = AfterSale::where([
  94. ['order_id', '=', $order['id']],
  95. ['status', '=', AfterSaleEnum::STATUS_ING]
  96. ])->select()->toArray();
  97. if($aferSale) {
  98. throw new \think\Exception('该订单已在售后中,请耐心等待');
  99. }
  100. }
  101. /**
  102. * @notes 生成售后记录
  103. * @param $params
  104. * @throws \think\db\exception\DataNotFoundException
  105. * @throws \think\db\exception\DbException
  106. * @throws \think\db\exception\ModelNotFoundException
  107. * @author Tab
  108. * @date 2021/8/2 10:38
  109. */
  110. public static function createAfterSale($params)
  111. {
  112. $order = Order::findOrEmpty($params['order_id'])->toArray();
  113. // 生成售后主表记录
  114. $data = [
  115. 'sn' => generate_sn((new AfterSale()), 'sn'),
  116. 'user_id' => $order['user_id'],
  117. 'order_id' => $order['id'],
  118. 'refund_reason' => AfterSaleLogEnum::getSenceDesc($params['scene']),
  119. 'refund_remark' => '系统发起整单退款',
  120. 'refund_type' => AfterSaleEnum::REFUND_TYPE_ORDER,
  121. 'refund_method' => AfterSaleEnum::METHOD_ONLY_REFUND,
  122. 'refund_way' => AfterSaleEnum::REFUND_WAYS_ORIGINAL,
  123. 'refund_total_amount' => $order['order_amount'],
  124. 'status' => AfterSaleEnum::STATUS_ING,
  125. 'sub_status' => AfterSaleEnum::SUB_STATUS_SELLER_REFUND_ING,
  126. 'refund_status' => AfterSaleEnum::NO_REFUND
  127. ];
  128. $afterSale = AfterSale::create($data);
  129. // 生成售后商品记录
  130. $orderGoods = OrderGoods::where('order_id', $order['id'])->select()->toArray();
  131. $data = [];
  132. foreach($orderGoods as $item) {
  133. $data[] = [
  134. 'after_sale_id' => $afterSale->id,
  135. 'order_goods_id' => $item['id'],
  136. 'goods_id' => $item['goods_id'],
  137. 'item_id' => $item['item_id'],
  138. 'goods_price' => $item['goods_price'],
  139. 'goods_num' => $item['goods_num'],
  140. 'refund_amount' => $item['total_pay_price']
  141. ];
  142. }
  143. (new AfterSaleGoods())->saveAll($data);
  144. // 生成售后日志
  145. $msg = ',系统发起整单退款';
  146. switch($params['scene']) {
  147. case AfterSaleLogEnum::BUYER_CANCEL_ORDER:
  148. $content = AfterSaleLogEnum::getSenceDesc(AfterSaleLogEnum::BUYER_CANCEL_ORDER) . $msg;
  149. self::createAfterLog($afterSale->id, $content, null, AfterSaleLogEnum::ROLE_SYS);
  150. break;
  151. case AfterSaleLogEnum::SELLER_CANCEL_ORDER:
  152. $content = AfterSaleLogEnum::getSenceDesc(AfterSaleLogEnum::SELLER_CANCEL_ORDER) . $msg;
  153. self::createAfterLog($afterSale->id, $content, null, AfterSaleLogEnum::ROLE_SYS);
  154. break;
  155. case AfterSaleLogEnum::ORDER_CLOSE:
  156. $content = AfterSaleLogEnum::getSenceDesc(AfterSaleLogEnum::ORDER_CLOSE) . $msg;
  157. self::createAfterLog($afterSale->id, $content, null, AfterSaleLogEnum::ROLE_SYS);
  158. break;
  159. }
  160. // 整单退款
  161. RefundLogic::refund(AfterSaleEnum::REFUND_WAYS_ORIGINAL, $order, $afterSale->id, $order['order_amount']);
  162. }
  163. /**
  164. * @notes 生成售后日志
  165. * @param $type
  166. * @param $afterSaleId
  167. * @param $content
  168. * @param null $operatorId
  169. * @author Tab
  170. * @date 2021/8/2 9:57
  171. */
  172. public static function createAfterLog($afterSaleId, $content, $operatorId = null,$operatorRole = null)
  173. {
  174. $data = [
  175. 'after_sale_id' => $afterSaleId,
  176. 'content' => $content,
  177. 'operator_id' => $operatorId,
  178. 'operator_role' => $operatorRole
  179. ];
  180. AfterSaleLog::create($data);
  181. }
  182. /**
  183. * @notes 退还库存
  184. * @param $params
  185. * @throws \think\db\exception\DataNotFoundException
  186. * @throws \think\db\exception\DbException
  187. * @throws \think\db\exception\ModelNotFoundException
  188. * @author Tab
  189. * @date 2021/8/2 10:34
  190. */
  191. public static function returnInventory($params)
  192. {
  193. $orderGoods = OrderGoods::where(['order_id' => $params['order_id']])->select()->toArray();
  194. foreach($orderGoods as $item) {
  195. $goods = Goods::findOrEmpty($item['goods_id']);
  196. $goodsItem = GoodsItem::findOrEmpty($item['item_id']);
  197. if($goods->isEmpty() || $goodsItem->isEmpty()){
  198. continue;
  199. }
  200. $goodsItem->stock = $goodsItem->stock + $item['goods_num'];
  201. $goodsItem->save();
  202. $goods->total_stock = $goods->total_stock + $item['goods_num'];
  203. $goods->save();
  204. }
  205. }
  206. /**
  207. * @notes 退还优惠券
  208. * @param $order
  209. * @author Tab
  210. * @date 2021/8/18 15:36
  211. */
  212. public static function returnCoupon($order)
  213. {
  214. if(empty($order['coupon_list_id'])) {
  215. return false;
  216. }
  217. $couponList = CouponList::findOrEmpty($order['coupon_list_id'])->toArray();
  218. // 重新发放一张新优惠券
  219. CouponLogic::send([
  220. 'id' => $couponList['coupon_id'],
  221. 'send_user_num' => 1,
  222. 'send_user' => [$order['user_id']],
  223. ]);
  224. }
  225. }