Главная

Руководство: FAQ

FAQ

Документы

Как в документе отключить сообщение о не проданных товарах стандартного ассортимента?
Необходимо добавить action-скрипт на точку расширения stmobile://module/skudocs/config в котором конфигурируется соответствующий параметр:
function doAction() {
    var conf = {
        "isNeedCheckUnsoldAssortment": false
    }

    api.result.setConfig(conf);
}
Как добавить в документ свою колонку с каким-то значением?
Добавление кастомной колонки в документ осуществлется двумя action-скриптами: один на preopen, другой на iteminit.
Скрипт на preopen будет вызван однажды при открытии документа и служит для добавления колонки, а скрипт на iteminit будет вызван для каждой строки документа и служит для заполнения значения.
Создайте два каталога: preopen и iteminit.
Метафайл action-скрипта на событие preopen будет выглядеть следующим образом:
{
    "uri": "stmobile://action/<ДОКУМЕНТ>/preopen",
    "type": "action",
    "datascript": {
        "script_file": "preopen.js"
    }
}
Где <ДОКУМЕНТ> - название документа, например preorder.

Теперь создайте соответствующий data-скрипт с именем preopen.js.
Создание колонки осуществляется следующим образом:
var newAttr = api.form.newRowsAttribute('columnNameHere'); // Добавление колонки
newAttr.title = "Название колонки";                        // Установка заголовка
Более подробно о доступных полях: Attribute

Добавьте схожим образом метафайл скрипта на событие iteminit:
{
    "uri": "stmobile://action/<ДОКУМЕНТ>/iteminit",
    "type": "action",
    "datascript": {
        "script_file": "iteminit.js"
    }
}
И создайте data-скрипт iteminit.js.
В data-скрипте необходимо получить доступ к конкретному строчному атрибуту:
var currAttr = api.form.rowAttribute('columnNameHere', api.context.rowItemId);
currAttr.value = 42; // установка значения
Для обмена данными между двумя скриптами используйте кэш.
Как добавить в меню (три точки) свои пункты?
Для работы необходимо создать метафайл обработчика действия (action) на URI stmobile://document//form/config.
Дата-скрипт должен содержать следующую функцию (имя функции предопределено):
function mtcall_menuAdditionalItems() {
    var items = [{
                    "name": "photoReport",      // имя пункта меню
                    "title": "Фотоотчет",       // выводимый текст
                    "onclick": openPhotoReport  // JavaScript-функция вызываемая при нажатии на пункт меню
                }];

    api.result.setConfig(items);
}
api.result.setConfig принимает в качестве параметра массив и устанавливает конфигурацию формы.
Как скрыть/отключить редактирование блоков "Условие акции" и "Бонус"?
Для работы необходимо создать метафайл обработчика действия (action) на URI stmobile://document/tma/form/config.
Дата-скрипт должен содержать следующую функцию (имя функции предопределено):
function mtcall_mechanicsFormConfig() {
    var config = {
        conditionsPanelVisible: true,   // отображение блока "Условие акции"
        conditionsPanelEnabled: false,  // редактирование блока "Условие акции"
        bonusPanelVisible: true,        // отображение блока "Бонус"
        bonusPanelEnabled: false        // редактирование блока "Бонус"
    }

    api.result.setConfig(config)
}
api.result.setConfig принимает в качестве параметра объект и устанавливает конфигурацию формы.
Как включить возможность редактирования штрих-кода после сканирования в документе "Опросный лист"?
Для работы необходимо создать метафайл обработчика действия (action) на URI stmobile://document/survey/form/config.
Дата-скрипт должен содержать следующую функцию (имя функции предопределено):
function mtcall_editAnswerConfig() {
    var config = {
        isAllowedBarcodeManualEdit: true,   // включить редактирование штрих-кода
    }

    api.result.setConfig(config)
}
api.result.setConfig принимает в качестве параметра объект и устанавливает конфигурацию формы.
Почему я не могу установить новое значение в документе из точки расширения itemchange?
Точка расширения itemchange срабатывает при изменении значения в колонке. Однако, если установить новое значение (value) у объекта, возвращаемого методом api.form.rowAttribute, то значение в дальнейшем перезапишется тем, что хранится в памяти калькулятора. Поэтому единственно верным вариантом является установка необходимого значения в точках расширения itempresave или itempostsave, а точка расширения itemchange может служить лишь для получения очередного вводимого значения.
Как работать с обработчиками действий "Акции и бонусы"?
stmobile://tma/bonus/preregistration
Вызывается перед проведением бонуса и позволяет изменить параметры, передающиеся на проведение (количество бонусных балов, скидка и etc), так же позволяет провести прерывание процесса оформления бонуса.
На вход передается структура registerData в контексте (api.context.registerData), структура имеет вид:
{
    bonusItemsList: 
        [
            {
                skuId: ID // идентификатор товара к которому применяется бонус
                value: number // количество бонусов
            },
            ... ,
        ],
    bonusPoint: number   // количество бонусных балов переданных на сохранение, не доступно к изменению 
}
На выход скрипта надо передать точно такую же структуру, она подменит текущую переданную на сохранение.
Если структура будет пуста, в базу ничего не будет записано, но бонусные баллы будут потрачены:
api.result.setData("bonusItemsList" , {...});
api.result.setData("bonusPoint" , 1);
stmobile://tma/bonus/postregistration
Вызывается после проведение бонуса и только регистрирует факт проведения.
Не требует возвращения данных

stmobile://tma/bonus/preunregistration
Вызывается перед отменой бонуса и позволяет изменить параметры передающиеся на отмену (количество бонусных балов, скидка и etc), так же позволяет провести прерывание процесса отмены бонуса.
Работа со структурами подобна preregistration.

stmobile://tma/bonus/postunregistration
Вызывается после отмены бонуса и только регистрирует факт проведения
Не требует возвращения данных
Как заполнить опросный лист своими значениями ?
Чтобы заполнить документ ОЛ своими значениями по умолчанию, необходимо использовать точку расширения stmobile://document/survey/customanswers.
Метафайл скрипта:
    {
        "uri": "stmobile://document/survey/customanswers",
        "type": "action",
        "datascript": {
            "script_file": "customAnswers.js"
        }
    }
Содержимое файла customAnswers.js:
    function doAction() {
        const { distributorId, templateId } = api.context;
        const topics = api.survey.service.topics(templateId).value;
        const answers = [];

        topics.forEach((topic) => {
            const questions = api.survey.service.questions(templateId, topic.id, distributorId).value;

            questions.forEach((question) => {
                const { possibleValues } = question.answerValuesRange;
                const answer = {
                    topicId: topic.id,
                    questionId: question.id,
                    values: [],
                };

                switch (question.answerType) {
                    case 'DataTypeInteger':
                        answer.values.push(357);
                        break;
                    case 'DataTypeReal':
                        answer.values.push(111.111);
                        break;
                    case 'DataTypeYesNo':
                        answer.values.push(1);
                        break;
                    case 'DataTypeYesNoUnknown':
                        answer.values.push(2);
                        break;
                    case 'DataTypeSingle':
                        answer.values.push(possibleValues[1].value);
                        break;
                    case 'DataTypeMultiple':
                        answer.values.push(possibleValues[1].value);
                        break;
                    case 'DataTypeText':
                        answer.values.push('text');
                        break;
                    case 'DataTypeBarCode':
                        answer.values.push('1q2w3e4r5t');
                        break;
                    case 'DataTypeDate':
                        answer.values.push(new Date(2019, 3, 25));
                        break;
                    case 'DataTypeTime':
                        answer.values.push(new Date(1900, 0, 1, 2, 30));
                        break;
                    case 'DataTypeDateTime':
                        answer.values.push(new Date(2019, 3, 25, 14, 40));
                        break;
                    default:
                        answer.values.push('-');
                }

                answers.push(answer);
            });
        });

        api.result.setParams("customAnswers", answers);
    }

Визиты

Как отменить автоматический вывод выбора результата посещения ТТ и вернуть своё значение?
Для отмены автоматического запроса результата визита необходимо вернуть из скрипта visit/presave resultId посредством api.result.setData. Получение модели результатов посещения осуществляется методом api.visits.reasonModel
Примерный скрипт на presave визита:
var reasons = api.visit.reasonModel();
var ret = api.interactive.selectSingleValue("Результат посещения", reasons, reasons[0].value);
if (!ret.success) {
   // нажали "Отмена"
   ...
}
else {
    var reasonId = ret.value;
    api.result.setData("reasonId", reasonId);
}
Как отключить серийные проверки при завершении визита?
Для отключения серийных проверок при завершении визита предусмотрена точка расширения stmobile://action/visit/preclose.
Для отключения серийных проверок необходимо установить из скрипта значение checksDisabled посредством api.result.setData Для показа/скрытия информационного сообщения об ошибках при завершении визита используется api.result. Пример:
    if (shouldClose) {
        // закрыть визит без проверок
        api.result.setData('checksDisabled', true);
    } else {
        // показать ошибку при завершении визита
        api.result.isShow = true;
        api.result.text = 'Отсутствует фотография фасада торговой точки';
        api.result.type = 'error';
    }
Серийные проверки, которые отключаются скриптом:
  • проверка на наличие незавершенных документов или черновиков
  • проверка на незавершенные задачи
  • проверка на завершение всех обязательных шагов сценария
Проверка на наличие и получение координат визита не отключается

Примеры использования данной точки расширения:
  • Разместить пользовательские проверки на завершение визита и отключить серийные проверки
  • Вызвать диалог с исходами визита и, в зависимости от выбранного исхода, заменить серийные проверки на пользовательские. Для реализации данного варианта необходимо дополнительно использовать точку расширения stmobile://action/visit/presave и api.cache для передачи идентификатора выбранного исхода в скрипт точки расширения visit/presave.

Карточка ТТ

Как настроить отображение модулей в карточке ТТ?
1. Откройте файл manifest.json карточки ТТ в вашей папке МТ:
\extensions\reports\outletreport\manifest.json

2. Найдите в файле manifest.json пункт "config", подпункт "modules".
Для каждого подключенного модуля есть свой набор свойств в подпункте "modules".

Cписок доступных модулей (актуально для версии 4.4.8):

        1. last_visits     - Последние визиты
        2. limits          - Лимиты
        3. matched_outlets - Сопоставленные точки
        4. outlet_photos   - Фотографии точки
        5. properties      - Общая информация
        6. visits_calendar - Календарь визитов
    

Содержимое файла manifest.json

    {
        ...
        "config": {
            "settingsKey": "myreport_open_modules",
            "modules": [
            {
                "name": "my_module",            // имя подключенного модуля (обязат.)
                "position": 1,                  // порядок сортировки (обязат.)
                "uiName": "qsTr(My module)",    // заголовок, который будет отображен в интерфейсе (обязат.)
                "visibilityCheck": true,        // проверка отображения модуля
                "reloadCheck": "self",          // проверка необходимости перезагрузки модуля
                "isDisabled": false             // отключение загрузки модуля
            }
            ]
        }
        ...
    }
    
Изменение порядка модулей
  • Модули выстраиваются в колонку (сверху вниз). На порядок сортировки указывает свойство "position".
  • Чем меньше значение "position", тем ближе к началу.
  • Чтобы изменить положение модуля, замените для него свойство "position", например, "position": 4,.
Загрузка модуля
  • Для того, чтобы модуль не загружался установите для него свойство "isDisabled" в значение true.

ВАЖНО!

формат json очень требователен к синтаксису:
  • строки в двойных кавычках
  • числа и булевы значения без кавычек
  • сохраняйте знаки препинания
  • комментарии запрещены

Формы

Как настроить атрибуты в форме редактирования торговой точки?
Необходимо создать расширение на точку stmobile://outlet/attributes
function doAction() {

    var attributes = api.context.config,
        attributesLength = attributes.length;

    for (var i = 0; i < attributesLength; i++) {
        // Структура атрибута:
        // {
        //     isReadonly:    bool,   (только для чтения)
        //     isRequired:    bool,   (обязательный для заполнения)
        //     defValue:      string, (значение по-умолчанию, используется только при создании новой ТТ)
        //     isShared:      bool,   (разделяемый или нет)
        //     distributorId: id,     (задано, если атрибут разделяемый)
        //     isUsed:        bool,   (признак использования атрибута)
        //     isVisible:     bool,   (признак отображения на форме. Атрибут может существовать в невидимом виде.
        //                             Если при этом атрибуту назначено значение по-умолчанию, то оно сохранится при записи)
        //     param:         string  (параметр атрибута, обычно указывает на классификатор, например, "ClassifierTT1")
        //     title:         string  (заголовок атрибута)
        //     type:          string  (внутреннее название атрибута, см. структуру AttributeType)
        //     valueHint:     string  (подсказка-placeholder для текстовых полей)
        // }
        attributes[i].isRequired = true;
    }

    // Установка новых значений параметров
    api.result.setConfig(attributes);

}
Почему не обновляется значение атрибута при использовании api.form.rowAttribute?
Чтобы настройки для атрибута применялись из скрипта, а не из конфига, для атрибута необходимо установить флаг force:
    // Скрываем колонку
    const rest = api.form.rowAttribute('NameRestStore');
    rest.force = true;
    rest.view = false;

JavaScript

Почему в новых версиях МТ у меня не работает регулярное выражение? (а раньше работало)
Скорее всего в регулярном выражении используется флаг g. JS-движок старых версий МТ не совсем точно следовал букве стандарта, в связи с чем значение свойства lastIndex сбрасывалось при повторном выполнении сравнения. Однако, это не верно, необходимо сбрасывать указатель. Пример:
// Было
...
for (var i = 0; i <= length; i++) {
    var reg = /(привет)?/g;
    var match = reg.exec(data[i]);
    if (match[1]) result.push(match[1]);
}
...
// Надо
...
var reg = /(привет)?/g;
for (var i = 0; i <= length; i++) {
    var match = reg.exec(data[i]);
    if (match[1]) result.push(match[1]);
    reg.lastIndex = 0;
}
...

HTML

Как вывести шаблонизатором несколько раз одно и то же
Встроенный в МТ шаблонизатор Grantlee имеет недокументированный тэг range, работающий аналогично одноименной функции языка Python. Примеры:
<ul>
{% range 5 as num %}
<li>{{ num }}</li>
{% endrange %}
</ul>
Получится:
  • 0
  • 1
  • 2
  • 3
  • 4
<ul>
{% range 5 10 as num %}
<li>{{ num }}</li>
{% endrange %}
</ul>
Получится:
  • 5
  • 6
  • 7
  • 8
  • 9
<ul>
{% range 5 30 5 as num %}
<li>{{ num }}</li>
{% endrange %}
</ul>
Получится:
  • 5
  • 10
  • 15
  • 20
  • 25
Датаскрипт:
...
mapper.rating = 4;
...
{% range rating %}
  *
{% endrange %}
Получится:
* * * *

Не работает API

Копирование/вставка наименований методов из документации
В документации в заголовках api могут присутствовать некорректные символы, а именно, одна из точек является другим символом юникода. Копирование методов из документации в код может привести к синтаксическим ошибкам при исполнении.

    // Примерный текст ошибки
    Can not call method of undefined
При этом линтер не подчеркнёт некорректные символы, а внешне они будут выглядеть одинаково.

SQL

Почему на устройстве я получаю ошибку "too many terms in compound SELECT"?
Сократите количество выражений SELECT, превышен их лимит (500), скорее всего неудачно сформирован запрос.

Общее

Как поменять глобальное меню и/или добавить свои пункты?
Создайте action-скрипт на URI stmobile://globalmenu/items
В функции doAction необходимо получить посредством api.context.config массив объектов в формате JSON, который содержит структуры, описывающие каждый элемент меню. Далее можно заменить или добавить пользовательские элементы, после чего отдать полученный массив обратно при помощи api.result.setConfig.
Внимание: в примере проверка по совпадению имени модуля является регистронезависимой.
Пример реализации расширения для кастомизации глобального меню:
function doAction() {

    var defaultItems = api.context.config;
    var userDefinedItems = [
            {
                "name":  "Summary",
                "icon":  "globalmenu/dashboard",
                "title": "Summary",
                "uri":   "stmobile://dashboard"
            },
            {
                "name":     "route",
                "icon":     "globalmenu/route",
                "title":    "Supervisor Routes",
                "uri":      "stmobile://route",
                "subtitle": "Ленинградский р-н"
            }
        ];

    for (var i = 0; i < userDefinedItems.length; i++) {
        var isFound = false;
        for(var j = 0; j < defaultItems.length; j++) {
            var userObject = userDefinedItems[i];
            var defaultObject = defaultItems[j];
            if (defaultObject.hasOwnProperty["name"] &&
                defaultObject["name"].toLowerCase() === userObject["name"].toLowerCase())
            {
                defaultObject["title"]    = userObject["title"];
                defaultObject["icon"]     = userObject["icon"];
                defaultObject["uri"]      = userObject["uri"];
                defaultObject["subtitle"] = userObject["subtitle"];
                isFound = true;
            }
        }
        if (!isFound) defaultItems.push(userObject);
    }

    api.result.setConfig(defaultItems);
    api.result.type = "ok";

}