Simulate PayPal errors in a sandbox account

I'm integrating PayPal payment on a web application I'm developing. I need to create an authorization for a transaction where I lock an amount of money (let's say 20€), then at the end of the transaction I complete the transaction and I take only the money that I need to take (so if the transaction's final cost is 15€, I give back 5€ to the user).

This workflow is currently working on a sandbox account, but now I wanted to test some errors that may occur while starting a new transaction, like for instance when the user doesn't have the sufficient amount of money (20€) that I need to lock in order to start a new transaction.

I found this documentation (https://developer.paypal.com/docs/api/test-values/#invoke-negative-testing) where it is stated To trigger the SENDER_EMAIL_UNCONFIRMED simulation response, set the items[0]/note value to ERRPYO002 in the POST v1/payments/payouts call. with the following code:

curl -X POST https://api.sandbox.paypal.com/v1/payments/payouts \
  -H "content-type: application/json" \
  -H "Authorization: Bearer Access-Token" \
  -d '{
  "sender_batch_header": {
    "sender_batch_id": "1524086406556",
    "email_subject": "This email is related to simulation"
  },
  "items": [
  {
    "recipient_type": "EMAIL",
    "receiver": "[email protected]",
    "note": "ERRPYO002",
    "sender_item_id": "15240864065560",
    "amount": {
      "currency": "USD",
      "value": "1.00"
    }
  }]
}'

So I guess that I need to pass an error code (like ERRPYO002) to a note field in my request body.

I'm using the checkout sdk, and my js code currently looks like this:

const buttonOpts = {
    env: 'sandbox',
    client: { production: $scope.key, sandbox: $scope.key },
    style: {
        label: 'paypal',
        size: 'medium',
        shape: 'rect',
        color: 'blue',
        tagline: false,
    },

    validate: actions => {
        // stuff
    },
    payment: (data, actions) => {
        return actions.payment.create({
            intent: 'authorize',
            payer: { payment_method: 'paypal' },
            transactions: [
                {
                    amount: {
                        total: '20.00',
                        currency: 'EUR',
                    },
                    description: 'My description',
                },
            ],
        });
    },
    onAuthorize: data => {
        // Sending data.paymentID and data.payerID to my backend to confirm the new transaction
    },
    onCancel: () => {
        // stuff
    },
    onError: err => {
        console.log(err);
        // stuff
    },
};

Paypal.Button.render(buttonOpts, '#paypal-button');

I guess that I need to pass the code needed to simulate the error to my actions.payment.create object parameter, but I didn't find where exactly since my workflow is different that the one in the docs.

These are the codes that PayPal allows you to use for error testing: https://developer.paypal.com/docs/payouts/integrate/test-payouts/#test-values

Any help is appreciated. Thanks a lot.

Answers:

Answer

Ok, I've actually found out how to solve this problem right after I posted this question. I'll just put my solution here for anyone that may have this problem in the future.

The option object I posted is actually correct as it is now, so after the user confirms that he/she wants to start a new transaction I get the payerID and the paymentID to send to my backend. On my backend function I changed my code so that it is as follows:

const paypal = require('paypal-rest-sdk');
const paymentId = event.paymentID;
const payerId = { payer_id: event.payerID };
paypal.configure({
    mode: process.env.PAYPAL_ENVIRONMENT, //sandbox or live
    client_id: '<MY_CLIENT_ID>',
    client_secret: '<MY_CLIENT_SECRET>',
});

paypal.payment.execute(
    paymentId,
    payerId,
    // START NEW CODE
    {
        headers: {
            'Content-Type': 'application/json',
            'PayPal-Mock-Response': '{"mock_application_codes": "INSUFFICIENT_FUNDS"}',
        },
    },
    // END NEW CODE
    (error, payment) => {
        console.error(JSON.stringify(error));
        console.error(JSON.stringify(payment));
        if (error) {
            /*
                {
                    "response": {
                        "name": "INSUFFICIENT_FUNDS",
                        "message": "Buyer cannot pay - insufficient funds.",
                        "information_link": "https://developer.paypal.com/docs/api/payments/#errors",
                        "debug_id": "a1b2c3d4e5f6g",
                        "details": [
                            {
                                "issue": "The buyer must add a valid funding instrument, such as a credit card or bank account, to their PayPal account."
                            }
                        ],
                        "httpStatusCode": 400
                    },
                    "httpStatusCode": 400
                }
            */
            return callback('unhandled_error', null);
        }
        if (payment.state === 'approved' && payment.transactions && payment.transactions[0].related_resources && payment.transactions[0].related_resources[0].authorization) {
            return callback(null, payment.transactions[0].related_resources[0].authorization.id);
        }
        console.log('payment not successful');
        return callback('unhandled_error', null);
    }
);

In the request headers you just have to put an header called PayPal-Mock-Response that contains the error code you want to test, and that's it.

Hope this'll help somebody!

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.