Обновление стоимости заказа

После создания платежной сессии иногда возникает необходимость обновить стоимость заказа. Стоимость влияет на доступность оплаты через Сплит. Поэтому при изменении стоимости заказа важно обновлять стоимость на кнопке Яндекс Пэй, чтобы пользователь имел актуальную информацию о доступности Сплита. Обычно обновление корзины — это асинхронное действие, которое по шагам выглядит так:

  1. Пользователь меняет состав корзины (или конечную сумму заказа).
  2. Продавец обновляет данные у себя на сервере.
  3. Продавец обновляет данные в платежной сессии Яндекс Пэй.

Проблема в том, что пользователь может начать процесс оплаты где-то между 1 и 2 пунктом, не дождавшись обновленных данных. Таким образом, он нажмет на кнопку и откроет форму Яндекс Пэй, ожидая воспользоваться Сплитом, однако Сплит может быть недоступен для обновленной суммы заказа.

Чтобы избежать подобной ситуации, нужно обновлять корзину с блокировкой кнопки Яндекс Пэй на время обновления.

Метод paymentSession.update принимает в качестве аргумента функцию (которая тут же выполняется), результатом работы которой ожидается Promise. Кнопка блокируется до резолва Promise.

Пример

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

    // Данные платежа
    const paymentData = {
        env: YaPay.PaymentEnv.Sandbox,
        version: 4,
        currencyCode: YaPay.CurrencyCode.Rub,
        merchantId: '<YOUR_MERCHANT_ID>',
        totalAmount: '7990.00',
        availablePaymentMethods: ['CARD', 'SPLIT'],
    };

    // Обработчик на клик по кнопке
    // Функция должна возвращать промис которые резолвит ссылку на оплату полученную от бэкенда Яндекс Пэй
    // Подробнее про создание заказа: https://pay.yandex.ru/ru/docs/custom/backend/yandex-pay-api/order/merchant_v1_orders-post
    async function onPayButtonClick() {
        /* Создание заказа... */
    }

    // Создаем платежную сессию
    YaPay.createSession(paymentData, {
        onPayButtonClick: onPayButtonClick,
    })
        .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) {
            // Не получилось создать платежную сессию.
        });

    // Эмуляция обновления корзины
    //   apiRequestPromise — Promise api-запроса на обновление корзины на сервисе
    onOrderUpdate(function (apiRequestPromise) {
        if (!activeSession) {
            return console.log('Payment session is not created');
        }

        const newAmount = getNewAmount();

        // Обновляем корзину с блокировкой кнопки
        activeSession.update(async function () {
            await apiRequestPromise;

            return {
                totalAmount: newAmount,
            };
        });
    });
}

/**
 * Сопроводительные функции для иллюстрации работы
 */

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

    const price = 7990;
    const count = randomInt(1, 20);

    return `${price * count}.00`;
}

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

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

    updateButton.addEventListener('click', function () {
        // Эмуляция Promise'a запроса на обновление корзины на сервере
        const apiRequestPromise = wait(2000);

        cb(apiRequestPromise);
    });
}