Документы
Как в документе отключить сообщение о не проданных товарах стандартного ассортимента?
Необходимо добавить action-скрипт на точку расширения stmobile://module/skudocs/config в котором конфигурируется соответствующий параметр:
function doAction() { var conf = { "isNeedCheckUnsoldAssortment": false } api.result.setConfig(conf); }
Как добавить в документ свою колонку с каким-то значением?
Добавление кастомной колонки в документ осуществлется двумя action-скриптами: один на preopen, другой на iteminit.
Скрипт на preopen будет вызван однажды при открытии документа и служит для добавления колонки, а скрипт на iteminit будет вызван для каждой строки документа и служит для заполнения значения.
Создайте два каталога: preopen и iteminit.
Метафайл action-скрипта на событие preopen будет выглядеть следующим образом:
Теперь создайте соответствующий data-скрипт с именем preopen.js.
Создание колонки осуществляется следующим образом:
Добавьте схожим образом метафайл скрипта на событие iteminit:
В data-скрипте необходимо получить доступ к конкретному строчному атрибуту:
Скрипт на 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), структура имеет вид:
Если структура будет пуста, в базу ничего не будет записано, но бонусные баллы будут потрачены:
Вызывается после проведение бонуса и только регистрирует факт проведения.
Не требует возвращения данных
stmobile://tma/bonus/preunregistration
Вызывается перед отменой бонуса и позволяет изменить параметры передающиеся на отмену (количество бонусных балов, скидка и etc), так же позволяет провести прерывание процесса отмены бонуса.
Работа со структурами подобна preregistration.
stmobile://tma/bonus/postunregistration
Вызывается после отмены бонуса и только регистрирует факт проведения
Не требует возвращения данных
Вызывается перед проведением бонуса и позволяет изменить параметры, передающиеся на проведение (количество бонусных балов, скидка и 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 визита:
Примерный скрипт на 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".
\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.
Внимание: в примере проверка по совпадению имени модуля является регистронезависимой.
Пример реализации расширения для кастомизации глобального меню:
В функции 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"; }