Update order value and cart items

You may sometimes need to update the cart when the payment session already exists. Updating the cart is an asynchronous action that includes the following steps:

  1. The user changes the items in the cart or the final order amount.
  2. The merchant updates the data on their server.
  3. The merchant updates the data in the payment session Yandex Pay.

The problem is that the user might start the payment process somewhere between Step 1 and Step 2, before the updated data has arrived. As a result, the user might click the button and open the Yandex Pay form with the old cart.

To avoid such a situation, updating the cart must lock the Yandex Pay button for the update period.

As an argument, the paymentSession.update method accepts a function (which is immediately executed). As a result of this function, a Promise is expected. The button is locked until the Promise resolves.

Example

function onYaPayLoad() {
    const YaPay = window.YaPay;
    let activeSession = null;

    // Payment details
    const paymentData = {
        env: YaPay.PaymentEnv.Sandbox,
        version: 2,
        countryCode: YaPay.CountryCode.Ru,
        currencyCode: YaPay.CurrencyCode.Rub,
        merchant: {
            id: '<YOUR_MERCHANT_ID>',
            name: 'test-merchant-name',
            url: 'https://test-merchant-url.ru',
        },
        order: getNewOrder(),
        paymentMethods: [
            {
                type: YaPay.PaymentMethodType.Card,
                gateway: 'test-gateway',
                gatewayMerchantId: 'test-gateway-merchant-id',
                allowedAuthMethods: [YaPay.AllowedAuthMethod.PanOnly],
                allowedCardNetworks: [
                    YaPay.AllowedCardNetwork.Visa,
                    YaPay.AllowedCardNetwork.Mastercard,
                    YaPay.AllowedCardNetwork.Mir,
                    YaPay.AllowedCardNetwork.Maestro,
                    YaPay.AllowedCardNetwork.VisaElectron,
                ],
            },
        ],
    };

    // Handler to obtain a payment token
    function onPaymentProcess(event) {
        console.log(`Payment token — ${event.token}`);
    }

    // Payment error handler
    function onPaymentError(event) {
        console.log(`Payment error — ${event.reason}`);
    }

    // Payment cancellation handler
    function onPaymentAbort(event) {}

    // Create a payment session.
    YaPay.createSession(paymentData, {
        onProcess: onPaymentProcess,
        onAbort: onPaymentAbort,
        onError: onPaymentError,
    })
        .then(function (paymentSession) {
            activeSession = paymentSession;
            paymentSession.mountButton(document.querySelector('#button_container'), {
                type: YaPay.ButtonType.Pay,
                theme: YaPay.ButtonTheme.Black,
                width: YaPay.ButtonWidth.Auto,
            });
        })
        .catch(function (err) {
            // Couldn't create a payment session. 
        });

    // Cart update emulation
    //   apiRequestPromise: API request Promise to update the cart in the service
    onOrderUpdate(function (apiRequestPromise) {
        if (!activeSession) {
            return console.log('Payment session is not created');
        }

        const newOrder = getNewOrder();

        // Update the cart, locking the button
        activeSession.update(async function () {
            await apiRequestPromise;

            return {
                order: newOrder,
            };
        });
    });
}

/**
 * Collateral features for illustrative purposes
 */

function getNewOrder() {
    const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

    const node = document.querySelector('#order_amount');
    const amount = randomInt(1000, 20000).toFixed(2);

    node.innerHTML = Intl.NumberFormat('ru-RU', {
        style: 'currency',
        currency: 'RUB',
    }).format(amount);

    return {
        id: `order-id-${Date.now()}`,
        total: { amount },
    };
}

function onOrderUpdate(cb) {
    const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    const updateButton = document.querySelector('#update_order_button');

    updateButton.addEventListener('click', function () {
        // Emulate the request's Promise to update the cart on the server
        const apiRequestPromise = wait(2000);

        cb(apiRequestPromise);
    });
}