MixedPayService.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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\pay;
  20. use app\common\enum\AccountLogEnum;
  21. use app\common\enum\PayEnum;
  22. use app\common\logic\AccountLogLogic;
  23. use app\common\model\User;
  24. use think\facade\Db;
  25. /**
  26. * 混合支付服务(余额+微信)
  27. * Class MixedPayService
  28. * @package app\common\service\pay
  29. */
  30. class MixedPayService extends BasePayService
  31. {
  32. protected $wechatPayService;
  33. protected $balancePayService;
  34. public function __construct($terminal, $userId = null)
  35. {
  36. try {
  37. $this->wechatPayService = new WeChatPayService($terminal, $userId);
  38. $this->balancePayService = new BalancePayService();
  39. } catch (\Exception $e) {
  40. $this->setError('混合支付服务初始化失败:' . $e->getMessage());
  41. }
  42. }
  43. /**
  44. * @notes 获取真实支付对象
  45. * @return mixed
  46. */
  47. function realPay()
  48. {
  49. return $this->wechatPayService->realPay();
  50. }
  51. /**
  52. * @notes 混合支付(余额+微信)
  53. * @param $from 订单类型
  54. * @param $order 订单信息
  55. * @return array|false
  56. * @author 系统
  57. * @date 2024/12/19
  58. */
  59. public function pay($from, $order)
  60. {
  61. Db::startTrans();
  62. try {
  63. $user = User::findOrEmpty($order['user_id']);
  64. if ($user->isEmpty()) {
  65. throw new \Exception('用户不存在');
  66. }
  67. // 记录调试日志
  68. file_put_contents(
  69. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  70. "[" . date('Y-m-d H:i:s') . "] 混合支付开始 - 用户ID: {$order['user_id']}, 订单号: {$order['sn']}, 订单金额: {$order['order_amount']}" . PHP_EOL,
  71. FILE_APPEND | LOCK_EX
  72. );
  73. $userBalance = $user['user_money']; // 用户余额
  74. $orderAmount = $order['order_amount']; // 订单金额
  75. // 记录余额信息
  76. file_put_contents(
  77. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  78. "[" . date('Y-m-d H:i:s') . "] 用户余额: {$userBalance}, 订单金额: {$orderAmount}" . PHP_EOL,
  79. FILE_APPEND | LOCK_EX
  80. );
  81. // 如果余额足够支付全部订单,直接使用余额支付
  82. if ($userBalance >= $orderAmount) {
  83. file_put_contents(
  84. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  85. "[" . date('Y-m-d H:i:s') . "] 余额充足,使用纯余额支付" . PHP_EOL,
  86. FILE_APPEND | LOCK_EX
  87. );
  88. $result = $this->balancePayService->pay($from, $order);
  89. if ($result === false) {
  90. throw new \Exception('余额支付失败:' . $this->balancePayService->getError());
  91. }
  92. Db::commit();
  93. return $result;
  94. }
  95. // 余额不足,使用混合支付
  96. $balanceAmount = $userBalance; // 使用全部余额
  97. $wechatAmount = $orderAmount - $balanceAmount; // 剩余金额用微信支付
  98. file_put_contents(
  99. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  100. "[" . date('Y-m-d H:i:s') . "] 使用混合支付 - 余额部分: {$balanceAmount}, 微信部分: {$wechatAmount}" . PHP_EOL,
  101. FILE_APPEND | LOCK_EX
  102. );
  103. // 先扣除用户余额
  104. if ($balanceAmount > 0) {
  105. User::update([
  106. 'user_money' => ['dec', $balanceAmount]
  107. ], ['id' => $order['user_id']]);
  108. // 记录余额流水
  109. AccountLogLogic::add(
  110. $order['user_id'],
  111. AccountLogEnum::BNW_DEC_ORDER,
  112. AccountLogEnum::DEC,
  113. $balanceAmount,
  114. $order['sn'],
  115. '混合支付-余额部分'
  116. );
  117. file_put_contents(
  118. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  119. "[" . date('Y-m-d H:i:s') . "] 余额扣除成功,扣除金额: {$balanceAmount}" . PHP_EOL,
  120. FILE_APPEND | LOCK_EX
  121. );
  122. }
  123. // 创建微信支付订单(金额为剩余需要支付的金额)
  124. $wechatOrder = $order;
  125. $wechatOrder['order_amount'] = $wechatAmount;
  126. $wechatOrder['balance_amount'] = $balanceAmount; // 记录已使用的余额金额
  127. file_put_contents(
  128. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  129. "[" . date('Y-m-d H:i:s') . "] 开始创建微信支付订单,金额: {$wechatAmount}" . PHP_EOL,
  130. FILE_APPEND | LOCK_EX
  131. );
  132. $result = $this->wechatPayService->pay($from, $wechatOrder);
  133. if ($result === false) {
  134. throw new \Exception('微信支付创建失败:' . $this->wechatPayService->getError());
  135. }
  136. // 在返回结果中添加混合支付信息
  137. $result['pay_way'] = PayEnum::MIXED_PAY;
  138. $result['balance_amount'] = $balanceAmount;
  139. $result['wechat_amount'] = $wechatAmount;
  140. $result['total_amount'] = $orderAmount;
  141. file_put_contents(
  142. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  143. "[" . date('Y-m-d H:i:s') . "] 混合支付创建成功" . PHP_EOL,
  144. FILE_APPEND | LOCK_EX
  145. );
  146. Db::commit();
  147. return $result;
  148. } catch (\Exception $e) {
  149. Db::rollback();
  150. file_put_contents(
  151. runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log',
  152. "[" . date('Y-m-d H:i:s') . "] 混合支付失败: " . $e->getMessage() . PHP_EOL,
  153. FILE_APPEND | LOCK_EX
  154. );
  155. $this->setError($e->getMessage());
  156. return false;
  157. }
  158. }
  159. /**
  160. * @notes 混合支付退款
  161. * @param $order 订单信息
  162. * @param $refundAmount 退款金额
  163. * @param $afterSaleId 售后ID
  164. * @return bool
  165. */
  166. public function refund($order, $refundAmount, $afterSaleId)
  167. {
  168. try {
  169. // 获取订单的余额支付金额和微信支付金额
  170. $balanceAmount = $order['balance_amount'] ?? 0;
  171. $wechatAmount = $order['order_amount'] - $balanceAmount;
  172. // 按比例退款
  173. if ($refundAmount >= $order['order_amount']) {
  174. // 全额退款
  175. $refundBalanceAmount = $balanceAmount;
  176. $refundWechatAmount = $wechatAmount;
  177. } else {
  178. // 部分退款,按比例分配
  179. $refundRatio = $refundAmount / $order['order_amount'];
  180. $refundBalanceAmount = $balanceAmount * $refundRatio;
  181. $refundWechatAmount = $wechatAmount * $refundRatio;
  182. }
  183. // 退回余额
  184. if ($refundBalanceAmount > 0) {
  185. $this->balancePayService->refund($order, $refundBalanceAmount, $afterSaleId);
  186. }
  187. // 微信退款
  188. if ($refundWechatAmount > 0) {
  189. // 这里需要调用微信退款接口
  190. $refundData = [
  191. 'out_trade_no' => $order['sn'],
  192. 'out_refund_no' => 'refund_' . $order['sn'] . '_' . time(),
  193. 'total_fee' => $wechatAmount * 100, // 原订单金额(分)
  194. 'refund_fee' => $refundWechatAmount * 100, // 退款金额(分)
  195. ];
  196. $this->wechatPayService->refund($refundData);
  197. }
  198. return true;
  199. } catch (\Exception $e) {
  200. $this->setError($e->getMessage());
  201. return false;
  202. }
  203. }
  204. }