首页 后端开发 php教程 Paypal实现循环扣款(订阅)功能的方法

Paypal实现循环扣款(订阅)功能的方法

May 24, 2018 pm 04:18 PM
paypal 订阅

本文主要介绍了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参考文档https://developer.paypal.com/webapps/developer/docs/api/对于其API和使用方式有较详细的介绍,但是如果自己直接调这些API还是很繁琐的,同时我们只想尽快完成业务要求而不是陷入对API的深入了解。

那么如何开始呢,建议直接安装官方提供的PayPal-PHP-SDK,通过其Wiki作为起点。

在完成首个例子之前,请确保你有Sandbox帐号,并正确配置了:

  • Client ID

  • Client Secret

  • Webhook API(必须是https开头且是443端口,本地调试建议结合ngrok反向代理生成地址)

  • Returnurl(注意项同上)

在完成Wiki的首个例子后,理解下接口的分类有助于完成你的业务需求,下面我对接口分类做个介绍,请结合例子理解http://paypal.github.io/PayPal-PHP-SDK/sample/#payments。

  • 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步,供有兴趣的参考:https://developer.paypal.com/docs/integration/direct/billing-plans-and-agreements/。

需要考虑的问题

功能是实现了,但是也发现不少注意点:

  • 国内使用Sandbox测试时连接特别慢,经常提示超时或出错,因此需要特别考虑执行中途用户关闭页面的情况;

  • 一定要实现webhook,否则当用户进Paypal取消订阅时,你的网站将得不到通知;

  • 订阅(Agreement)一旦产生,除非主动取消,否则将一直生效。因此如果你的网站设计了多个升级计划(比如Basic,Standard,Advanced),当用户已经订阅某个计划后,去切换升级计划时,开发上必须取消前一个升级计划;

  • 用户同意订阅-(取消旧订阅-完成新订阅的签约-修改用户信息为新的订阅),括号整个过程 应该是原子操作,同时耗时又长,因此应该将其放到队列中执行直到成功体验会更好。

以上就是本文的全部内容,希望对大家的学习有所帮助。


相关推荐:

Paypal实现循环扣款(订阅)功能的示例代码分享

zen cart实现订单中增加paypal中预留电话的方法

paypal最简单的PHP在线支付SDK

以上是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)

热门话题

Java教程
1662
14
CakePHP 教程
1419
52
Laravel 教程
1311
25
PHP教程
1261
29
C# 教程
1234
24
无法在iPhone上更改Apple ID国家/地区:修复 无法在iPhone上更改Apple ID国家/地区:修复 Apr 20, 2024 am 08:22 AM

无法更改AppleID所属国家或地区。在许多情况下,您无法更改AppleID的区域。我们已经讨论了所有这些条件及其各自的解决方案,以便您能够在iPhone上更改AppleID。修复1–取消所有活动订阅如果您已经有活动订阅,Apple不允许您执行区域修改操作。通常,这些应用程序在不同地区具有不同的订阅计划、等级和费用(货币)。步骤1–您必须转到“设置”。步骤2–您将在“设置”页面的顶部找到您的AppleID。步骤3–点击一次即可打开它。步骤4–在下一页上,打开“订阅”菜单。步骤5–您可以在其中查看

订阅已过期,请更新付款以保留Microsoft 365 订阅已过期,请更新付款以保留Microsoft 365 Feb 19, 2024 am 11:06 AM

本文将探讨Windows11/10计算机上出现的“订阅过期,更新付款以保留Microsoft365”通知。这并非错误消息,而是在通知中心中看到的提醒。据报道,一些用户尽管已有有效订阅,仍会收到此通知。如果你也遇到类似情况,可以参考本文中提供的建议处理。订阅已过期,请更新付款以保留Microsoft365如果您收到订阅过期的通知,建议不要立即点击其中的链接或采取行动。请确保在更新付款前,通过官方途径验证通知的真实性,以避免系统受到潜在的感染风险。检查您的订阅状态检查您的付款信息用好的反恶意软件或反

使用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账户所集成的高级管理功能,能掌控每一笔交易详情。

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

要下载 PayPal 官方应用程序,请访问 PayPal 官方网站:https://www.paypal.com/ 单击“下载”,根据您的设备选择相应应用程序商店,搜索“PayPal”,下载并安装,最后登录您的 PayPal 账户。该应用程序可让您轻松管理账户、确保安全、跟踪支出、无缝付款,并适用于 iOS 和 Android 设备。

如何实现记账系统的订阅和付费功能 - 使用PHP开发付费记账功能的方法 如何实现记账系统的订阅和付费功能 - 使用PHP开发付费记账功能的方法 Sep 25, 2023 pm 07:09 PM

如何实现记账系统的订阅和付费功能-使用PHP开发付费记账功能的方法,需要具体代码示例。随着互联网和移动支付的快速发展,订阅和付费功能已经成为许多在线服务的重要组成部分。在记账系统中,实现订阅和付费功能可以为用户提供更加个性化、安全可靠的服务。本文将介绍如何使用PHP语言开发记账系统的订阅和付费功能,并提供具体的代码示例。创建数据库表首先,在MySQL数据

GCash 推出 PayPal 稳定币,允许菲律宾人交易不受价格波动影响的加密货币 GCash 推出 PayPal 稳定币,允许菲律宾人交易不受价格波动影响的加密货币 Jul 31, 2024 am 06:36 AM

GCash 周二表示,PayPal USD (PYUSD) 代币现在可以通过 GCrypto 进行交易,GCrypto 是由菲律宾数字资产交易所提供支持的应用内功能,且交易费用较低。

See all articles