1

我读了这个问题这个问题。他们都表示(一年前)正在通过 REST API 进行定期付款。在我客户的网站上,客户需要能够支付

  1. 全额(一次全部 - 例如,结账时 1200 美元)
  2. 分期付款(6 个月 1200 美元,每月 200 美元)

当客户付款时通知他的网站至关重要。我目前已经为选项 #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 是否有办法通知我的服务器?

4

2 回答 2

4

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

好的,首先您需要设置从 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);      
}

此方法将允许您向客户分配和同意。您将需要协议的 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 是最终用户将被发送到以完成协议的 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;
}
于 2014-08-13T13:56:12.873 回答
1

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

我会使用带有定期付款的快速结帐,然后您将需要使用即时付款通知 (IPN)来处理付款、取消的个人资料等。

IPN 通知实际上会针对您帐户中的任何交易触发,因此您可以自动处理付款、退款、争议、订阅等。您可以更新您的数据库、发送电子邮件通知或其他任何您需要自动执行的操作在这些交易类型上。

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

于 2014-06-20T06:32:06.413 回答