海南旅游SAAS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.9 KiB

  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Controller;
  4. use App\Models\Agent;
  5. use App\Models\AgentProduct;
  6. use App\Models\Order;
  7. use App\Models\Product;
  8. use App\Models\UserMoneyLog;
  9. use EasyWeChat\Factory;
  10. use EasyWeChat\Kernel\Exceptions\Exception;
  11. use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;
  12. use Illuminate\Support\Facades\DB;
  13. use App\Service\OrderStatus;
  14. class WxpayController
  15. {
  16. //微信支付 支付结果通知网址
  17. public function notify()
  18. {
  19. // {"sign": "3F99E6044C503B0E0131F95A1410B630", "appid": "wxb35ef055a4dd8ad4", "mch_id": "1606181693", "openid": "oBYj55W0gLv5MYUnsYUuJfzYzmsg", "cash_fee": "1", "fee_type": "CNY", "time_end": "20210623222330", "bank_type": "OTHERS", "nonce_str": "60d343d820e94", "total_fee": "1", "trade_type": "JSAPI", "result_code": "SUCCESS", "return_code": "SUCCESS", "is_subscribe": "N", "out_trade_no": "2842908479209865216", "transaction_id": "4200001210202106237487333085"}
  20. $agent_id = request()->route('aid');
  21. $agent = Agent::find($agent_id);
  22. $config = config('wechat.payment.default');
  23. $config = array_merge($config, [
  24. 'app_id' => $agent->appid,
  25. 'mch_id' => $agent->mchid,
  26. 'key' => $agent->mchkey,
  27. ]);
  28. $app = Factory::payment($config);
  29. try {
  30. $response = $app->handlePaidNotify(function ($message, $fail) {
  31. // 请求成功
  32. if ($message['return_code'] === 'SUCCESS') {
  33. //订单号带有pay_type后缀,主要是为了区分定金支付和尾款支付,前24位才是真正的订单号
  34. $order_no = substr($message['out_trade_no'], 0, 24);
  35. $order = Order::query()
  36. ->where(['order_no' => $order_no])
  37. ->first();
  38. //已经处理过的订单直接返回true
  39. if ($order && in_array($order->status, [OrderStatus::PAID, OrderStatus::PAY_RETAINAGE])) {
  40. return true;
  41. }
  42. // 支付成功
  43. if ($message['result_code'] === 'SUCCESS') {
  44. DB::beginTransaction();
  45. try {
  46. $status = $order->status;
  47. $pay_type = $order->pay_type;
  48. //定金支付和首付款支付
  49. if (in_array($pay_type, [1, 2])) {
  50. if ($pay_type == OrderStatus::UNPAID) {
  51. $order->status = OrderStatus::PAY_EARNEST;
  52. } else if ($status == OrderStatus::PAY_EARNEST) {
  53. $order->status = OrderStatus::PAY_RETAINAGE;
  54. }
  55. } else if ($pay_type == 0) {
  56. $order->status = OrderStatus::PAID;
  57. }
  58. $money = $message['total_fee'] / 100;
  59. $order->paid_at = time();
  60. $order->paid_money = DB::raw('`paid_money` + ' . $money);
  61. $order->save();
  62. //增加销量,库存在拍下时已经减了
  63. AgentProduct::query()
  64. ->where('id', $order->agent_product_id)
  65. ->increment('sale', $order->num);
  66. Product::query()
  67. ->where('id', $order->product_id)
  68. ->increment('sale', $order->num);
  69. //资金流水
  70. UserMoneyLog::query()->create([
  71. 'user_id' => $order->user_id,
  72. 'agent_id' => $order->agent_id,
  73. 'money' => -$money,
  74. 'order_id' => $order->id,
  75. 'type' => 1,
  76. 'desc' => '购买产品:' . $order->title,
  77. 'created_at' => time(), //模型没有updated_at,无法自动写入时间
  78. ]);
  79. DB::commit();
  80. return true;
  81. } catch (\Exception $e) {
  82. DB::rollBack();
  83. $fail('Unknown error');
  84. }
  85. } // 支付失败
  86. else if ($message['result_code'] === 'FAIL') {
  87. return true;
  88. }
  89. }
  90. // 希望微信重试
  91. $fail('Order not exists.');
  92. });
  93. } catch (InvalidSignException | \Exception $e) {
  94. $time = time();
  95. $filename = storage_path('logs/wxpay_notify_') . date('Y-m-d-H', $time) . '.log';
  96. $data = '[' . date('Y-m-d H:i:s', $time) . ']' . PHP_EOL;
  97. $data .= '[message]:' . $e->getMessage() . $e->getFile() . $e->getLine() . PHP_EOL . PHP_EOL;
  98. file_put_contents($filename, $data, FILE_APPEND);
  99. return 'error';
  100. }
  101. return $response;
  102. }
  103. //退款通知
  104. public function refund()
  105. {
  106. // {"sign": "3F99E6044C503B0E0131F95A1410B630", "appid": "wxb35ef055a4dd8ad4", "mch_id": "1606181693", "openid": "oBYj55W0gLv5MYUnsYUuJfzYzmsg", "cash_fee": "1", "fee_type": "CNY", "time_end": "20210623222330", "bank_type": "OTHERS", "nonce_str": "60d343d820e94", "total_fee": "1", "trade_type": "JSAPI", "result_code": "SUCCESS", "return_code": "SUCCESS", "is_subscribe": "N", "out_trade_no": "2842908479209865216", "transaction_id": "4200001210202106237487333085"}
  107. $config = config('wechat.payment.default');
  108. $app = Factory::payment($config);
  109. $response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) {
  110. // 记录一下本地调试
  111. file_put_contents(storage_path('/wxpay/refund'.date('Y-m-d-H').'.log'), date('Y-m-d H:i:s').PHP_EOL.json_encode($message).PHP_EOL.json_encode($reqInfo), FILE_APPEND);
  112. // 请求成功
  113. if ($message['return_code'] === 'SUCCESS') {
  114. //订单号带有pay_type后缀,主要是为了区分定金支付和尾款支付,前24位才是真正的订单号
  115. $order_no = substr($message['out_trade_no'], 0, 24);
  116. $order = Order::query()
  117. ->where(['order_sn' => $order_no])
  118. ->first();
  119. // 退款成功
  120. if ($reqInfo['refund_status'] === 'SUCCESS') {
  121. DB::beginTransaction();
  122. try {
  123. $apply = RefundApply::query()
  124. ->where('refund_sn', $reqInfo['out_refund_no'])
  125. ->first();
  126. if (!$apply) {
  127. $fail('退款单没找到');
  128. }
  129. $apply->state = 2;
  130. $apply->save();
  131. $order->state = UserGoodsOrder::REFUNDED;
  132. $order->save();
  133. // 退库存
  134. GoodsSpecs::query()
  135. ->where([
  136. 'id' => $order->goods_specs_id,
  137. 'goods_id' => $order->goods_id,
  138. ])
  139. ->update([
  140. 'stock' => DB::raw('stock+'.$order->number.''),
  141. ]);
  142. DB::commit();
  143. return true;
  144. } catch (\Exception $e) {
  145. DB::rollBack();
  146. $fail('Unknown error');
  147. }
  148. }
  149. }
  150. $fail('Unknown error');
  151. });
  152. return $response;
  153. }
  154. }