有没有办法使用PayPal REST API设置定期付款?

时间:2014-06-20 00:46:15

标签: javascript node.js paypal paypal-rest-sdk

我看了this questionthis one。他们都说(一年前)通过REST API进行的定期付款正在进行中。在我客户的网站上,客户需要支付

  1. 完整(一次全部 - 例如,结账时1200美元)
  2. 分期付款(6个月1200美元,每月200美元)
  3. 当客户付款时,通知他的网站至关重要。我目前为选项#1设置了这个:

    app.get("/cart/checkout/paypal", isLoggedIn, isVerified, function (req, res) {
        var user = req.user;
        var paymentDetails = {
            "intent": "sale",
            "payer": { "payment_method": "paypal"},
            "redirect_urls": {
                "return_url": "http://localhost:5000/cart/checkout/success",
                "cancel_url": "http://localhost:5000/cart"
            },
            "transactions": [
                { "amount": { "total": user.cart.finalPrice.toFixed(2), "currency": "USD"},
                "description": "You are being billed for " + user.cart.finalPrice.toFixed(2)}
            ]
        };
        paypal.payment.create(paymentDetails, function (err, payment) {
            if (err) console.log(err);
            else {
                if (payment.payer.payment_method === "paypal") {
                    req.session.paymentId = payment.id;
                    var redirectURL;
                    for (var i = 0; i < payment.links.length; i++) {
                        var link = payment.links[i];
                        if (link.method === "REDIRECT") redirectURL = link.href;
                    }
                    res.redirect(redirectURL);
                }
            }
        })
    })
    

    然后,"return_url"/cart/checkout/success)抓取所有正确的会话信息,我的数据库处理它。

    app.get("/cart/checkout/success", isLoggedIn, isVerified, function (req, res) {
        var user = req.user,
            paymentId = req.session.paymentId,
            payerId = req.param("PayerID"),
            details = { "payer_id": payerId };
    ...
    

    选项#2是否有类似的设置(定期付款)。如果没有,PayPal是否有办法在每次用户支付了未付余额和支付金额的分期付款时通知我的服务器?

2 个答案:

答案 0 :(得分:4)

是的,现在有一种方法可以在新的REST API中进行订阅。请参阅the documentation

好的,首先您需要设置从PayPal获得的客户端ID和密码。 我有测试和现场环境

所有{xxx}都是我的私有应用程序变量

public function __construct()
{

    $this->sandbox = {sandbox};
    if($this->sandbox) 
    {
        $this->host = 'https://api.sandbox.paypal.com';
        $this->clientId = {clientIdSandbox};
        $this->clientSecret = {clientSecretSandbox};            
    }
    else 
    {
        $this->host = 'https://api.paypal.com';
        $this->clientId = {clientId};
        $this->clientSecret = {clientSecret};           
    }
    $this->get_access_token();
}

然后我去获取访问令牌

private function get_access_token() 
{
    $curl = curl_init($this->host.'/v1/oauth2/token'); 
    curl_setopt($curl, CURLOPT_POST, true); 
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_USERPWD, $this->clientId . ":" . $this->clientSecret);
    curl_setopt($curl, CURLOPT_HEADER, false); 
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($curl, CURLOPT_POSTFIELDS, 'grant_type=client_credentials'); 
    $response = curl_exec( $curl );
    if (empty($response)) 
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode( $response );
    $this->token = $jsonResponse->access_token;
    $this->expires = time()+$jsonResponse->expires_in;
}

然后将访问数据存储在类属性

然后你还需要三个部分。创建订阅模板,然后检索协议,然后为客户创建协议。

在这个方法中,我发送数据名称,描述,期间,间隔和价格。但是你可以手动填写。这将创建您现在可以销售的订阅。

public function create_subscription($name, $desc, $period, $interval, $price)
{
    $data = array(
        'name' => $name,
        'description' => $desc,
        'type' => 'INFINITE',
        'payment_definitions' => array(
            0 => array (
                'name' => 'Payment Definition-1',
                'type' => 'REGULAR',
                'frequency' => $period,
                'frequency_interval' => $interval,
                'amount' => array(
                    'value' => $price,
                    'currency' => 'EUR',
                ),
                'cycles' => '0',
            ),
        ),
        'merchant_preferences' => array(
            'return_url'=>{return_url},
            'cancel_url'=>{cancel_url},
            'auto_bill_amount' => 'YES',
            'initial_fail_amount_action' => 'CONTINUE',
            'max_fail_attempts' => '0',
        ),
    );
    $data=json_encode($data);
    $url = $this->host.'/v1/payments/billing-plans';
    return $this->make_post_call($url, $data);  
}

从上面的方法中你会得到一个id,用于下面的方法来收集订阅的数据并存储它

public function retrieve_agreement($id)
{
    $url = $this->host.'/v1/payments/billing-agreements/'.$id;
    return $this->make_get_call($url);      
}

此方法允许您分配和同意客户端。 您需要具有一些数据的aggree的id才能添加到描述中。

public function create_agreement($subId, $data, $product)
{
    $paypalId = ($this->sandbox) ? $product->paypal_test_sub_id : $product->paypal_sub_id;
    $startDate = date('c', strtotime('+10 MINUTE'));
    $data = array (
        'name'=>'Subscription for subscription::'.$subId,
        'description'=>{company}.'  Subscription - ' . $data . ' - '.$product->name.' - '.$product->price .'€',
        'start_date'=>$startDate,
        'plan'=>array(
            'id'=>$paypalId,
        ),
        'payer'=>array(
            'payment_method'=>'paypal',
        ),
        'override_merchant_preferences'=>array(
            'return_url'=>{return_url}.$subId.'/',
            'cancel_url'=>{cancel_url}.$subId.'/',
        ),
    );  
    $data=json_encode($data);
    $url = $this->host.'/v1/payments/billing-agreements';
    $response = $this->make_post_call($url, $data);
    header("location:".$response['links'][0]['href']);      
    //return $response;
}

return_url是最终用户将被发送以完成协议的网址。我用它来传递给下面的方法

public function execute_agreement($token)
{

    $data=json_encode('');
    $url = $this->host.'/v1/payments/billing-agreements/'.$token.'/agreement-execute';
    return $response = $this->make_post_call($url, $data);
}

然后,您需要创建一个计划任务以使用retrieve_agreement方法,并查看订阅是否已被取消。

这是一个简短的解释。

如果您需要更多,请告诉我。

获取和发布

private function make_post_call($url, $postdata) 
{
    $curl = curl_init($url); 
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Authorization: Bearer '.$this->token,
                'Accept: application/json',
                'Content-Type: application/json'
                ));

    curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); 
    $response = curl_exec( $curl );
    if (empty($response)) 
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode($response, TRUE);
    return $jsonResponse;
}

private function make_get_call($url) 
{
    $curl = curl_init($url); 
    curl_setopt($curl, CURLOPT_POST, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Authorization: Bearer '.$this->token,
                'Accept: application/json',
                'Content-Type: application/json'
                ));
    $response = curl_exec( $curl );
    if (empty($response))
    {
        echo "NO RESPONSE for $url for function ".__FUNCTION__;
        print_r(curl_getinfo($curl));
        die(curl_error($curl));
        curl_close($curl); // close cURL handler
    } 
    else 
    {
        $info = curl_getinfo($curl);
        //echo "Time took: " . $info['total_time']*1000 . "ms\n";
        curl_close($curl); // close cURL handler
        if($info['http_code'] != 200 && $info['http_code'] != 201 ) 
        {
            echo "Received error: " . $info['http_code']. "\n";
            echo "Raw response:".$response."\n";
            die();
        }
    }
    $jsonResponse = json_decode($response, TRUE);
    return $jsonResponse;
}

答案 1 :(得分:1)

我建议暂时远离REST API。它还没有完成,Classic API为您提供了更多的灵活性。

我会使用快速结帐进行定期付款,然后您将要使用Instant Payment Notification (IPN)来处理付款,取消个人资料等。

任何曾经访问过您帐户的交易实际上都会触发IPN通知,因此您可以自动处理付款,退款,争议,订阅等。您可以更新数据库,发送电子邮件通知或其他任何需要的内容基于这些事务类型自动化。

IPN是PayPal提供的最有价值的工具之一,但它也是最未充分利用的工具之一。