SfPayController.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\logic\api\SfPayLogic;
  4. use App\Http\logic\api\SfPayCashierLogic;
  5. use App\Inter\PayMentInterFace;
  6. use App\Notification\TelegramBot;
  7. use App\Services\SfPay;
  8. use App\Util;
  9. use App\Utility\SetNXLock;
  10. use Illuminate\Http\Request;
  11. use Illuminate\Support\Facades\Redis;
  12. class SfPayController implements PayMentInterFace
  13. {
  14. /**
  15. * 代收下单
  16. */
  17. public function pay_order(
  18. $userId,
  19. $payAmt,
  20. $userName,
  21. $userEmail,
  22. $userPhone,
  23. $GiftsID,
  24. $buyIP,
  25. $AdId,
  26. $eventType,
  27. $pay_method = ''
  28. ) {
  29. $logic = new SfPayLogic();
  30. try {
  31. $res = $logic->pay_order($userId, $payAmt, $userPhone, $userEmail, $userName, $GiftsID, $buyIP, $AdId, $eventType, $pay_method);
  32. } catch (\Exception $exception) {
  33. Redis::set("PayErro_SfPay", 1);
  34. Redis::expire("PayErro_SfPay", 600);
  35. Util::WriteLog('SfPay_error', $exception->getMessage() . json_encode($logic->result ?? []));
  36. TelegramBot::getDefault()->sendProgramNotify("SfPay Except ", $exception->getMessage(), $exception);
  37. return apiReturnFail($logic->getError());
  38. }
  39. if (!empty($res) && isset($res['code']) && $res['code'] === 0) {
  40. // SfPay 成功返回: data.paymentLinkUrl 是支付链接
  41. $data = [
  42. 'content' => $res['data']['paymentLinkUrl'] ?? '',
  43. 'money' => $payAmt,
  44. 'prdOrdNo' => $res['data']['orderNo'] ?? '',
  45. ];
  46. return apiReturnSuc($data);
  47. }
  48. if ($res == false) {
  49. return apiReturnFail($logic->getError() ?: 'Payment failed');
  50. }
  51. // 非0的响应,记录错误
  52. Redis::set("PayErro_SfPay", 1);
  53. Redis::expire("PayErro_SfPay", 600);
  54. $errMsg = $res['msg'] ?? 'Unknown error';
  55. TelegramBot::getDefault()->sendProgramNotify("SfPay ReturnFail ", $errMsg . " | " . json_encode($res) . "$userId");
  56. return apiReturnFail(['web.payment.paytype_error', $errMsg]);
  57. }
  58. /**
  59. * 代收异步回调通知
  60. *
  61. * SfPay回调格式(POST JSON,不加密):
  62. * {
  63. * "data": {
  64. * "amount": "20.00",
  65. * "orderNo": "...",
  66. * "message": "Success",
  67. * "type": "payment",
  68. * "merchantOrderNo": "...",
  69. * "processedTime": "...",
  70. * "transferMode": "PIX",
  71. * "status": "SUCCESS"
  72. * },
  73. * "signature_n": "..."
  74. * }
  75. */
  76. public function notify(Request $request)
  77. {
  78. $post = $request->all();
  79. $payload = json_encode($post);
  80. Util::WriteLog('SfPay', "SfPay回调订单\n" . $payload);
  81. $callbackData = $post['data'] ?? [];
  82. $signatureN = $post['signature_n'] ?? '';
  83. if (empty($callbackData) || empty($signatureN)) {
  84. Util::WriteLog('SfPay', '回调数据不完整');
  85. return response()->json(['code' => 200]);
  86. }
  87. // 验签
  88. $service = new SfPay();
  89. if (!$service->verifySign($callbackData, $signatureN)) {
  90. Util::WriteLog('SfPay', '签名错误');
  91. return response()->json(['code' => 200]);
  92. }
  93. $order_sn = $callbackData['merchantOrderNo'] ?? '';
  94. if (empty($order_sn)) {
  95. Util::WriteLog('SfPay', '缺少商户订单号');
  96. return response()->json(['code' => 200]);
  97. }
  98. // 代收回调加锁,防止并发重复处理
  99. $lockKey = 'pay_notify_SfPay_' . $order_sn;
  100. if (!SetNXLock::getExclusiveLock($lockKey, 60)) {
  101. Util::WriteLog('SfPay', '代收回调并发,订单已处理或处理中: ' . $order_sn);
  102. return response()->json(['code' => 200]);
  103. }
  104. $logic = new SfPayLogic();
  105. try {
  106. $ret = $logic->notify($post);
  107. return response()->json(['code' => 200]);
  108. } catch (\Exception $exception) {
  109. Redis::set("PayErro_SfPay", 1);
  110. Redis::expire("PayErro_SfPay", 600);
  111. TelegramBot::getDefault()->sendProgramNotify("SfPay 订单回调执行异常 ", json_encode($post), $exception);
  112. Util::WriteLog("SfPay_error", $post);
  113. return response()->json(['code' => 200]);
  114. } finally {
  115. SetNXLock::release($lockKey);
  116. }
  117. }
  118. /**
  119. * 代付异步回调通知
  120. *
  121. * SfPay代付回调格式(POST JSON,不加密):
  122. * {
  123. * "data": {
  124. * "amount": "30.00",
  125. * "orderNo": "...",
  126. * "message": "...",
  127. * "type": "payout",
  128. * "merchantOrderNo": "...",
  129. * "processedTime": "...",
  130. * "processAmount": "0.00",
  131. * "status": "SUCCESS"
  132. * },
  133. * "signature_n": "..."
  134. * }
  135. */
  136. public function cash_notify(Request $request)
  137. {
  138. $post = $request->all();
  139. $payload = json_encode($post);
  140. Util::WriteLog('SfPay', "SfPay 提现回调\n" . $payload);
  141. $callbackData = $post['data'] ?? [];
  142. $signatureN = $post['signature_n'] ?? '';
  143. if (empty($callbackData) || empty($signatureN)) {
  144. Util::WriteLog('SfPay', '提现回调数据不完整');
  145. return response('SUCCESS');
  146. }
  147. // 验签
  148. $service = new SfPay();
  149. if (!$service->verifySign($callbackData, $signatureN)) {
  150. Util::WriteLog('SfPay', '提现回调签名错误');
  151. return response('SUCCESS');
  152. }
  153. $logic = new SfPayCashierLogic();
  154. try {
  155. return $logic->notify($post);
  156. } catch (\Exception $exception) {
  157. TelegramBot::getDefault()->sendProgramNotify(
  158. "SfPay 提现异步回调执行异常 ",
  159. json_encode($post),
  160. $exception
  161. );
  162. Util::WriteLog("SfPay_error", $post);
  163. return response('SUCCESS');
  164. }
  165. }
  166. /**
  167. * 代收订单主动查询
  168. *
  169. * POST /api/sfpay/orderQuery
  170. * 用于回调未到达时主动查询订单状态
  171. */
  172. public function orderQuery(Request $request)
  173. {
  174. $merchantOrderNo = $request->input('merchantOrderNo', '');
  175. if (empty($merchantOrderNo)) {
  176. return apiReturnFail('merchantOrderNo is required');
  177. }
  178. $logic = new SfPayLogic();
  179. try {
  180. $res = $logic->orderQuery($merchantOrderNo);
  181. } catch (\Exception $e) {
  182. Util::WriteLog('SfPay_error', 'orderQuery exception: ' . $e->getMessage());
  183. return apiReturnFail('Query failed');
  184. }
  185. if ($res === false) {
  186. return apiReturnFail($logic->getError() ?: 'Query failed');
  187. }
  188. if (isset($res['code']) && $res['code'] === 0) {
  189. return apiReturnSuc($res['data'] ?? []);
  190. }
  191. return apiReturnFail($res['msg'] ?? 'Query error');
  192. }
  193. }