PayPal.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <?php
  2. namespace App\Http\Controllers\Gateway;
  3. use App\Models\Payment;
  4. use Auth;
  5. use Exception;
  6. use GuzzleHttp\Client;
  7. use Illuminate\Http\JsonResponse;
  8. use Illuminate\Http\Request;
  9. use Log;
  10. use Response;
  11. use Srmklive\PayPal\Services\ExpressCheckout;
  12. class PayPal extends AbstractPayment
  13. {
  14. protected $provider;
  15. protected $exChange;
  16. public function __construct()
  17. {
  18. $this->provider = new ExpressCheckout();
  19. $config = [
  20. 'mode' => 'live',
  21. 'live' => [
  22. 'username' => sysConfig('paypal_username'),
  23. 'password' => sysConfig('paypal_password'),
  24. 'secret' => sysConfig('paypal_secret'),
  25. 'certificate' => sysConfig('paypal_certificate'),
  26. 'app_id' => sysConfig('paypal_app_id'),
  27. ],
  28. 'payment_action' => 'Sale',
  29. 'currency' => 'USD',
  30. 'billing_type' => 'MerchantInitiatedBilling',
  31. 'notify_url' => (sysConfig('website_callback_url') ?: sysConfig(
  32. 'website_url'
  33. )) . '/callback/notify?method=paypal',
  34. 'locale' => 'zh_CN',
  35. 'validate_ssl' => true,
  36. ];
  37. $this->provider->setApiCredentials($config);
  38. $this->exChange = 7;
  39. $client = new Client(['timeout' => 15]);
  40. $exChangeRate = json_decode(
  41. $client->get(
  42. 'http://api.k780.com/?app=finance.rate&scur=USD&tcur=CNY&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4'
  43. )
  44. ->getBody(),
  45. true
  46. );
  47. if ($exChangeRate && $exChangeRate['success']) {
  48. $this->exChange = $exChangeRate['result']['rate'];
  49. }
  50. }
  51. public function purchase($request): JsonResponse
  52. {
  53. $payment = $this->creatNewPayment(
  54. Auth::id(),
  55. $request->input('id'),
  56. $request->input('amount')
  57. );
  58. $data = $this->getCheckoutData($payment->trade_no, $payment->amount);
  59. try {
  60. $response = $this->provider->setExpressCheckout($data);
  61. if ( ! $response['paypal_link']) {
  62. Log::error('Paypal处理错误:' . var_export($response, true));
  63. return Response::json(
  64. ['status' => 'fail', 'message' => '创建订单失败,请使用其他方式或通知管理员!']
  65. );
  66. }
  67. $payment->update(['url' => $response['paypal_link']]);
  68. return Response::json(
  69. [
  70. 'status' => 'success',
  71. 'url' => $response['paypal_link'],
  72. 'message' => '创建订单成功!',
  73. ]
  74. );
  75. } catch (Exception $e) {
  76. Log::error("【PayPal】错误: " . $e->getMessage());
  77. exit;
  78. }
  79. }
  80. protected function getCheckoutData($trade_no, $amount): array
  81. {
  82. $amount = 0.3 + ceil($amount / $this->exChange * 100) / 100;
  83. return [
  84. 'invoice_id' => $trade_no,
  85. 'items' => [
  86. [
  87. 'name' => sysConfig('subject_name') ?: sysConfig(
  88. 'website_name'
  89. ),
  90. 'price' => $amount,
  91. 'desc' => 'Description for' . (sysConfig(
  92. 'subject_name'
  93. ) ?: sysConfig('website_name')),
  94. 'qty' => 1,
  95. ],
  96. ],
  97. 'invoice_description' => $trade_no,
  98. 'return_url' => sysConfig(
  99. 'website_url'
  100. ) . '/callback/checkout',
  101. 'cancel_url' => sysConfig('website_url') . '/invoices',
  102. 'total' => $amount,
  103. ];
  104. }
  105. public function getCheckout(Request $request)
  106. {
  107. $token = $request->get('token');
  108. $PayerID = $request->get('PayerID');
  109. // Verify Express Checkout Token
  110. $response = $this->provider->getExpressCheckoutDetails($token);
  111. if (in_array(
  112. strtoupper($response['ACK']),
  113. ['SUCCESS', 'SUCCESSWITHWARNING']
  114. )) {
  115. $payment = Payment::whereTradeNo($response['INVNUM'])->firstOrFail(
  116. );
  117. $data = $this->getCheckoutData(
  118. $payment->trade_no,
  119. $payment->amount
  120. );
  121. // Perform transaction on PayPal
  122. $payment_status = $this->provider->doExpressCheckoutPayment(
  123. $data,
  124. $token,
  125. $PayerID
  126. );
  127. $status = $payment_status['PAYMENTINFO_0_PAYMENTSTATUS'];
  128. if ( ! strcasecmp($status, 'Completed') || ! strcasecmp(
  129. $status,
  130. 'Processed'
  131. )) {
  132. Log::info(
  133. "Order $payment->order_id has been paid successfully!"
  134. );
  135. $payment->order->update(['status' => 1]);
  136. } else {
  137. Log::error(
  138. "Error processing PayPal payment for Order $payment->id!"
  139. );
  140. }
  141. }
  142. return redirect('/invoices');
  143. }
  144. public function notify($request): void
  145. {
  146. $request->merge(['cmd' => '_notify-validate']);
  147. foreach ($request->input() as $key => $value) {
  148. if ($value == null) {
  149. $request->request->set($key, '');
  150. }
  151. }
  152. $post = $request->all();
  153. $response = (string)$this->provider->verifyIPN($post);
  154. if ($response === 'VERIFIED' && $request['invoice']) {
  155. $payment = Payment::whereTradeNo($request['invoice'])->first();
  156. if ($payment && $payment->status == 0) {
  157. $ret = $payment->order->update(['status' => 2]);
  158. if ($ret) {
  159. exit('success');
  160. }
  161. }
  162. }
  163. exit("fail");
  164. }
  165. }