PartnerPayment.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <?php
  2. namespace app\api\controller\xmwechat;
  3. use app\common\controller\Frontend;
  4. use app\common\library\xmwechat\payment\PartnerPayService;
  5. use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
  6. use EasyWeChat\Kernel\Exceptions\RuntimeException;
  7. use EasyWeChat\Pay\Application;
  8. use EasyWeChat\Pay\Message;
  9. use think\facade\Db;
  10. use think\facade\Log;
  11. use think\Request;
  12. /**
  13. * 合作伙伴(服务商模式支付)
  14. */
  15. class PartnerPayment extends Frontend
  16. {
  17. // 数组中的 pay、refunds 请在调试完成后删除,支付、退款接口需要登录
  18. protected array $noNeedLogin = ['pay', 'refunds', 'payNotify', 'refundsNotify'];
  19. protected array $partnerPaymentConfig;
  20. protected array $wechatPartnerConfig;
  21. public function initialize(): void
  22. {
  23. parent::initialize();
  24. $config = config('xmwechat');
  25. $this->partnerPaymentConfig = $config['partnerPayment'];
  26. $this->wechatPartnerConfig = [
  27. 'mch_id' => $this->partnerPaymentConfig['sp_mchid'],
  28. 'secret_key' => $this->partnerPaymentConfig['secret_key'],
  29. 'certificate' => $this->partnerPaymentConfig['certificate'],
  30. 'private_key' => $this->partnerPaymentConfig['sp_mchid'],
  31. 'notify_url' => $this->partnerPaymentConfig['notify_url'],
  32. 'http' => [
  33. 'throw' => true, // 状态码非 200、300 时是否抛出异常,默认为开启
  34. 'timeout' => 5.0,
  35. ],
  36. ];
  37. }
  38. /**
  39. * 微信公众号、小程序支付示例(合作伙伴服务商模式)
  40. * 支付接口是需要登录的,测试结束后,请在最上方$noNeedLogin数组中去掉 pay
  41. * @param Request $request
  42. * @return void
  43. * @throws \Exception
  44. * @author jsjxsz
  45. * order_no 订单号
  46. * body 描述
  47. * pay_price 支付金额
  48. * openid 用户openid
  49. * transaction_no 交易号
  50. */
  51. public function pay(Request $request): void
  52. {
  53. if ($request->isPost()) {
  54. $params = $request->only(['order_no', 'body', 'pay_price', 'openid', 'transaction_no']);
  55. // miniProgram: 小程序支付; offiAccount: 公众号支付
  56. $params['pay_type'] = 'miniProgram';
  57. $result = PartnerPayService::getInstance()->pay($params);
  58. if ($result !== false) {
  59. $this->success('success', $result);
  60. } else {
  61. $this->error('error');
  62. }
  63. }
  64. }
  65. /**
  66. * 退款申请(退款状态需在退款回调中获取)
  67. * @param Request $request
  68. * @return void
  69. * @author jsjxsz
  70. * out_trade_no 原支付交易对应的商户订单号
  71. * out_refund_no 商户退款单号,商户系统内部的退款单号,退款时生成,唯一
  72. * reason 退款原因
  73. * refund_price 退款金额
  74. * pay_price 原交易金额
  75. */
  76. public function refunds(Request $request): void
  77. {
  78. if ($request->isPost()) {
  79. $params = $request->only(['pay_price', 'refund_price', 'out_trade_no','out_refund_no','reason']);
  80. $result = PartnerPayService::getInstance()->refunds($params);
  81. if ($result !== false) {
  82. $this->success('success', $result);
  83. } else {
  84. $this->error('error');
  85. }
  86. }
  87. }
  88. /**
  89. * 服务商模式支付回调
  90. * 注意仔细看下面的注释内容
  91. * @return \Psr\Http\Message\ResponseInterface|void
  92. * @author jsjxsz
  93. */
  94. public function payNotify()
  95. {
  96. try {
  97. $app = new Application($this->wechatPartnerConfig);
  98. $server = $app->getServer();
  99. $server->handlePaid(function (Message $message, \Closure $next) use ($app) {
  100. $noyifyData = json_decode($message, true);
  101. $success_time = strtotime($noyifyData['success_time']);
  102. $out_trade_no = $noyifyData['out_trade_no'];
  103. /**
  104. * 这里写你自己的逻辑 start
  105. */
  106. // 这里查询你自己的数据表!!!
  107. $order = Db::name('order')->where('transaction_no', $out_trade_no)->find();
  108. if (!$order || $order['pay_status'] == 1) {
  109. // 如果订单不存在 或者 订单已经支付过了
  110. // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  111. return ['code' => 'SUCCESS', 'message' => '成功'];
  112. }
  113. // return_code 表示通信状态,不代表支付状态
  114. if ($noyifyData['trade_state'] === 'SUCCESS') {
  115. // pay success
  116. $total_fee = $noyifyData['amount']['payer_total'] / 100;//单位分
  117. // 这里写你自己的回调逻辑
  118. } elseif ($message['result_code'] === 'FAIL') {
  119. // pay fail
  120. }
  121. /**
  122. * 这里写你自己的逻辑 end
  123. */
  124. return $next($message);
  125. });
  126. return $server->serve();
  127. } catch (InvalidArgumentException|RuntimeException|\ReflectionException|\Throwable $e) {
  128. Log::info('服务商微信支付回调通知:' . $e->getMessage());
  129. }
  130. }
  131. /**
  132. * 服务商模式退款回调
  133. * 注意仔细看下面的注释内容
  134. * @return \Psr\Http\Message\ResponseInterface|void
  135. * @author jsjxsz
  136. */
  137. public function refundsNotify()
  138. {
  139. try {
  140. $app = new Application($this->wechatPartnerConfig);
  141. $server = $app->getServer();
  142. $server->handleRefunded(function (Message $message, \Closure $next) use ($app) {
  143. $noyifyData = json_decode($message, true);
  144. $success_time = strtotime($noyifyData['success_time']); // 退款时间
  145. $out_refund_no = $noyifyData['out_refund_no'];
  146. /**
  147. * 这里写你自己的逻辑 start
  148. */
  149. // 这里查询你自己的数据表!!!
  150. $order_refunds = Db::name('order_refunds')->where('out_refund_no', $out_refund_no)->find();
  151. if (!$order_refunds || $order_refunds['refund_status'] == 1) {
  152. // 如果订单不存在 或者 订单已经支付过了
  153. // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  154. return ['code' => 'SUCCESS', 'message' => '成功'];
  155. }
  156. // return_code 表示通信状态,不代表支付状态
  157. if ($noyifyData['refund_status'] === 'SUCCESS') {
  158. // success
  159. } elseif ($message['result_code'] === 'FAIL') {
  160. // pay fail
  161. }
  162. /**
  163. * 这里写你自己的逻辑 end
  164. */
  165. return $next($message);
  166. });
  167. return $server->serve();
  168. } catch (InvalidArgumentException|RuntimeException|\ReflectionException|\Throwable $e) {
  169. Log::info('服务商微信退款回调通知:' . $e->getMessage());
  170. }
  171. }
  172. }