Home  >  Article  >  Backend Development  >  How to implement recurring deduction (subscription) function in Paypal

How to implement recurring deduction (subscription) function in Paypal

墨辰丷
墨辰丷Original
2018-05-24 16:18:481905browse

This article mainly introduces the ideas and methods of Paypal to implement recurring deductions (subscriptions); it also summarizes how to use Paypal's payment interface, which has a good reference value.

Cause

The business needs to integrate Paypal to realize the recurring deduction function. However, Baidu and GOOGLE searched around and found no relevant development tutorials except the official website, so I had to Looking at Paypal, it took two days to integrate successfully. Here is a summary of how to use Paypal's payment interface.

Paypal now has multiple sockets:

  • Express Checkout is implemented through Braintree (we will talk about Braintree later);

  • Create App through the interface of REST Api (now the mainstream interface);

  • The interface of NVP/SOAP API apps (old interface);

Braintree's interface

Braintree is a company acquired by Paypal. In addition to supporting Paypal payment, it also provides upgrade plans, credit cards, customer information, etc. A complete series of management, more convenient to use; Paypal's second set of REST interface actually integrates most of these functions, but Paypal's Dashboard cannot directly manage this information but Braintree can, so I actually prefer to use Braintree. The key is that the backend framework I use is Laravel, and its cashier solution supports Braintee by default, so this set of interfaces is my first choice. But when I implemented all its functions, I found a painful problem: Braintree is not supported in China. . . . . . Death. . .

REST API

This is a product that adapts to the development of the times. If you have used OAuth 2.0 and REST API before, you should not have any confusion when looking at these interfaces.

Old interface

Unless the REST API interface cannot be satisfied, such as policy restrictions, it is not recommended to use it. The whole world is migrating to OAuth 2.0 authentication methods and REST API API usage methods, so why go against the trend? Therefore, when the REST API can solve the problem, I did not make an in-depth comparison of this set of interfaces.

Introduction to REST API

Official API reference document https://developer.paypal.com/webapps/developer/docs/api/for its API and usage The method is introduced in more detail, but it is still very cumbersome to adjust these APIs directly. At the same time, we just want to complete the business requirements as soon as possible instead of getting into an in-depth understanding of the API.

So how to get started? It is recommended to directly install the officially provided PayPal-PHP-SDK and use its Wiki as a starting point.

Before completing the first example, please make sure you have a Sandbox account and configured it correctly:

  • Client ID

  • Client Secret

  • Webhook API (must start with https and be port 443. It is recommended to use ngrok reverse proxy to generate the address for local debugging)

  • Returnurl (Notes are the same as above)

After completing the first example in Wiki, understanding the classification of interfaces will help to complete your business needs. Let me introduce the classification of interfaces. Please understand http://paypal.github.io/PayPal-PHP-SDK/sample/#payments with examples.

  • Payments One-time payment interface does not support recurring donations. The main payment content includes support for Paypal payment, credit card payment, support through saved credit card (requires the use of Vault interface, such an interface is mainly due to PCI requirements, does not allow general websites to collect sensitive credit card information), supports payment to the third party Third Party Payee.

  • Payouts Not used, ignore;

  • Authorization and Capture supports logging in to your website directly through your Paypal account and obtains relevant information;

  • Sale Follow Relevant to the mall, not used, ignored;

  • Order Relevant to the mall, not used, ignored;

  • Billing Plan & Agreements Upgrade plan and contract, that is, the subscription function, you must use the function here to achieve recurring deductions, which is the focus of this article;

  • Vault Store credit card information

  • ##Payment Experience Not used, ignored;

  • Notifications Process the information of Webhook, Important, but not the focus of this article;

  • Invoice Invoice processing;

  • Identity Authentication processing, realizing OAuth 2.0 login, and obtaining the corresponding token to request other APIs. This Paypal-PHP-SDK has already been completed and will not be discussed in this article.

How to implement recurring deductions

Four steps:

  1. Create an upgrade plan, and activate;

  2. Create a subscription (create Agreement), and then jump to Paypal's website to wait for the user's consent;

  3. After the user agrees, execute the subscription

  4. Get the debit bill

1. Create an upgrade plan

Upgrade plan Corresponds to the Plan class. There are several points to note in this step:

  • After the upgrade plan is created, it is in the CREATED state and must be changed to ACTIVE before it can be used normally.

  • Plan has two objects, PaymentDefinition and MerchantPreferences, both of which cannot be empty;

  • If you want to create a TRIAL type plan, The plan must also have a matching REGULAR payment definition, otherwise an error will be reported;

  • Look at the code and call a setSetupFee (very, very, very important) method, which sets the completion of the subscription The fee for the first debit after that, while the recurring deduction method of the Agreement object sets the fee at the beginning of the second time.

Take creating a Standard plan as an example, its parameters are as follows:

$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"
 ];

The code to create and activate the plan is as follows :

 //上面的$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. Create a subscription (create Agreement), and then jump to Paypal’s website to wait for user consent

After the Plan is created, how do you let users subscribe? In fact, it means creating an Agreement. Regarding the Agreement, there are the following points to note:

  • As mentioned before, Plan The setSetupFee method of the object sets the fee for the first deduction after completing the subscription, while the cyclic deduction method of the Agreement object sets the fee for the second start.

  • The setStartDate method sets the time for the second deduction, so if you cycle on a monthly basis, it should be the current time plus one month. At the same time, this method requires the time format to be ISO8601 format , can be easily solved using the Carbon library;

  • When creating the Agreement, the unique ID has not been generated yet, so I encountered a small difficulty: that is when the user completes the subscription , how do I know which user this subscription belongs to? The token in the URL obtained through Agreement's getApprovalLink method is unique. I extract the token as a method of identification and replace it with the real ID after the user completes the subscription.

The example parameters are as follows:

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

The code is as follows:

 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,等待用户同意
 }

After the function is executed, it returns $approvalUrl. Remember to jump to the Paypal website through redirect($approvalUrl) to wait for the user to pay.

After the user agrees, execute the subscription

After the user agrees, the subscription has not been completed. The execute method of Agreement must be executed to complete the real process. subscription. The important thing to note in this step is that

  • After completing the subscription, it does not mean that the payment will be deducted, and it may be delayed for a few minutes;

  • If the first step If the setSetupFee fee is set to 0, the order will not be generated until the recurring deduction time is up;

The code snippet is as follows:

 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;
 }

Get transaction records

After subscribing, the transaction record of transaction deduction may not be generated immediately. If it is empty, it will be repeated after a few minutes. try. Notes on this step:

  • start_date and end_date cannot be empty

  • In actual testing, the object returned by this function cannot always return empty JSON object, so if you need to output JSON, please manually extract the corresponding parameters according to the API description of AgreementTransactions.

 /** 获取交易记录
 * @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() ;
 }

Finally, of course Paypal officially has corresponding tutorials, but they call the native interface, which is different from the process above. Only the first 3 steps are mentioned for reference: https://developer.paypal.com/docs/integration/direct/billing-plans-and-agreements/.

Issues that need to be considered

The function has been implemented, but there are also many points to note:

  • Domestic use of Sandbox During testing, the connection was extremely slow, often prompting a timeout or error, so special consideration needs to be given to the situation where the user closes the page mid-execution;

  • Be sure to implement webhook, otherwise when the user cancels the subscription in Paypal, Your website will not be notified;

  • Once the subscription (Agreement) is generated, it will remain in effect unless canceled actively. Therefore, if your website is designed with multiple upgrade plans (such as Basic, Standard, Advanced), when the user has subscribed to a plan and switches to an upgrade plan, the previous upgrade plan must be canceled during development;

  • The user agrees to subscribe - (cancel the old subscription - complete the signing of the new subscription - modify the user information to the new subscription), the whole process of brackets should be an atomic operation, and it is time-consuming and long, so it should be placed Executing in the queue until successful will provide a better experience.

#The above is the entire content of this article, I hope it will be helpful to everyone's study.


related suggestion:

PaypalSample code sharing to implement the recurring deduction (subscription) function

zen cart realizes adding a reservation in paypal to the order Telephone method

paypal The simplest PHP online payment SDK

The above is the detailed content of How to implement recurring deduction (subscription) function in Paypal. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn