Refund.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <?php
  2. namespace app\common\service\order;
  3. use app\common\model\fullsend\FullSendActivity as FullSendActivityModel;
  4. use app\common\enum\order\OrderStatus as OrderStatusEnum;
  5. use app\common\enum\order\ReceiptStatus;
  6. use app\common\exception\BaseException;
  7. use app\common\model\mj\MjSendActivity;
  8. use app\common\model\Order as OrderModel;
  9. use app\common\model\qc\QcMjSendActivity;
  10. use app\common\model\User as UserModel;
  11. use app\common\model\Wxapp as WxappModel;
  12. use app\common\model\user\BalanceLog as BalanceLogModel;
  13. use app\common\enum\order\PayType as PayTypeEnum;
  14. use app\common\enum\order\refund\RefundStatus as RefundStatusEnum;
  15. use app\common\enum\user\balanceLog\Scene as SceneEnum;
  16. use app\common\library\wechat\WxPay;
  17. use app\common\model\OrderGoods as OrderGoodsModel;
  18. use think\Log;
  19. /**
  20. * 订单退款服务类
  21. * Class Refund
  22. * @package app\common\service\order
  23. */
  24. class Refund
  25. {
  26. /**
  27. * 执行订单退款
  28. * @param \app\common\model\BaseModel $order 订单信息
  29. * @param double|null $money 指定退款金额
  30. * @return bool
  31. * @throws \think\Exception
  32. * @throws \think\exception\DbException
  33. * @throws \app\common\exception\BaseException
  34. */
  35. public function execute($order, $out_refund_no, $money = null)
  36. {
  37. // 退款金额,如不指定则默认为订单实付款金额
  38. is_null($money) && $money = $order['pay_price'];
  39. if(isset($order['parent_order_id'])&&$order['parent_order_id']>0){ //说明是子订单
  40. $order = OrderModel::find($order['parent_order_id']);
  41. }
  42. // 1.微信支付退款
  43. if ($order['pay_type'] == PayTypeEnum::WECHAT) {
  44. return $this->wechatRefund($order, $money,$out_refund_no);
  45. }
  46. // // 2.余额支付退款
  47. // if ($order['pay_type'] == PayTypeEnum::BALANCE) {
  48. // return $this->balance($order, $money,$out_refund_no);
  49. // }
  50. // // 2.支付宝退款
  51. // if ($order['pay_type'] == PayTypeEnum::ALIPAY) {
  52. // return $this->alipayRefund($order, $money,$out_refund_no);
  53. // }
  54. return false;
  55. }
  56. /**
  57. * 余额支付退款
  58. * @param $order
  59. * @param $money
  60. * @return bool
  61. * @throws \think\Exception
  62. * @throws \think\exception\DbException
  63. */
  64. private function balance(&$order, $money)
  65. {
  66. // 回退用户余额
  67. $user = UserModel::detail($order['user_id']);
  68. $user->setInc('balance', $money);
  69. // 记录余额明细
  70. BalanceLogModel::add(SceneEnum::REFUND, [
  71. 'user_id' => $user['user_id'],
  72. 'money' => $money,
  73. ], ['order_no' => $order['order_no']]);
  74. return true;
  75. }
  76. /**
  77. * 微信支付退款
  78. * @param $order
  79. * @param double $money
  80. * @return bool
  81. * @throws \app\common\exception\BaseException
  82. * @throws \think\exception\DbException
  83. */
  84. private function wxpay(&$order, $money)
  85. {
  86. $wxConfig = WxappModel::getWxappCache($order['wxapp_id']);
  87. $WxPay = new WxPay($wxConfig);
  88. return $WxPay->refund($order['transaction_id'], $order['pay_price'], $money);
  89. }
  90. //微信支付退款
  91. private function wechatRefund($order,$money,$out_refund_no){
  92. $wxConfig = WxappModel::find(10001);
  93. $WxPay = new WxPay($wxConfig);
  94. // $out_refund_no = OrderService::createOrderNo('TK');
  95. $payment = $WxPay->refundNew($order['order_no'], $out_refund_no, $order['pay_price'], $money);
  96. return $payment;
  97. }
  98. //支付宝退款
  99. private function alipayRefund($order,$money,$out_request_no){
  100. $refund_amount = $money;//退款金额
  101. $out_trade_no = $order['order_no']; //原支付订单号
  102. // $out_request_no = OrderService::createOrderNo('TK'); //退款订单号
  103. $refund_reason = '售后单退款'; //退款的原因说明
  104. $aliConfig = config('alipay');
  105. $aop = new \AopClient();
  106. $aop->gatewayUrl = $aliConfig['gateway_url'];
  107. $aop->appId = $aliConfig['app_id'];
  108. $aop->rsaPrivateKey = $aliConfig['private_key'];
  109. $aop->alipayrsaPublicKey=$aliConfig['public_key'];
  110. $aop->apiVersion = '1.0';
  111. $aop->postCharset='UTF-8';
  112. $aop->format='json';
  113. $aop->signType='RSA2';
  114. $request = new \AlipayTradeRefundRequest ();
  115. $bizContent = "{" .
  116. " \"refund_reason\":\"$refund_reason\"," .
  117. " \"out_trade_no\":\"$out_trade_no\"," .
  118. " \"out_request_no\":\"$out_request_no\"," .
  119. " \"refund_amount\":$refund_amount" .
  120. " }";
  121. $request->setBizContent($bizContent);
  122. $result = $aop->execute ( $request);
  123. $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
  124. $resultCode = $result->$responseNode->code;
  125. if(!empty($resultCode)&&$resultCode == 10000){
  126. // return ['code'=>0,'msg'=>'退款成功'];
  127. return true;
  128. } else {
  129. Log::error($result);
  130. throw new BaseException(['msg' => 'err_code_des: ' . $result->$responseNode->sub_msg]);
  131. }
  132. }
  133. //判断退货退款订单商品是否需要提示退回赠品
  134. public static function checkRefund($order_id,$order_goods_id,$refund_money){
  135. $order = OrderModel::get(['order_id'=>$order_id]);
  136. if(!$order){
  137. return false;
  138. }
  139. $goodFullPrice = 0;
  140. $isCheck = false;
  141. foreach ($order['goods'] as $good){
  142. if($good['full_send_activity_id']>0){
  143. $goodFullPrice += $good['total_price'];
  144. if($good['refund']['status'] == RefundStatusEnum::COMPLETED){
  145. $goodFullPrice -= $good['refund']['refund_money'];
  146. }
  147. }
  148. if($good['order_goods_id'] == $order_goods_id){
  149. $isCheck = true;
  150. }
  151. }
  152. if($isCheck){//
  153. $FullSendActivity = FullSendActivityModel::detail($order['full_send_activity_id']);
  154. if($goodFullPrice-$refund_money<$FullSendActivity['full_money']){//退款的商品不足满减条件了,就需要退回赠品
  155. return true;
  156. }
  157. }
  158. return false;
  159. }
  160. //判断满件送商品退款后的剩余的商品件数是否满足赠品活动条件,如不满足,弹窗提示将赠品一起寄回。-V1.3.7添加于2022年3月29日
  161. //$goods_num退回的商品数量
  162. public static function checkMjRefund($order_id,$order_goods_id,$goods_num){
  163. $order = OrderModel::get(['order_id'=>$order_id]);
  164. if(!$order){
  165. return 0;
  166. }
  167. $isCheck = 0;//需要退还的赠品套数
  168. foreach ($order['goods'] as $good){
  169. if($good['order_goods_id'] == $order_goods_id && $good['is_mj_send']==1){//是满件送活动
  170. $MjSendActivity = MjSendActivity::find($good['mj_send_activity_id']);
  171. $mj_props = array_values(array_sort($MjSendActivity['mj_props'], 'value', true));
  172. $c = $good['total_num']-$good['mj_send_use_count'];
  173. if($c>0){
  174. $c2 = $goods_num-$c;
  175. if($c2<=0){
  176. continue;
  177. }
  178. }
  179. $residue_num = $good['total_num']-$goods_num;//剩余商品数量
  180. $count = 0;
  181. foreach ($mj_props as $arr){
  182. if($residue_num>=$arr['value']){//商品数量大于当前活动满件送的最小数量
  183. $count = $arr['count'];
  184. break;
  185. }else{
  186. continue;
  187. }
  188. }
  189. $isCheck = $good['mj_send_count'] - $count;
  190. }
  191. }
  192. if($isCheck){//
  193. return $isCheck;
  194. }
  195. return 0;
  196. }
  197. //判断全场满件送商品退款后的剩余的商品件数是否满足赠品活动条件,如不满足,弹窗提示将赠品一起寄回。-V1.4.2添加于2022年7月12日
  198. //$goods_num退回的商品数量
  199. public static function checkQcMjRefund($order_id,$order_goods_id,$goods_num){
  200. $order = OrderModel::get(['order_id'=>$order_id]);
  201. if(!$order){
  202. return 0;
  203. }
  204. $act_count = 0;//全场满件送活动的剩余数量
  205. foreach ($order['goods'] as $good){
  206. if($good['qc_send_activity_id']>0){
  207. $act_count += $good['qc_send_use_count'];
  208. if($good['refund']['status'] == RefundStatusEnum::COMPLETED){
  209. $count = $good['total_num']-$good['qc_send_use_count'];
  210. if($count>0){
  211. if($good['refund']['goods_num']-$count>0){
  212. $act_count -= $good['refund']['goods_num']-$count;
  213. }
  214. }else{
  215. $act_count -= $good['refund']['goods_num'];
  216. }
  217. }
  218. }
  219. }
  220. $isCheck = 0;//需要退还的赠品套数
  221. foreach ($order['goods'] as $good){
  222. if($good['order_goods_id'] == $order_goods_id && $good['is_qc_send_send']==1){//是全场满件送活动
  223. $QcMjSendActivity = QcMjSendActivity::find($good['qc_send_activity_id']);
  224. $mj_props = array_values(array_sort($QcMjSendActivity['mj_props'], 'value', true));
  225. $c = $good['total_num']-$good['qc_send_use_count'];
  226. if($c>0){
  227. $c2 = $goods_num-$c;
  228. if($c2<=0){
  229. continue;
  230. }else{
  231. $residue_num = $act_count-$c2;//剩余商品数量
  232. }
  233. }else{
  234. $residue_num = $act_count-$goods_num;//剩余商品数量
  235. }
  236. $count = 0;
  237. foreach ($mj_props as $arr){
  238. if($residue_num>=$arr['value']){//商品数量大于当前活动满件送的最小数量
  239. $count = $arr['count'];
  240. break;
  241. }else{
  242. continue;
  243. }
  244. }
  245. $isCheck = $good['qc_send_count'] - $count;
  246. }
  247. }
  248. if($isCheck){//
  249. return $isCheck;
  250. }
  251. return 0;
  252. }
  253. }