如何使用 SDK 对 PayPal 定期付款配置文件进行计费 [英] How to Bill a PayPal Recurring Payment Profile with the SDK

查看:34
本文介绍了如何使用 SDK 对 PayPal 定期付款配置文件进行计费的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 .net 中使用 PayPal SDK(我认为它是旧"版本,经典?)我有我的商家资料下的一堆定期付款协议(可以从 https://www.paypal.com/ca/cgi-bin/webscr?cmd=_merchant-hub,并列在活动 -> 所有报告 -> 客户协议 ->; PayPal 网站上的定期付款).手动为它们开票工作正常,但我想自动化.我可以获得要开具发票的定期付款资料列表,所以我只是错过了最后一步 - 为定期付款资料实际开具发票.

I am using a PayPal SDK in .net (I think it's 'old' version, classic?) I have a bunch of recurring payment agreements under my merchant profile (the ones that can be invoiced manually from https://www.paypal.com/ca/cgi-bin/webscr?cmd=_merchant-hub, and are listed under Activity -> All Reports -> Customer Agreements -> Recurring payments on the PayPal web site). Invoicing them manually works fine, but I'd like to automate that. I am able to get a list of recurring payment profiles to invoice, so I'm just missing the very last step - to actually invoice a recurring payment profile.

我试过了

PayPalAPIInterfaceServiceService.BillUser() 

PayPalAPIInterfaceServiceService.BillOutstandingAmount()

它们都不起作用.PayPalAPIInterfaceServiceService.BillUser() 返回一个

and neither of them work. PayPalAPIInterfaceServiceService.BillUser() returns a

协议 ID 无效

错误(我猜他们正在寻找不同类型的计费协议).PayPalAPIInterfaceServiceService.BillOutstandingAmount() 返回一个

error (I guess they are looking for a different kind of billing agreement). PayPalAPIInterfaceServiceService.BillOutstandingAmount() returns a

未结余额必须>0

Outstanding balance must be > 0

错误.我想我也许可以使用

error. I thought I could perhaps set the outstanding balance on a recurring payment using

PayPalAPIInterfaceServiceService.UpdateRecurringPaymentsProfile()

但是,当在构造函数中将定期付款配置文件 ID 传递给 UpdateRecurringPaymentsProfileRequestDetailsType 或通过 UpdateRecurringPaymentsProfileRequestDetailsType.ProfileID 进行设置时,会导致

but, when passing the recurring payment profile ID either in the constructor to UpdateRecurringPaymentsProfileRequestDetailsType or setting through UpdateRecurringPaymentsProfileRequestDetailsType.ProfileID, that resulted in a

个人资料 ID 对该帐户无效.请重新提交请求使用正确的个人资料 ID.

Profile ID is not valid for this account. Please resubmit request with the correct profile ID.

将 UpdateRecurringPaymentsProfileRequestDetailsType.ProfileReference 设置为定期付款配置文件 ID 时,错误消息为

When setting UpdateRecurringPaymentsProfileRequestDetailsType.ProfileReference to the recurring payment profile ID, the error message is

个人资料 ID 无效

最后,我也尝试使用参考交易来计费:

Finally, I have also tried to bill using a reference transaction:

PaymentDetailsType payment = new PaymentDetailsType() { OrderTotal = new BasicAmountType(CurrencyCodeType.USD, amount.ToString()) };
DoReferenceTransactionRequestDetailsType request = new DoReferenceTransactionRequestDetailsType(recurringPaymentId, PaymentActionCodeType.SALE, payment);
var response = service.DoReferenceTransaction(new DoReferenceTransactionReq() { DoReferenceTransactionRequest = new DoReferenceTransactionRequestType(request) });

结果是

结算协议 ID 或交易 ID 无效

Billing Agreement Id or transaction Id is not valid

我的想法快用完了!

在给定配置文件 ID 的情况下,为定期付款配置文件开具发票/计费的正确 PayPal SDK 调用是什么?

What is the correct PayPal SDK call for invoicing/billing a recurring payment profile, given its profile id?

推荐答案

(我仍在努力解决这个问题,并将随着我的进展更新我的答案.当我完成后,此消息将被删除).

(I'm still working my way through this, and will be updating my answer as I progress. This message will be removed when I'm done).

根据 PayPal 商家技术支持,使用类似链接创建的重复性 PayPal 付款协议

As per PayPal merchant technical support, recurring PayPal payment agreements that are created with a link like

https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=###

并且有一个以I-"开头的ID;不能使用 PayPal API 开具发票.

and have an ID starting with "I-" cannot be invoiced using a PayPal API.

相反,人们必须使用参考交易,这种交易只能通过 PayPal API 创建(而不是如上所示的指向托管按钮"的链接).

Instead, one has to use reference transactions, which can only be created with the PayPal API (as opposed to a link to a 'hosted button' as shown above).

现在,PayPal 商家帐户默认没有启用参考交易;必须致电或发送电子邮件至 PayPal 才能启用该功能(一些指导可用).

Now, PayPal merchant accounts don't have Reference Transactions enabled by default; one has to call or email PayPal to get that turned on (some guidance available).

一旦启用参考交易(使用 PayPal 来回大约需要两周的时间才能启用我的,但也许我没有大多数人那么幸运:^),您可以使用 Express Checkout API(以及其他)以创建参考交易.

Once reference transactions are enabled (took about two weeks of back & forth with PayPal for mine to be enabled, but maybe I'm less lucky than most :^), one can use the Express Checkout API (among others) to create reference transactions.

参考交易列在可以注册的自动 SFTP RPP 报告中.它们确实出现在商家中心(并且它们的 ID 以 B- 而不是 I- 开头),并且可以从悬停鼠标时显示的工具提示中获取与来自商家中心的参考交易相关联的电子邮件地址将鼠标悬停在列表上(查看参考交易详细信息时不会显示付款人电子邮件地址).还可以在 returnUrl 调用的代码中使用 GetExpressCheckoutDetails 获取付款人信息,将作为参数传递给 returnUrl 的令牌(与用于调用 CreateBillingAgreement 的令牌相同)传递给它.

Reference transactions are not listed in automated SFTP RPP reports that one can sign up for. They do show up on the merchant hub (and their ID starts with a B- instead of an I-), and one can get the email address associated with the reference transaction from the merchant hub from the tool tip that shows up when hovering the mouse over the listing (the payer email address is not shown when looking at the reference transaction details). One can also get the payer information using GetExpressCheckoutDetails in the code that gets called by the returnUrl, passing it the token that gets passed as a parameter to the returnUrl (same token that is used to call CreateBillingAgreement).

这是处理创建 PayPal 参考交易的 php 代码.一个单独的 php 文件来处理这一切.我在那里留下了一些(注释掉的)调试代码,以帮助您在需要时完成这个过程.

Here's php code that handles the creation of a PayPal reference transaction. One single php file to handle it all. I left some (commented out) debugging code in there to help you walk through this if need be.

<?php
    require_once( dirname(__FILE__) . '/ppconfig.php' ); 

    /* ppconfig.php should contain something like:
    <?php
    global $ppApiUser, $ppApiPwd, $ppApiSig;
    $ppApiUser = '...';
    $ppApiPwd = '...';
    $ppApiSig = '...';
    ?>    
    */

    //print_r($_GET);
   
    if (!array_key_exists("a", $_GET))
        Intro();
    else switch ($_GET["a"])
    { 
        case "go":
            Setup();   
            break;

        case "cf":
            Confirmed();   
            break;

        case "cx":
            Cancelled();   
            break;

        default:
            Intro();
            break;
    }

    function Intro()
    {
        echo("<p>Please <a href='" . BaseUrl() . "?a=go'>click here</a> to create a PayPal billing agreement.</p>");
    }    

    function Setup()
    {
        $post = [
            'PAYMENTREQUEST_0_PAYMENTACTION' => 'AUTHORIZATION',
            'PAYMENTREQUEST_0_AMT' => '0',
            'PAYMENTREQUEST_0_CURRENCYCODE' => 'USD',
            'L_BILLINGTYPE0' => 'MerchantInitiatedBilling',
            'L_BILLINGAGREEMENTDESCRIPTION0' => 'Monthly Fee',
            'cancelUrl' => BaseUrl() . '?a=cx',
            'returnUrl' => BaseUrl() . '?a=cf'
        ];        

        $post = SetupPostArray($post, 'SetExpressCheckout');
        //echo "<p>query: " . http_build_query($post) . "</p>";

        $parsedResponse = DoCurl($post);
        // example response: Array ( [TOKEN] => EC-9WG24287H6582094R [TIMESTAMP] => 2021-05-17T18:14:09Z [CORRELATIONID] => 37010d4454fac [ACK] => Success [VERSION] => 86 [BUILD] => 55627781 )
           
        if ($parsedResponse['ACK'] === "Success")        
            Redirect("https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" . $parsedResponse['TOKEN']);
        else
            echo("<p>There was an issue creating your PayPal billing agreement; please forward this to us: SetExpressCheckout response = " . print_r($parsedResponse, true) . "</p>");             
    }    

    function Confirmed()
    {
        //$callerIp = $_SERVER['REMOTE_ADDR'];
        //$callerName = gethostbyaddr ( $callerIp );
        //echo("<p>Caller ip: $callerIp  Caller name: $callerName</p>"); returns my own address

        // sample request url: https://xxx.php?a=cf&token=EC-6F958498XP432134J
        // (paypal parameter same as cancel)

        $details = GetExpressCheckoutDetails($_GET["token"]);
        //echo("<p>Payer email: " . $details['EMAIL'] . "  Payer ID: " . $details['PAYERID'] . "</p>");
        
        $post = SetupPostArray([ 'TOKEN' => $_GET["token"] ], 'CreateBillingAgreement');  
        $parsedResponse = DoCurl($post);
        // sample response to create billing agreement: Array ( [BILLINGAGREEMENTID] => B-4EM76674LS64xxxxx [TIMESTAMP] => 2021-05-17T17:51:59Z [CORRELATIONID] => 3be427e93xxxx [ACK] => Success [VERSION] => 86 [BUILD] => 55627781 )

        if ($parsedResponse['ACK'] === "Success")
        {
            echo("<p>You successfully setup a pre-authorized payment (" . $parsedResponse['BILLINGAGREEMENTID'] . "). Thank you.</p>");                               
        }
        else
            echo("<p>There was an issue creating your PayPal billing agreement; please forward this to us: CreateBillingAgreement = " . print_r($parsedResponse, true) . "</p>");                
    }    

    function Cancelled()
    {
        // sample request url: https://xxx.php?a=cx&token=EC-6F958498XP432134J
        // (paypal parameter same as success)

        echo("<p>It looks like you cancelled the creation of your PayPal pre-authorized payment (how could you!) Please <a href='" . BaseUrl() . "?a=go'>click here</a> to try again.</p>");
    }    

    function GetExpressCheckoutDetails($token)
    {
        $post = SetupPostArray([ 'TOKEN' => $token ], 'GetExpressCheckoutDetails');  
        //echo "<p>GetExpressCheckoutDetails query: " . http_build_query($post) . "</p>";
        $parsedResponse = DoCurl($post);
        // sample response to GetExpressCheckoutDetails:  Array ( [TOKEN] => EC-87S04858V0280572C [BILLINGAGREEMENTACCEPTEDSTATUS] => 1 [CHECKOUTSTATUS] => PaymentActionNotInitiated [TIMESTAMP] => 2021-05-19T15:16:06Z [CORRELATIONID] => f5d17498exxxx [ACK] => Success [VERSION] => 86 [BUILD] => 55627781 [EMAIL] => xxxx@gmail.com [PAYERID] => xxxx [PAYERSTATUS] => verified [FIRSTNAME] => xxx [LASTNAME] => xxx [COUNTRYCODE] => xx [SHIPTONAME] => xxx xxx [SHIPTOSTREET] => xxx Dr [SHIPTOCITY] => xxx [SHIPTOSTATE] => xx [SHIPTOZIP] => xxxx [SHIPTOCOUNTRYCODE] => xx [SHIPTOCOUNTRYNAME] => xxx [ADDRESSSTATUS] => Confirmed [CURRENCYCODE] => USD [AMT] => 0.00 [ITEMAMT] => 0.00 [SHIPPINGAMT] => 0.00 [HANDLINGAMT] => 0.00 [TAXAMT] => 0.00 [INSURANCEAMT] => 0.00 [SHIPDISCAMT] => 0.00 [INSURANCEOPTIONOFFERED] => false [PAYMENTREQUEST_0_CURRENCYCODE] => USD [PAYMENTREQUEST_0_AMT] => 0.00 [PAYMENTREQUEST_0_ITEMAMT] => 0.00 [PAYMENTREQUEST_0_SHIPPINGAMT] => 0.00 [PAYMENTREQUEST_0_HANDLINGAMT] => 0.00 [PAYMENTREQUEST_0_TAXAMT] => 0.00 [PAYMENTREQUEST_0_INSURANCEAMT] => 0.00 [PAYMENTREQUEST_0_SHIPDISCAMT] => 0.00 [PAYMENTREQUEST_0_SELLERPAYPALACCOUNTID] => xxx@xxx.com [PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED] => false [PAYMENTREQUEST_0_SHIPTONAME] => xxx xxx [PAYMENTREQUEST_0_SHIPTOSTREET] => xxx Dr [PAYMENTREQUEST_0_SHIPTOCITY] => xxx [PAYMENTREQUEST_0_SHIPTOSTATE] => xx [PAYMENTREQUEST_0_SHIPTOZIP] => xxxxx [PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE] => xx [PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME] => xxx [PAYMENTREQUEST_0_ADDRESSSTATUS] => Confirmed [PAYMENTREQUESTINFO_0_ERRORCODE] => 0 )

        //echo("<p>GetExpressCheckoutDetails response: " . print_r($parsedResponse, true) . "</p>");                

        return $parsedResponse;        
    }
    
    function SetupPostArray($post, $method)
    {
        global $ppApiUser, $ppApiPwd, $ppApiSig; 
        $post['USER'] = $ppApiUser;
        $post['PWD'] = $ppApiPwd;
        $post['SIGNATURE'] = $ppApiSig;
        $post['METHOD'] = $method; 
        $post['VERSION'] = '86';
        return $post;
    }

    function DoCurl($post)
    {
        $ch = curl_init("https://api-3t.paypal.com/nvp");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));    
        $response = curl_exec($ch);
        curl_close($ch);    

        //echo("<p>Raw response: '$response'</p>");
        // example response: Array ( [TOKEN] => EC-9WG24287H6582094R [TIMESTAMP] => 2021-05-17T18:14:09Z [CORRELATIONID] => 37010d445xxxx [ACK] => Success [VERSION] => 86 [BUILD] => 55627781 )

        parse_str($response, $parsedResponse);

        return $parsedResponse;
    }

    function Redirect($url)
    {
        echo "<script type='text/javascript'> 
        window.location = '$url'; 
        </script>";        
    }

    function BaseUrl()
    {
        //return strtok($_SERVER["REQUEST_URI"], '?'); // see https://stackoverflow.com/a/6975045/68936
        return strtok("https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]", '?'); // see stackoverflow.com/a/6975045, stackoverflow.com/a/6768831
    }
?>

这篇关于如何使用 SDK 对 PayPal 定期付款配置文件进行计费的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆