PayPal订阅扣费(Billing Agreement)
相关文档资料
- https://developer.paypal.com/webapps/developer/docs/api/#create-a-plan (文档)
- https://segmentfault.com/q/1010000020803319 (别人的接入博客)
- https://www.jb51.net/article/109298.htm (别人的接入博客,这个强烈推荐看完)
- https://developer.paypal.com/docs/api/payments.billing-agreements/v1/ (订阅计划创建API接口文档)
- https://developer.paypal.com/docs/api/payments.billing-plans/v1/ (创建订阅API调用返回数据字段)
- http://paypal.github.io/PayPal-PHP-SDK/sample/doc/billing/CreatePlan.html (PHP SDK代码接口示例)
- https://developer.paypal.com/docs/api/reference/api-responses/#hateoas-links (hateoas-links说明)
- https://developer.paypal.com/docs/api/get-an-access-token-curl/ (curl获取access_token)
- https://developer.paypal.com/docs/api/get-an-access-token-postman/ (postman获取access_token)
订阅流程说明
- 通过PayPal的SDK进行调用创建一个升级计划(Plan)
- 通过升级计划ID创建一个订阅订单(Agreement)
- 支付协议创建成功后,返回一个URL给客户端进行重定向
- 如果用户同意该协议,跳转至return_url参数完成订阅的最后一步(调用agreement的execute方法)
- 执行成功后进行初始化扣款(前提是有设置了setup_fee)
- 订阅完成
特殊说明
-
setup_fee设置了一个初始化支付金额,如果有一个订阅是一年12个月,想在刚订阅时就支付一个月的费用,那就必须设置setup_fee,然后charge_model中需要设置cycle为11,因为初始化扣款后实际周期扣款是11次,如果填12的话,一共扣款是13次。
-
升级计划最好是通过后台进行管理,升级计划和用户的订阅并不是一对一的关系,可以把升级计划理解为一个模板或者付费点,订阅是用这个模板/付费点去下一个单,相关的扣款规则由模板/付费点决定。PayPal SDK有提供升级计划的新增、查询、修改、删除的接口
创建订阅代码实现
<?php
namespace App\Utils\OrdersUtils\lib;
use App\Utils\BaseUtil;
use Carbon\Carbon;
use Closure;
use Exception;
use PayPal\Api\Agreement;
use PayPal\Api\ChargeModel;
use PayPal\Api\Currency;
use PayPal\Api\MerchantPreferences;
use PayPal\Api\Patch;
use PayPal\Api\PatchRequest;
use PayPal\Api\Payer;
use PayPal\Api\PaymentDefinition;
use PayPal\Api\Plan;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Common\PayPalModel;
use PayPal\Rest\ApiContext;
use Throwable;
/**
* PayPal订阅,升级计划只支持单定义
* Class PayPalSubscribe
* @package App\Utils\OrdersUtils\lib
*/
class PayPalSubscribe extends BaseUtil
{
protected $clientId;
protected $secret;
protected $name;
protected $cycles = 0;
protected $description;
protected $definitionAmount;
protected $tax = 0;
protected $shipping = 0;
protected $currency = 'USD';
protected $planType = self::PLAN_FIXED;
protected $definitionType = self::DEFINITION_REGULAR;
protected $returnUrl;
protected $notifyUrl;
protected $cancelUrl;
protected $autoBillAmount;
protected $initialFailAmountAction;
protected $maxFailAttempts = 0;
protected $setupFee = 0;
protected $startDate;
protected $frequency;
protected $frequencyInterval;
protected $errorCallable;
protected $context;
const PLAN_FIXED = 'FIXED';
const PLAN_INFINITE = 'INFINITE';
const DEFINITION_TRIAL = 'TRIAL';
const DEFINITION_REGULAR = 'REGULAR';
const FREQUENCY_DAY = 'DAY';
const FREQUENCY_WEEK = 'WEEK';
const FREQUENCY_MONTH = 'MONTH';
const FREQUENCY_YEAR = 'YEAR';
const AUTO_YES = 'YES';
const AUTO_NO = 'NO';
const ACTION_CONTINUE = 'CONTINUE';
const ACTION_CANCEL = 'CANCEL';
const PLAN_CREATED = 'CREATED';
const PLAN_ACTIVE = 'ACTIVE';
const PLAN_INACTIVE = 'INACTIVE';
const PLAN_ALL = 'ALL';
/**
* @param mixed $clientId
* @return PayPalSubscribe
*/
public function setClientId($clientId)
{
$this->clientId = $clientId;
return $this;
}
/**
* @param mixed $secret
* @return PayPalSubscribe
*/
public function setSecret($secret)
{
$this->secret = $secret;
return $this;
}
/**
* @param mixed $name
* @return PayPalSubscribe
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @param int $cycles
* @return PayPalSubscribe
*/
public function setCycles(int $cycles): PayPalSubscribe
{
$this->cycles = $cycles;
return $this;
}
/**
* @param mixed $description
* @return PayPalSubscribe
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* @param mixed $definitionAmount
* @return PayPalSubscribe
*/
public function setDefinitionAmount($definitionAmount)
{
$this->definitionAmount = $definitionAmount;
return $this;
}
/**
* @param int $tax
* @return PayPalSubscribe
*/
public function setTax