首頁 後端開發 php教程 Paypal實現循環扣款(訂閱)功能的範例程式碼分享

Paypal實現循環扣款(訂閱)功能的範例程式碼分享

Mar 24, 2017 am 09:26 AM

本文主要介紹了Paypal實現循環扣款(訂閱)的想法與方法;並對如何使用Paypal的支付介面做下總結,具有很好的參考價值。下面跟著小編一起來看吧

起因

業務需求要整合Paypal,實現循環扣款功能,然而百度和GOOGLE了一圈,除官網外面,沒找到相關開發教程,只好在Paypal上看,花了兩天後整合成功,這裡對如何使用Paypal的支付介面做下總結。

Paypal現在有多套介面:

  • 透過Braintree(後面會談Braintree)實作Express Checkout;

  • #建立App,透過REST Api的介面方式(現在的主流介面方式);

  • NVP/SOAP API apps的介面(舊介面);

Braintree的介面

Braintree是Paypal收購的公司,它除了支援Paypal的支付外,還提供了升級計劃,信用卡,客戶資訊等一系列全套的管理,使用上更方便;這些功能Paypal第二套REST介面其實也整合了大部分,但是Paypal的Dashboard不能直接管理這些資訊而Braintree可以,所以我其實我更願意用Braintree。關鍵是我使用的後端框架是Laravel,它的cashier解決方案預設可以支援Braintee,所以這套介面是我的首選。但是當我把它的功能都實現後發現一個蛋痛的問題:Braintree在國內不支持。 。 。 。 。 。卒。 。 。

REST API

這是順應時代發展的產物,如果你之前有使用OAuth 2.0與REST API,那麼看這些介面應該不會有什麼困惑。

舊介面

除非REST API介面有不能滿足的,例如政策限制,否則不建議使用。全世界都在往OAuth 2.0的認證方式和REST API的API使用方式遷移,幹嘛逆勢而行。因此在REST API能解決問題情況下,我也沒對這套介面做深入比較。

REST API的介紹

如果自己直接調這些API還是很繁瑣的,同時我們只想盡快完成業務要求而不是陷入對API的深入了解。

那麼如何開始呢,建議直接安裝官方提供的PayPal-PHP-SDK,透過其Wiki作為起點。

在完成首個範例之前,請確保你有Sandbox帳號,並且正確配置了:

  • Client ID

  • Client Secret

  • Webhook API(必須是https開頭且是443端口,本地調試建議結合ngrok反向代理生成地址)

  • #Returnurl(注意項目同上)

  • #Payments 一次性支付接口,不支援循環捐款。主要支付內容有支援Paypal支付,信用卡支付,透過已保存的信用卡支援(需要使用Vault接口,會有這樣的接口主要是PCI的要求,不允許一般的網站採集信用卡的敏感資訊),支援付給第三方收款人。

  • Payouts 沒用到,忽略;

  • Authorization and Capture 支援直接透過Paypal的帳號登陸你的網站,並取得相關資訊;

  • Sale 跟商城有關,沒用到,忽略;

  • Order 跟商城有關,沒用到,忽略;

  • Billing Plan & Agreements 升級計畫與簽約,也就是訂閱功能,實現循環扣款必須使用這裡的功能,這是本文的重點;

  • Vault 儲存信用卡資訊

  • Payment Experience 沒用到,忽略;

  • Notifications 處理Webhook的訊息,重要,但不是本文關注內容;

  • Invoice 票據處理;

  • Identity 認證處理,實現OAuth 2.0的登陸,取得對應token以便請求其他API,這塊Paypal-PHP-SDK已經做進去,本文也不談。

    如何實現循環扣款

    #分成四個步驟:

    1. 建立昇級計劃,並啟動;

    2. 建立訂閱(創建Agreement),然後將跳到Paypal的網站等待使用者同意;

    3. ##使用者同意後,執行訂閱

    4. 取得扣款帳單

    1.建立昇級計畫

    升級計畫對應Plan這個類別。這一步有幾個注意點:

    • 升級計畫建立後,處於CREATED狀態,必須將狀態修改為ACTIVE才能正常使用。

    • Plan有PaymentDefinition和MerchantPreferences兩個對象,這兩個物件都不能為空;

    • 如果想建立TRIAL類型的計劃,該計劃還必須有配套的REGULAR的付款定義,否則會報錯;

    • #看程式碼有呼叫一個setSetupFee(非常,非常,非常重要)方法,該方法設定了完成訂閱後首次扣款的費用,而Agreement物件的循環扣款方法設定的是第2次開始時的費用。

    以建立一個Standard的計畫為例,其參數如下:

    $param = [
     "name" => "standard_monthly",
     "display_name" => "Standard Plan",
     "desc" => "standard Plan for one month",
     "type" => "REGULAR",
     "frequency" => "MONTH",
     "frequency_interval" => 1,
     "cycles" => 0,
     "amount" => 20,
     "currency" => "USD"
     ];
    登入後複製

    建立並啟動計畫程式碼如下:

     //上面的$param例子是个数组,我的实际应用传入的实际是个对象,用户理解下就好。
     public function createPlan($param)
     {
     $apiContext = $this->getApiContext();
     $plan = new Plan();
     // # Basic Information
     // Fill up the basic information that is required for the plan
     $plan->setName($param->name)
     ->setDescription($param->desc)
     ->setType('INFINITE');//例子总是设置为无限循环
     // # Payment definitions for this billing plan.
     $paymentDefinition = new PaymentDefinition();
     // The possible values for such setters are mentioned in the setter method documentation.
     // Just open the class file. e.g. lib/PayPal/Api/PaymentDefinition.php and look for setFrequency method.
     // You should be able to see the acceptable values in the comments.
     $paymentDefinition->setName($param->name)
     ->setType($param->type)
     ->setFrequency($param->frequency)
     ->setFrequencyInterval((string)$param->frequency_interval)
     ->setCycles((string)$param->cycles)
     ->setAmount(new Currency(array('value' => $param->amount, 'currency' => $param->currency)));
     // Charge Models
     $chargeModel = new ChargeModel();
     $chargeModel->setType('TAX')
     ->setAmount(new Currency(array('value' => 0, 'currency' => $param->currency)));
     $returnUrl = config('payment.returnurl');
     $merchantPreferences = new MerchantPreferences();
     $merchantPreferences->setReturnUrl("$returnUrl?success=true")
     ->setCancelUrl("$returnUrl?success=false")
     ->setAutoBillAmount("yes")
     ->setInitialFailAmountAction("CONTINUE")
     ->setMaxFailAttempts("0")
     ->setSetupFee(new Currency(array('value' => $param->amount, 'currency' => 'USD')));
     $plan->setPaymentDefinitions(array($paymentDefinition));
     $plan->setMerchantPreferences($merchantPreferences);
     // For Sample Purposes Only.
     $request = clone $plan;
     // ### Create Plan
     try {
     $output = $plan->create($apiContext);
     } catch (Exception $ex) {
     return false;
     }
     $patch = new Patch();
     $value = new PayPalModel('{"state":"ACTIVE"}');
     $patch->setOp('replace')
     ->setPath('/')
     ->setValue($value);
     $patchRequest = new PatchRequest();
     $patchRequest->addPatch($patch);
     $output->update($patchRequest, $apiContext);
     return $output;
     }
    登入後複製

    2.創建訂閱(創建Agreement),然後將跳到Paypal的網站等待用戶同意

    #Plan創建後,要怎麼讓用戶訂閱呢,其實就是創建Agreement,關於Agreement,有以下注意點:

    • 如前面所述,Plan物件的setSetupFee方法,設定了完成訂閱後首次扣款的費用,而Agreement物件的循環扣款方法設定的是第2次開始時的費用。

    • setStartDate方法設定的是第2次扣款時的時間,因此如果你按月循環,應該是當前時間加一個月,同時該方法要求時間格式是ISO8601格式,使用Carbon庫可輕鬆解決;

    • 在創建Agreement的時候,此時還沒有產生唯一ID,於是我碰到了一點小困難:那就是當用戶完成訂閱的時候,我怎麼知道這個訂閱是哪個用戶的?透過Agreement的getApprovalLink方法得到的URL,裡面的token是唯一的,我透過提取該token作為識別方式,在用戶完成訂閱後替換成真正的ID。

    範例參數如下:

    $param = [
     'id' => 'P-26T36113JT475352643KGIHY',//上一步创建Plan时生成的ID
     'name' => 'Standard', 
     'desc' => 'Standard Plan for one month'
    ];
    登入後複製

    程式碼如下:

     public function createPayment($param)
     {
     $apiContext = $this->getApiContext();
     $agreement = new Agreement();
     $agreement->setName($param['name'])
     ->setDescription($param['desc'])
     ->setStartDate(Carbon::now()->addMonths(1)->toIso8601String());
     // Add Plan ID
     // Please note that the plan Id should be only set in this case.
     $plan = new Plan();
     $plan->setId($param['id']);
     $agreement->setPlan($plan);
     // Add Payer
     $payer = new Payer();
     $payer->setPaymentMethod('paypal');
     $agreement->setPayer($payer);
     // For Sample Purposes Only.
     $request = clone $agreement;
     // ### Create Agreement
     try {
     // Please note that as the agreement has not yet activated, we wont be receiving the ID just yet.
     $agreement = $agreement->create($apiContext);
     // ### Get redirect url
     // The API response provides the url that you must redirect
     // the buyer to. Retrieve the url from the $agreement->getApprovalLink()
     // method
     $approvalUrl = $agreement->getApprovalLink();
     } catch (Exception $ex) {
     return "create payment failed, please retry or contact the merchant.";
     }
     return $approvalUrl;//跳转到$approvalUrl,等待用户同意
     }
    登入後複製

    函數執行後傳回$approvalUrl,記得透過redirect( $approvalUrl)跳到Paypal的網站等待用戶付款。

    用戶同意後,執行訂閱

    用戶同意後,訂閱還未完成,必須執行Agreement的execute方法才算完成真正的訂閱。這一步驟的注意點在於

    • 完成訂閱後,並不等於扣款,可能會延遲幾分鐘;

    • ##如果第一步的setSetupFee費用設定為0,則必須等到循環扣款的時間到了才會產生訂單;

    程式碼片段如下:

     public function onPay($request)
     {
     $apiContext = $this->getApiContext();
     if ($request->has('success') && $request->success == 'true') {
     $token = $request->token;
     $agreement = new \PayPal\Api\Agreement();
     try {
     $agreement->execute($token, $apiContext);
     } catch(\Exception $e) {
     return ull;
     return $agreement;
     }
     return null;
     }
    登入後複製

    • #在取得交易記錄

    • 訂閱後,可能不會立刻產生交易扣費的交易記錄,如果為空則過幾分鐘再嘗試。本步驟注意點:

    • start_date與end_date不能為空

    • #實際測試時,該函數傳回的物件不能總是傳回空的JSON對象,因此如果有需要輸出JSON,請依照AgreementTransactions的API說明,手動取出對應參數。

       /** 获取交易记录
       * @param $id subscription payment_id
       * @warning 总是获取该subscription的所有记录
       */
       public function transactions($id)
       {
       $apiContext = $this->getApiContext();
       $params = ['start_date' => date('Y-m-d', strtotime('-15 years')), 'end_date' => date('Y-m-d', strtotime('+5 days'))];
       try {
       $result = Agreement::searchTransactions($id, $params, $apiContext);
       } catch(\Exception $e) {
       Log::error("get transactions failed" . $e->getMessage());
       return null;
       }
       return $result->getAgreementTransactionList() ;
       }
      登入後複製
      最後,Paypal官方當然也有對應的教程,不過是呼叫原生介面的,跟我上面流程不一樣點在於只說了前3步### ###需要考慮的問題#########功能是實現了,但是也發現不少注意點:############國內使用Sandbox測試時連接特別慢,經常提示逾時或出錯,因此需要特別考慮執行中途用戶關閉頁面的情況;#############一定要實現webhook,否則當用戶進Paypal取消訂閱時,你的網站將得不到通知;############訂閱(Agreement)一旦產生,除非主動取消,否則將一直生效。因此如果你的網站設計了多個升級方案(例如Basic,Standard,Advanced),當使用者已經訂閱某個方案後,去切換升級方案時,開發上必須取消前一個升級方案;###### ######用戶同意訂閱-(取消舊訂閱-完成新訂閱的簽約-###修改用戶資訊###為新的訂閱),括號整個過程應該是原子操作,同時耗時又長,因此應該將其放到###隊列###中執行直到成功體驗會更好。 ##########

      以上是Paypal實現循環扣款(訂閱)功能的範例程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    使用PHP和PayPal實現線上支付 使用PHP和PayPal實現線上支付 May 11, 2023 pm 03:37 PM

    隨著網路的快速發展,越來越多的企業選擇將產品和服務線上銷售,這使得線上支付成為企業的一大需求。而PayPal作為世界領先的線上支付平台,也成為了許多企業的首選。本文將介紹如何使用PHP和PayPal實現線上支付。我們將分為以下幾個步驟:建立PayPal帳號和應用整合PayPalSDK取得付款Token處理付款處理付款確認建立PayPal帳號和應用程式要使用P

    paypal無法付款的原因是什麼 paypal無法付款的原因是什麼 Sep 01, 2023 pm 05:00 PM

    paypal無法付款的原因是帳戶餘額不足、付款方式被限制、交易被風控系統攔截、收款方帳戶問題、網路連線問題以及用戶帳戶異常等。詳細介紹:1、帳戶餘額不足,可以透過銀行轉帳或信用卡充值來增加帳戶餘額;2、付款方式被限制,查看付款設定並確保所選的付款方式沒有受到限制;3、交易被風控系統攔截,聯絡PayPal客服,提供相關資訊以證明交易的合法性,並請求解除付款限制等等。

    歐洲人用paypal嗎 歐洲人用paypal嗎 Nov 10, 2022 am 10:52 AM

    歐洲人用paypal,但不是通用的,只有開通的地區才可以使用;PayPal是一個總部在美國加利福尼亞州聖何塞市的在線支付服務商;PayPal帳戶是PayPal公司推出的安全的網絡電子帳戶,使用它可有效降低網路詐欺的發生;PayPal帳戶所整合的高階管理功能,能掌控每一筆交易詳情。

    GCash 推出 PayPal 穩定幣,讓菲律賓人交易不受價格波動影響的加密貨幣 GCash 推出 PayPal 穩定幣,讓菲律賓人交易不受價格波動影響的加密貨幣 Jul 31, 2024 am 06:36 AM

    GCash 週二表示,PayPal USD (PYUSD) 代幣現在可以透過 GCrypto 進行交易,GCrypto 是由菲律賓數位資產交易所提供支援的應用程式內功能,且交易費用較低。

    paypal官方app下載 paypal官方app下載 Apr 23, 2024 am 10:00 AM

    要下載PayPal 官方應用程序,請訪問PayPal 官方網站:https://www.paypal.com/ 點擊“下載”,根據您的設備選擇相應應用程式商店,搜尋“PayPal”,下載並安裝,最後登錄您的PayPal 帳戶。該應用程式可讓您輕鬆管理帳戶、確保安全、追蹤支出、無縫付款,並適用於 iOS 和 Android 裝置。

    paypal無法付款是什麼原因 paypal無法付款是什麼原因 Oct 16, 2023 pm 03:23 PM

    paypal無法付款是因為付款方式、帳戶餘額、Paypal餘額、付款資訊、網路問題、Paypal系統、商家和瀏覽器等問題造成的。詳細介紹:1、付款方式,請確使用的付款方式已添加到Paypal帳戶中;2、帳戶餘額,確保Paypal帳戶餘額足夠支付訂單金額;3、Paypal餘額,查看帳戶狀態,了解是否存在異常情況; 4、付款信息,確保輸入的付款資訊正確無誤,如信用卡號、到期日等。

    Paypal 的 PYUSD 接近 10 億美元里程碑 Paypal 的 PYUSD 接近 10 億美元里程碑 Aug 17, 2024 am 06:10 AM

    Paypal發行的穩定幣資產在過去十天大幅成長後,目前已成為第六大穩定幣資產。

    PayPal聯手蘋果Tap to Pay,數百萬美國小型企業實現iPhone免接觸支付 PayPal聯手蘋果Tap to Pay,數百萬美國小型企業實現iPhone免接觸支付 Apr 10, 2024 pm 12:10 PM

    3月8日消息,貝寶(PayPal)控股有限公司近日發佈公告,宣佈數百萬美國小型企業,這些企業均是Venmo和PayPalZettle的用戶,現在無需任何額外硬體如擴展配件或藍牙讀卡器,只需透過支援蘋果的TaptoPay功能,便可僅靠一台iPhone實現免接觸式支付。蘋果公司於2022年5月推出的TaptoPay功能,使得美國商家可以利用iPhone及與支援商家的iOS應用程式來接受ApplePay和其他免接觸式支付方式。透過此服務,使用相容於iPhone設備的用戶能夠安全地處理免接觸式支付以及已啟用

    See all articles