使用react-paypal-js托管字段发送帐单地址

发布于 2025-01-13 23:03:28 字数 633 浏览 1 评论 0原文

有没有人曾经使用react-paypal-js托管字段的submit()功能发送过帐单地址?我正在这样做:

    hostedFields
        .submit({
            // The full name as shown in the card and billing address
            cardHolderName: cardHolderName,
            billingAddress: billingAddress
        })

问题是我实际上不确定它是否有效。没有真正的方法来验证帐单地址是否确实发送到贝宝,这导致我遇到如下处理错误:

         "processor_response": {
                        "avs_code": "N",
                        "cvv_code": "M",
                        "response_code": "9500"
                    }

我在官方文档中找不到有关在字段提交期间发送帐单地址的任何内容。如果有人知道这件事请告诉我。如果不可能,我将不得不切换到原始 SDK。

Has anyone ever sent a billing address using the submit() functionality of the react-paypal-js hosted fields? I'm doing this:

    hostedFields
        .submit({
            // The full name as shown in the card and billing address
            cardHolderName: cardHolderName,
            billingAddress: billingAddress
        })

The problem is that I'm not actually sure that it's working. There's no real way to verify if the billing address is actually being sent to paypal, and its resulting in me getting processing errors such as this one:

         "processor_response": {
                        "avs_code": "N",
                        "cvv_code": "M",
                        "response_code": "9500"
                    }

I couldn't find anything in the official docs about sending billing addresses during the field submission. If anyone knows anything about this let me know. If it's not possible, I will have to switch to the raw sdk.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青芜 2025-01-20 23:03:28

为了进行故障排除,您应该将对象分配给一个变量,然后记录它:

let submitOptions = {
            // The full name as shown in the card and billing address
            cardHolderName: cardHolderName,
            billingAddress: billingAddress
        };
console.log('submitOptions',submitOptions,JSON.encode(submitOptions,null,4));
hostedFields
        .submit(submitOptions)

该控制台输出是您应该在问题中包含的内容作为示例(实际数据是检查正确性的重要内容,而不是您的代码和变量名称用于创建对象)


这是一个有效的 HTML/JS(“原始 sdk”)示例,您可以使用它来检查相同的拒绝和 AVS:N 是否独立于 react-paypal-js 发生。尝试这样做将帮助您确定是否是该模块/其使用的问题,还是您的真实账户及其处理的问题。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />

  <!-- Sample CSS styles for demo purposes. You can override these styles to match your web page's branding. -->
  <link rel="stylesheet" type="text/css" href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"/>
</head>
<body>

<!-- Include the PayPal JavaScript SDK with correct client-id, and a client_token generated for this checkout-->
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=REPLACE_WITH_YOURS" data-client-token="REPLACE_WITH_TOKEN"></script>

<div align="center" style="margin:auto; max-width:600px;">

  <div id="paypal-button-container"></div> 

  <!-- Advanced credit and debit card payments form -->
  <form id="card-form" style="text-align:left; padding:10px;">
    <div align="center" style="padding-bottom:5px;"> or </div>

    <label for="card-number">Card Number</label><div id="card-number" class="card_field"></div>
    <div style="display:flex; flex-direction:row;">
      <div>
        <label for="expiration-date">Expiration Date</label><div id="expiration-date" class="card_field"></div>
      </div>
      <div style="margin-left:10px;">
        <label for="cvv">CSC</label><div id="cvv" class="card_field"></div>
      </div>
    </div>
    <label for="card-holder-name">Name on Card</label>
    <input type="text" id="card-holder-name" name="card-holder-name" autocomplete="off" placeholder="card holder name"/>
    <label for="card-billing-address-street">Billing Address</label>
    <input type="text" id="card-billing-address-street" name="card-billing-address-street" autocomplete="off" placeholder="street address"/>
    <input type="text" id="card-billing-address-unit" name="card-billing-address-unit" autocomplete="off" placeholder="unit"/>
    <input type="text" id="card-billing-address-city" name="card-billing-address-city" autocomplete="off" placeholder="city"/>
    <input type="text" id="card-billing-address-state" name="card-billing-address-state" autocomplete="off" placeholder="state"/>
    <input type="text" id="card-billing-address-zip" name="card-billing-address-zip" autocomplete="off" placeholder="zip / postal code"/>
    <input type="text" id="card-billing-address-country" name="card-billing-address-country" autocomplete="off" placeholder="country code" />

    <div align="center" >
      <button value="submit" id="submit" class="btn" style="width:150px !important;font-size:120%;">Pay</button>
    </div>
  </form>
</div>

<script>
    function createOrderOnServer(data, actions) {
        return fetch('/path/on/your/server/paypal/order/create/', {
            method: 'post'
        }).then(function(res) {
            return res.json();
        }).then(function(orderData) {
            return orderData.id;
        });
    }
 
    function captureOrderOnServer(data, actions) {
        return fetch('/path/on/your/server/paypal/order/' + (data.orderID || data.orderId) + '/capture/', {
            method: 'post'
        }).then(function(res) {
            return res.json();
        }).then(function(orderData) {
            // Three cases to handle:
            //   (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
            //   (2) Other non-recoverable errors -> Show a failure message
            //   (3) Successful transaction -> Show confirmation or thank you

            // This example reads a v2/checkout/orders capture response, propagated from the server
            // You could use a different API or structure for your 'orderData'
            var errorDetail = Array.isArray(orderData.details) && orderData.details[0];

            if (actions && errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
                return actions.restart(); // Recoverable state, per:
                // https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
            }

            if (errorDetail) {
                var msg = 'Sorry, your transaction could not be processed.';
                if (errorDetail.description) msg += '\n\n' + errorDetail.description;
                if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
                return alert(msg); // Show a failure message
            }

            // Show a success message, or redirect to success page
            cardDetails = orderData.payment_source && orderData.payment_source.card;
            if (cardDetails) alert('Transaction completed with ' + cardDetails.brand + ' x-' + cardDetails.last_digits);
            else alert('Transaction completed by ' + orderData.payer.name.given_name);
        });
    }

    // Displays PayPal buttons
    paypal.Buttons({
        createOrder: createOrderOnServer,

        onApprove: captureOrderOnServer,

    }).render("#paypal-button-container");

    // If this returns false or the card fields aren't visible, see step #1 in https://developer.paypal.com/docs/business/checkout/advanced-card-payments/
    if (paypal.HostedFields.isEligible()) {

      // Renders card fields
      paypal.HostedFields.render({
        // On submit, calls your server to set up the transaction
        createOrder: createOrderOnServer,

        styles: {
          '.valid': {
           'color': 'green'
          },
          '.invalid': {
           'color': 'red'
          }
        },

        fields: {
          number: {
            selector: "#card-number",
            placeholder: "4111 1111 1111 1111"
          },
          cvv: {
            selector: "#cvv",
            placeholder: "123"
          },
          expirationDate: {
            selector: "#expiration-date",
            placeholder: "MM/YY"
          }
        }
      }).then(function (cardFields) {
        document.querySelector("#card-form").addEventListener('submit', (event) => {
          const submitterHTML = event.submitter.innerHTML;
          event.submitter.innerHTML = 'Processing...'; event.submitter.disabled = true;
          event.preventDefault();

          let submitOptions = {
            // Cardholder's first and last name
            cardholderName: document.getElementById('card-holder-name').value,
            // Billing Address
            billingAddress: {
              // Street address, line 1
              streetAddress: document.getElementById('card-billing-address-street').value,
              // Street address, line 2 (Ex: Unit, Apartment, etc.)
              extendedAddress: document.getElementById('card-billing-address-unit').value,
              // State
              region: document.getElementById('card-billing-address-state').value,
              // City
              locality: document.getElementById('card-billing-address-city').value,
              // Postal Code
              postalCode: document.getElementById('card-billing-address-zip').value,
              // Country Code
              countryCodeAlpha2: document.getElementById('card-billing-address-country').value
            }
          };
          console.log('submitOptions', submitOptions, JSON.encode(submitOptions,null,4));
          cardFields.submit(submitOptions).then(function (data) {
            console.log('Order was created with card', data);

            //Next either capture on the server immediately, or use window.location to go to an order review page
            return captureOrderOnServer(data).then(function() {
              event.submitter.innerHTML = submitterHTML; event.submitter.disabled = false;
            });
         }).catch(function (err) {
           event.submitter.innerHTML = submitterHTML; event.submitter.disabled = false;
           console.log('Hosted Fields submission error', err);
           console.log(JSON.stringify(err,null,2));
           //Show message to buyer about failure or validation problems
           alert('Sorry, your payment could not be processed.\n\n' + JSON.stringify(err,null,2));
         });
        });
      });
    } else {
      console.log('Cannot use advanced card fields! See step #1 in guide for activation, and SDK url must refresh from cache afterward');
      document.querySelector("#card-form").style.display = 'none';
    }
  </script>
</body>
</html>

For troubleshooting purposes you should assign the object to a variable and then log it:

let submitOptions = {
            // The full name as shown in the card and billing address
            cardHolderName: cardHolderName,
            billingAddress: billingAddress
        };
console.log('submitOptions',submitOptions,JSON.encode(submitOptions,null,4));
hostedFields
        .submit(submitOptions)

The console output of that is what you should include in your question as an example (the actual data is what's important to check for correctness, not your code and variable names used to create the object)


Here is a working HTML/JS ('raw sdk') sample you can use to check whether the same decline and AVS:N happens independently of react-paypal-js. Trying with this will help you isolate whether it's an issue with that module/its use, vs. with your live account and its processing.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />

  <!-- Sample CSS styles for demo purposes. You can override these styles to match your web page's branding. -->
  <link rel="stylesheet" type="text/css" href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"/>
</head>
<body>

<!-- Include the PayPal JavaScript SDK with correct client-id, and a client_token generated for this checkout-->
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=REPLACE_WITH_YOURS" data-client-token="REPLACE_WITH_TOKEN"></script>

<div align="center" style="margin:auto; max-width:600px;">

  <div id="paypal-button-container"></div> 

  <!-- Advanced credit and debit card payments form -->
  <form id="card-form" style="text-align:left; padding:10px;">
    <div align="center" style="padding-bottom:5px;"> or </div>

    <label for="card-number">Card Number</label><div id="card-number" class="card_field"></div>
    <div style="display:flex; flex-direction:row;">
      <div>
        <label for="expiration-date">Expiration Date</label><div id="expiration-date" class="card_field"></div>
      </div>
      <div style="margin-left:10px;">
        <label for="cvv">CSC</label><div id="cvv" class="card_field"></div>
      </div>
    </div>
    <label for="card-holder-name">Name on Card</label>
    <input type="text" id="card-holder-name" name="card-holder-name" autocomplete="off" placeholder="card holder name"/>
    <label for="card-billing-address-street">Billing Address</label>
    <input type="text" id="card-billing-address-street" name="card-billing-address-street" autocomplete="off" placeholder="street address"/>
    <input type="text" id="card-billing-address-unit" name="card-billing-address-unit" autocomplete="off" placeholder="unit"/>
    <input type="text" id="card-billing-address-city" name="card-billing-address-city" autocomplete="off" placeholder="city"/>
    <input type="text" id="card-billing-address-state" name="card-billing-address-state" autocomplete="off" placeholder="state"/>
    <input type="text" id="card-billing-address-zip" name="card-billing-address-zip" autocomplete="off" placeholder="zip / postal code"/>
    <input type="text" id="card-billing-address-country" name="card-billing-address-country" autocomplete="off" placeholder="country code" />

    <div align="center" >
      <button value="submit" id="submit" class="btn" style="width:150px !important;font-size:120%;">Pay</button>
    </div>
  </form>
</div>

<script>
    function createOrderOnServer(data, actions) {
        return fetch('/path/on/your/server/paypal/order/create/', {
            method: 'post'
        }).then(function(res) {
            return res.json();
        }).then(function(orderData) {
            return orderData.id;
        });
    }
 
    function captureOrderOnServer(data, actions) {
        return fetch('/path/on/your/server/paypal/order/' + (data.orderID || data.orderId) + '/capture/', {
            method: 'post'
        }).then(function(res) {
            return res.json();
        }).then(function(orderData) {
            // Three cases to handle:
            //   (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
            //   (2) Other non-recoverable errors -> Show a failure message
            //   (3) Successful transaction -> Show confirmation or thank you

            // This example reads a v2/checkout/orders capture response, propagated from the server
            // You could use a different API or structure for your 'orderData'
            var errorDetail = Array.isArray(orderData.details) && orderData.details[0];

            if (actions && errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
                return actions.restart(); // Recoverable state, per:
                // https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
            }

            if (errorDetail) {
                var msg = 'Sorry, your transaction could not be processed.';
                if (errorDetail.description) msg += '\n\n' + errorDetail.description;
                if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
                return alert(msg); // Show a failure message
            }

            // Show a success message, or redirect to success page
            cardDetails = orderData.payment_source && orderData.payment_source.card;
            if (cardDetails) alert('Transaction completed with ' + cardDetails.brand + ' x-' + cardDetails.last_digits);
            else alert('Transaction completed by ' + orderData.payer.name.given_name);
        });
    }

    // Displays PayPal buttons
    paypal.Buttons({
        createOrder: createOrderOnServer,

        onApprove: captureOrderOnServer,

    }).render("#paypal-button-container");

    // If this returns false or the card fields aren't visible, see step #1 in https://developer.paypal.com/docs/business/checkout/advanced-card-payments/
    if (paypal.HostedFields.isEligible()) {

      // Renders card fields
      paypal.HostedFields.render({
        // On submit, calls your server to set up the transaction
        createOrder: createOrderOnServer,

        styles: {
          '.valid': {
           'color': 'green'
          },
          '.invalid': {
           'color': 'red'
          }
        },

        fields: {
          number: {
            selector: "#card-number",
            placeholder: "4111 1111 1111 1111"
          },
          cvv: {
            selector: "#cvv",
            placeholder: "123"
          },
          expirationDate: {
            selector: "#expiration-date",
            placeholder: "MM/YY"
          }
        }
      }).then(function (cardFields) {
        document.querySelector("#card-form").addEventListener('submit', (event) => {
          const submitterHTML = event.submitter.innerHTML;
          event.submitter.innerHTML = 'Processing...'; event.submitter.disabled = true;
          event.preventDefault();

          let submitOptions = {
            // Cardholder's first and last name
            cardholderName: document.getElementById('card-holder-name').value,
            // Billing Address
            billingAddress: {
              // Street address, line 1
              streetAddress: document.getElementById('card-billing-address-street').value,
              // Street address, line 2 (Ex: Unit, Apartment, etc.)
              extendedAddress: document.getElementById('card-billing-address-unit').value,
              // State
              region: document.getElementById('card-billing-address-state').value,
              // City
              locality: document.getElementById('card-billing-address-city').value,
              // Postal Code
              postalCode: document.getElementById('card-billing-address-zip').value,
              // Country Code
              countryCodeAlpha2: document.getElementById('card-billing-address-country').value
            }
          };
          console.log('submitOptions', submitOptions, JSON.encode(submitOptions,null,4));
          cardFields.submit(submitOptions).then(function (data) {
            console.log('Order was created with card', data);

            //Next either capture on the server immediately, or use window.location to go to an order review page
            return captureOrderOnServer(data).then(function() {
              event.submitter.innerHTML = submitterHTML; event.submitter.disabled = false;
            });
         }).catch(function (err) {
           event.submitter.innerHTML = submitterHTML; event.submitter.disabled = false;
           console.log('Hosted Fields submission error', err);
           console.log(JSON.stringify(err,null,2));
           //Show message to buyer about failure or validation problems
           alert('Sorry, your payment could not be processed.\n\n' + JSON.stringify(err,null,2));
         });
        });
      });
    } else {
      console.log('Cannot use advanced card fields! See step #1 in guide for activation, and SDK url must refresh from cache afterward');
      document.querySelector("#card-form").style.display = 'none';
    }
  </script>
</body>
</html>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文