Оформление заказа
На этом шаге мы создадим сценарий для оформления заказа и функции, с помощью которых будут обработаны выбранные товары.
Функции для работы с корзиной
Создайте файл function.js в папке src.
function deleteFromCart(name){
    var $session = $jsapi.context().session;
    for(var i = 0; i < $session.cart.length; i++){
        var current_position = $session.cart[i];
        if(current_position.name === name){
            $session.cart.splice(i, 1);
        }
    }
    log('!!!!!! CART: ' + JSON.stringify($session.cart));
}
function getTotalSum(){
    var totalSum = 0;
    var $session = $jsapi.context().session;
    for(var i = 0; i < $session.cart.length; i++){
        var current_position = $session.cart[i];
        for(var id = 1; id < Object.keys(pizza).length + 1; id++){
            if (current_position.name === pizza[id].value.title){
                var variation = _.find(pizza[id].value.variations, function(variation){
                    return variation.id === current_position.id;
                });
                totalSum += variation.price * current_position.quantity;
            }
        }
    }
    log("!!!!!!!!!!!! totalSum = " + totalSum);
    return totalSum;
}
function editText(messageId, text) {
    var $response = $jsapi.context().response;
    var reply = {
        type: "raw",
        body: {
            text: text,
            message_id: messageId,
            reply_markup: {
                "resize_keyboard": false,
            }
        },
        method: "editMessageText"
    };
    $response.replies = $response.replies || [];
    $response.replies.push(reply);
}
Здесь:
function deleteFromCart(name)— удаление товара из корзины;function getTotalSum()— подсчет общей суммы заказа;function editText(messageId, text)— редактирование предыдущих сообщений.
deleteFromCart()
Напишем функцию удаления товаров из корзины. В качестве входного параметра будем передавать название товара, который необходимо удалить.
function deleteFromCart(name){
    var $session = $jsapi.context().session;
    for(var i = 0; i < $session.cart.length; i++){
        var current_position = $session.cart[i];
        if(current_position.name === name){
            $session.cart.splice(i, 1);
        }
    }
    log('!!!!!! CART: ' + JSON.stringify($session.cart));
}
Создадим цикл, в котором будем проходить по каждому элементу массива товаров в корзине. Если имя товара совпадает с именем входной переменной, удаляем из массива этот товар с помощью метода splice(). Метод splice() добавляет и удаляет элементы из массива, меняя его.
Затем с помощью функции log() выведем сообщение о внесенных изменениях. Во вкладке Логи при удалении товара будет появляться следующее сообщение:
!!!!!! CART: [{"name":"Пепперони","id":7,"quantity":1}]
getTotalSum()
Напишем функцию, которая будет возвращать полную стоимость товаров из корзины.
Создадим переменную totalSum, в которой будем хранить сумму. Пройдемся циклом по всем товарам в корзине и для каждого вида пицц посчитаем сумму, умножив стоимость variation.price на количество конкретного товара current_position.quantity.
function getTotalSum(){
    var totalSum = 0;
    var $session = $jsapi.context().session;
    for(var i = 0; i < $session.cart.length; i++){
        var current_position = $session.cart[i];
        for(var id = 1; id < Object.keys(pizza).length + 1; id++){
            if (current_position.name === pizza[id].value.title){
                var variation = _.find(pizza[id].value.variations, function(variation){
                    return variation.id === current_position.id;
                });
                totalSum += variation.price * current_position.quantity;
            }
        }
    }
    log("!!!!!!!!!!!! totalSum = " + totalSum);
    return totalSum;
}
Затем с помощью функции log() выведем сумму всех товаров в корзине. Во вкладке Логи появится следующее сообщение:
!!!!!!!!!!!! totalSum = 299
editText()
Напишем функцию, которая будет редактировать сообщения. Функция editText(messageId, text) использует метод editMessageText и позволяет редактировать предыдущие сообщения бота. В процессе редактирования корзины мы заменяем название удаленной пиццы на сообщение 'Удален'.
function editText(messageId, text) {
    var $response = $jsapi.context().response;
    var reply = {
        type: "raw",
        body: {
            text: text,
            message_id: messageId,
            reply_markup: {
                "resize_keyboard": false,
            }
        },
        method: "editMessageText"
    };
    $response.replies = $response.replies || [];
    $response.replies.push(reply);
}
Создание сценария
Создайте файл сценария cart.sc в папке src.
require: function.js
theme: /
    state: Cart
        intent!: /корзина
        a: Ваша корзина:
        script:
            $temp.totalSum = 0;
            var n = 0;
            for(var i = 0; i < $session.cart.length; i++){
                var current_position = $session.cart[i];
                for(var id = 1; id < Object.keys(pizza).length + 1; id++){
                    if (current_position.name == pizza[id].value.title){
                        var variation = _.find(pizza[id].value.variations, function(variation){
                            return variation.id === current_position.id;
                        });
                        n++;
                        if (!variation) {
                            $reactions.answer("Что-то пошло не так, вариант не найден для id " + current_position.id);
                        } else {
                            $reactions.answer(n + ". " + current_position.name + ", " + variation.name + "\nЦена: " + variation.price + "\nКоличество: " + current_position.quantity);
                            $reactions.inlineButtons({text: "Удалить", callback_data: current_position.name});
                            $temp.totalSum += variation.price * current_position.quantity;
                        }
                    }
                }
            }
            $session.messageId = $request.rawRequest.message.message_id + n + 2;
        a: Общая сумма заказа: {{ $temp.totalSum }} рублей.
        a: Если все верно, отправьте свой номер телефона, и наш менеджер с вами свяжется.
        buttons:
            {text: "Отправить номер телефона", request_contact: true}
            "Меню" -> /ChoosePizza
        state: Edit
            event: telegramCallbackQuery
            script:
                var name = $request.rawRequest.callback_query.data;
                deleteFromCart(name);
                var message_id = $request.rawRequest.callback_query.message.message_id;
                editText(message_id, 'Удален');
                editText($session.messageId, 'Общая сумма заказа: ' + getTotalSum() + ' руб.');
            if: $session.cart.length == 0
                a: Вы очистили корзину
                go!: /ChoosePizza
            state: ClickButtons
                q: *
                a: Нажмите, пожалуйста, кнопку.
                go!: ..
    state: GetPhoneNumber
        event: telegramSendContact
        script:
            $client.phone_number = $request.rawRequest.message.contact.phone_number;
        a: Спасибо! Наш менеджер свяжется с вами по номеру телефона {{ $client.phone_number }}.
Подключение модулей
В начале сценария под тегом require подключаем справочник function.js.
require: function.js
Теперь подключим сценарий cart.sc к основному сценарию main.sc:
require: cart.sc
Стейты
Сценарий состоит из следующих стейтов:
Cart— вывод содержимого корзины и общей суммы заказа.Edit— редактирование корзины.GetPhoneNumber— отправка номера телефона для подтверждения заказа.
Структура сценария
Cart
state: Cart
    intent!: /корзина
    a: Ваша корзина:
    script:
        $temp.totalSum = 0;
        var n = 0;
        for(var i = 0; i < $session.cart.length; i++){
            var current_position = $session.cart[i];
            for(var id = 1; id < Object.keys(pizza).length + 1; id++){
                if (current_position.name == pizza[id].value.title){
                    var variation = _.find(pizza[id].value.variations, function(variation){
                        return variation.id === current_position.id;
                    });
                n++;
                if (!variation) {
                    $reactions.answer("Что-то пошло не так, вариант не найден для id " + current_position.id);
                    } else {
                        $reactions.answer(n + ". " + current_position.name + ", " + variation.name + "\nЦена: " + variation.price + "\nКоличество: " + current_position.quantity);
                        $reactions.inlineButtons({text: "Удалить", callback_data: current_position.name});
                        $temp.totalSum += variation.price * current_position.quantity;
                    }
                }
            }
        }
        $session.messageId = $request.rawRequest.message.message_id + n + 2;
        a: Общая сумма заказа: {{ $temp.totalSum }} рублей.
        a: Если все верно, отправьте свой номер телефона, и наш менеджер с вами свяжется.
        buttons:
            {text: "Отправить номер телефона", request_contact: true}
            "Меню" -> /ChoosePizza
Интент
Сделаем так, чтобы клиент мог проверить товары в корзине из любого стейта. Создадим интент /корзина, по которому будет осуществляться переход в стейт cart.
Перейдите на вкладку NLU > Интенты, расположенную в боковом меню. Создайте интент и добавьте в поле Тренировочные фразы следующие фразы:
покажи корзину
что там в корзине
что в корзине
корзина

Скрипт
Здесь бот выводит список всех товаров из корзины и их полную стоимость.
Создадим переменную $temp.totalSum, в которую будем записывать стоимость товаров.
script:
    $temp.totalSum = 0;
    var n = 0;
    for(var i = 0; i < $session.cart.length; i++){
        var current_position = $session.cart[i];
        for(var id = 1; id < Object.keys(pizza).length + 1; id++){
            if (current_position.name == pizza[id].value.title){
                var variation = _.find(pizza[id].value.variations, function(variation){
                    return variation.id === current_position.id;
                });
                n++;
                if (!variation) {
                    $reactions.answer("Что-то пошло не так, вариант не найден для id " + current_position.id);
                } else {
                    $reactions.answer(n + ". " + current_position.name + ", " + variation.name + "\nЦена: " + variation.price + "\nКоличество: " + current_position.quantity);
                    $reactions.inlineButtons({text: "Удалить", callback_data: current_position.name});
                    $temp.totalSum += variation.price * current_position.quantity;
                }
            }
        }
    }
    $session.messageId = $request.rawRequest.message.message_id + n + 2;
Теперь предложим клиенту отправить номер телефона, чтобы завершить заказ. Для этого поставим две кнопки: Отправить номер телефона и Меню. Первая будет вызывать API метод Telegram request_contact для отправки номера телефона, а вторая направлять в стейт ChoosePizza.
a: Если все верно, отправьте свой номер телефона, и наш менеджер с вами свяжется.
buttons:
    {text: "Отправить номер телефона", request_contact: true}
    "Меню" -> /ChoosePizza
Edit
Telegram поддерживает функцию редактирования предыдущих сообщений. Если клиент ре шил удалить какие-либо товары из корзины, бот должен сообщить о внесенных изменениях и пересчитать общую сумму заказа.
В процессе редактирования корзины мы заменяем название удаленной пиццы на сообщение Удален. Если корзина окажется пустой, то бот выведет сообщение Вы очистили корзину и перейдет в стейт ChoosePizza.
state: Edit
    event: telegramCallbackQuery
    script:
        var name = $request.rawRequest.callback_query.data;
        deleteFromCart(name);
        var message_id = $request.rawRequest.callback_query.message.message_id;
        editText(message_id, 'Удален');
        editText($session.messageId, 'Общая сумма заказа: ' + getTotalSum() + ' руб.');
    if: $session.cart.length == 0
        a: Вы очистили корзину
        go!: /ChoosePizza
    state: ClickButtons
        q: *
        a: Нажмите, пожалуйста, кнопку.
        go!: ..
Добавим вложенный стейт ClickButtons:
state: ClickButtons
    q: *
    a: Нажмите, пожалуйста, кнопку.
    go!: ..
GetPhoneNumber
Для оформления заказа попросим клиента оставить свой номер телефона. Как только он отправит свой номер, сработает событие telegramSendContact. Полученный номер будем хранить в переменной $client.phone_number.
state: GetPhoneNumber
    event: telegramSendContact
    script:
        $client.phone_number = $request.rawRequest.message.contact.phone_number;
    a: Спасибо! Наш менеджер свяжется с вами по номеру телефона {{ $client.phone_number }}.
Тестирование
Протестируем результат в Telegram. Результат запуска:
Далее перейдем к тестированию сценария.