PHP 對接 paypal 支付

xiaoyukarl發表於2020-06-01

環境準備

  • 註冊paypal賬號
  • 註冊paypal開發者賬號
  • 建立paypal沙盒測試賬戶
  • 建立paypal應用
  • 下載PHP SDK
  • 實現支付
  • 實現支付成功回撥
  • 實現退款
  • 更多API程式碼模板

註冊paypal賬號

  • www.paypal.com 註冊商家賬戶
  • 選擇,”建立商家使用者”,根據要求填寫資訊,註冊完得去郵箱啟用

註冊paypal開發者賬號

  • developer.paypal.com 使用上一步註冊的賬號登入
  • 在左側導航欄點選Accounts,建立兩個sandbox賬號,一個個人賬號(personal)用於付款,一個商家賬號(business)用於收款,系統已經預設建立了兩個,可以自己選擇建立,方便記憶; 建立賬號後記得給當前賬號新增餘額用於接下來的測試。
    建立賬號
  • 用剛才建立的測試賬號登入沙盒測試站點,檢視金額和交易資訊www.sandbox.paypal.com

建立沙盒應用APP

  • 賬號預設給建立好了一個Default Application,點選檢視獲取 ClientId和Secret;儲存起來,接下來介面呼叫會使用到;(上線時請重新建立一個Live的應用)
    檢視ClientId和Secret

下載SDK

  • 本人使用laravel框架,使用composer下載paypal包
  • composer require paypal/rest-api-sdk-php

實現支付

  • 以下是生成支付的程式碼片段,虛擬碼

    function createPayPal(){
      $shippingPrice = 2;
      $taxPrice = 0;
      $subTotal = 26;
      $item1 = new PayPal\Api\Item();
      $item1->setName("產品2")->setCurrency("USD")->setQuantity(1)->setPrice(10);
      $item2 = new PayPal\Api\Item();
      $item2->setName("產品1")->setCurrency("USD")->setQuantity(2)->setPrice(8);
    
      $itemList = new PayPal\Api\ItemList();
      $itemList->addItems([$item1,$item2]);
    
      // Set payment details
      $details = new PayPal\Api\Details();
      $details->setShipping($shippingPrice)->setTax($taxPrice)->setSubtotal($subTotal);
    
      // Set payment amount
      //注意,此處的subtotal,必須是產品數*產品價格,所有值必須是正確的,否則會報錯
      $total = $shippingPrice + $subTotal + $taxPrice;
      $amount = new PayPal\Api\Amount();
      $amount->setCurrency("USD")->setTotal($total)->setDetails($details);
    
      // Set transaction object
      $transaction = new PayPal\Api\Transaction();
      $transaction->setAmount($amount)->setItemList($itemList)->setDescription("這是交易描述")
          ->setInvoiceNumber(uniqid());//setInvoiceNumber為支付唯一識別符號,在使用時建議改成訂單號
    
      $payer = new PayPal\Api\Payer();
      $payer->setPaymentMethod('paypal');//["credit_card", "paypal"]
      $redirectUrls = new PayPal\Api\RedirectUrls();
      $redirectUrl = "http://test.com/redirect/success";//支付成功跳轉的回撥
      $cancelUrl = "http://test.com/redirect/cancel";//取消支付的回撥
      $redirectUrls->setReturnUrl($redirectUrl)->setCancelUrl($cancelUrl);
    
      // Create the full payment object
      $payment = new PayPal\Api\Payment();
      $payment->setIntent("sale")->setPayer($payer)->setRedirectUrls($redirectUrls)->addTransaction($transaction);
    
      try {
          $clientId = "xxxxxx";//上面應用的clientId和secret
          $secret = "XXXXXX";
          $oAuth = new \PayPal\Auth\OAuthTokenCredential($clientId, $secret);
          $apiContext =  new \PayPal\Rest\ApiContext($oAuth);
          $payment->create($apiContext);
          $approvalUrl = $payment->getApprovalLink();
          dd($approvalUrl);//這個是請求支付的連結,在瀏覽器中請求此連結就會跳轉到支付頁面
      } catch (\Exception $e) {
          dd($e->getMessage());//錯誤提示
      }
    }

    交易記錄

  • 以下是支付成功的回撥程式碼片段,虛擬碼

    function payRedirect(Request $request)
    {
      $paymentID = $request->get('paymentId');
      $payerId = $request->get('PayerID');
    
      $clientId = "xxxxxx";//上面應用的clientId和secret
      $secret = "XXXXXX";
      $oAuth = new \PayPal\Auth\OAuthTokenCredential($clientId, $secret);
      $apiContext =  new \PayPal\Rest\ApiContext($oAuth);
      $payment = \PayPal\Api\Payment::get($paymentID, $apiContext);
    
      $execute = new \PayPal\Api\PaymentExecution();
      $execute->setPayerId($payerId);
    
      try{
          $payment = $payment->execute($execute, $apiContext);//執行,從paypal獲取支付結果
          $paymentState = $payment->getState();//Possible values: created, approved, failed.
          $invoiceNum = $payment->getTransactions()[0]->getInvoiceNumber();
          $payNum = $payment->getTransactions()[0]->getRelatedResources()[0]->getSale()->getId();//這是支付的流水單號,必須儲存,在退款時會使用到
          $total = $payment->getTransactions()[0]->getRelatedResources()[0]->getSale()->getAmount()->getTotal();//支付總金額
          $transactionState = $payment->getTransactions()[0]->getRelatedResources()[0]->getSale()->getState();//Possible values: completed, partially_refunded, pending, refunded, denied.
    
          if($paymentState == 'approved' && $transactionState == 'completed'){
              //處理成功的邏輯,例如:判斷支付金額與訂單金額,更新訂單狀態等
              return "success";//返回成功標識
          }else{
              //paypal回撥錯誤,paypal狀態不正確
              return "error";//返回錯誤標識
          }
      }catch(\Exception $e){
          dd($e->getMessage());
      }
    }

退款

  • 退款必須要有支付成功的流水單號

  • 一個流水單號可以進行多次退款

  • 退款成功之後,在賬號的交易記錄中不體現,測試時請登入測試賬號自己記錄一下餘額的變化情況,以確定退款是否成功

  • 商家賬號會減少餘額並增加手續費(手續費是之前付款多收的),使用者賬號會增加餘額

    function refundOrder()
    {
      try{
          $refundRequest = new \PayPal\Api\RefundRequest();
          $amount = new \PayPal\Api\Amount();
          $amount->setCurrency("USD")->setTotal(10);//退總金額
          $refundRequest->setAmount($amount);
          $refundRequest->setDescription("退款測試");
          $sale = new \PayPal\Api\Sale();
          $sale->setId("XXXXXXXXX");//支付單號,支付成功時儲存的支付流水單號
          $clientId = "xxxxxx";//上面應用的clientId和secret
          $secret = "XXXXXX";
          $oAuth = new \PayPal\Auth\OAuthTokenCredential($clientId, $secret);
          $apiContext =  new \PayPal\Rest\ApiContext($oAuth);
    
          $detailedRefund = $sale->refundSale($refundRequest, $apiContext);//調介面
          $refundState = $detailedRefund->getState();//Possible values: pending, completed, cancelled, failed.
    
          //var_dump($refundedSale);
          if($refundState == 'completed'){
              //退款成功,返回
          }else{
              dd('paypal 退款失敗, 狀態不正確');
          }
      }catch (\Exception $exception){
          dd($exception->getMessage());//發生異常
      }
    }

    更多介面程式碼示例

  • paypal.github.io/PayPal-PHP-SDK/sam...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章