$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('https://www.jb51.net/') ->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,则必须等到循环扣款的时间到了才会产生订单;
代码片段如下: