И так представьте, одним прекрасным днём к вам, как к системному администратору, поступает задача. За пару дней обновить все фискальные регистраторы во всех точках продаж, т.к. в маркировке очередные изменения и для их поддержки нужно перепрошить все ККМ новой прошивкой. И за одно, коль уж предстоит играться с ККМ, ещё добавить логотип компании и индивидуальную рекламную информацию в чек для каждой точки продаж. Вот моим решением такой интересной задачи, я хотел бы с вами поделиться. И рассказать о полезных моментах, которые вам могут пригодиться, в аналогичной ситуации.
Распределение ККМ и точек продаж по Московской области
Тут сразу становиться очевидно, что нужно автоматизировать данную задачу. Количество точек не маленькое и нет гарантий, что через месяц не прилетит аналогичная задача, но уже с новой версией прошивки и придётся делать всё заново. Да и кассы постоянно заменяются на точках и хочется, чтобы они настраивались сами и постоянно.
Хорошо что мы всегда были за унификацию оборудования и на всех точках у нас Штрих-М, но правда четырёх разных моделей. Работать с оборудованием одного производителя всегда проще.
Первым делом, для написания скриптов, разобьём задачу на подзадачи:
Во-первых, как взаимодействовать с ККМ? Тут всё оказалось просто. Драйвер фискального регистратора создаёт ActiveX объект, вот через него мы и будем строить своё взаимодействие. Поэтому на сайте производителя помимо свеженького установочного файла драйвера, нам ещё пригодится документ ШТРИХ-М: Драйвер ККТ А4.15. Руководство программиста. На моё удивление в этом документе всё очень чётко, структурированно и понятно расписано, какие свойства и методы есть у этого объекта, и как их вызывать.
// создаём объект для взаимодействия с кассой
if (!error) {// если нету ошибок
try {// пробуем подключиться к кассе
driver = new ActiveXObject("Addin.DrvFR");
speed = driver.BaudRate;
driver.Password = password;
driver.GetECRStatus();
if (!driver.ResultCode) {// если запрос выполнен
} else error = 2;
} catch (e) { error = 2; };
};
Пару слов, про то, как вызывать эти методы. Производитель реализовал достаточно интересный подход к API. Ты создаёшь экземпляр объекта, у него есть свойства и методы, но методы не принимают параметры, в привычном понимании этого. Вместо этого, ты просто перед вызовом метода у экземпляра объекта задаёшь необходимые свойства. Вызываешь метод без параметров. А затем читаешь значения из нужных тебе свойств. По началу данный подход кажется не привычным, но потом находишь его удобным, т.к. тебе не нужно парится об переменных, в которых хранить результаты выполнения методов. Ты просто всегда можешь обратиться к экземпляру объекта и прочитать нужные свойства.
Графический интерфейс тест-драйвера Штрих-М для ККМ
Кстати, в графическом интерфейсе тест-драйвера при наведении на почти все кнопки и поля выскакивают подсказки с интересными названиями. Так вот, это как раз названия методов и свойств, которые нужно вызвать при программной реализации взаимодействия, для получения аналогичного результата. Такой любезное отношение к разработчикам очень порадовало, и сэкономило мне кучу времени на поиске нужного метода. За что производителю отдельное спасибо.
Второй интересный момент. Как загрузить файл прошивки в ККМ? Оказалась тут есть нюансы. Если в фискальный регистратор установлена обычная SD карта, то просто вызываем нужный метод, загружаем файл на эту карту и другим методом перезагружаем ККМ. При включении ККМ обновится.
// загружаем прошивку на карту память
if (!error && !isUpdated) {// если нужно выполнить
driver.FileType = 1;// прошивка
driver.FileName = image;
driver.LoadFileOnSDCard();
if (!driver.ResultCode) {// если данные получены
} else error = 11;
};
// перезагружаем кассу
if (!error && !isUpdated) {// если нужно выполнить
driver.RebootKKT();
if (!driver.ResultCode) {// если данные получены
} else error = 12;
};
Но если SD карты нет, то нужен другой подход. И он зависит от того, как подключена ККМ к компьютеру. Если через USB, то нужно использовать режим DFU.
// обновляем прошивку через usb
if (!error && !isUpdated) {// если нужно выполнить
driver.UpdateFirmwareMethod = 0;// DFU
driver.FileName = image;
driver.UpdateFirmware();
if (!driver.ResultCode) {// если запрос выполнен
while (1 == driver.UpdateFirmwareStatus) wsh.sleep(timeout);
if (!driver.UpdateFirmwareStatus) isUpdated = true;
};
};
Если ККМ подключена к компьютеру через COM порт, то нужно использовать режим XMODEM.
// обновляем прошивку через com
if (!error && !isUpdated) {// если нужно выполнить
driver.UpdateFirmwareMethod = 1;// XMODEM
driver.FileName = image;
driver.UpdateFirmware();
if (!driver.ResultCode) {// если запрос выполнен
while (1 == driver.UpdateFirmwareStatus) wsh.sleep(timeout);
if (!driver.UpdateFirmwareStatus) isUpdated = true;
} else error = 8;
};
В-третьих, после обновления нужно сделать технологическое обнуление, а перед ним нужно сохранить все настройки ККМ и потом восстановить их. Но тут я решил сделать всё просто, сохранить таблицу значений в многомерный массив и потом восстановить её из этого массива.
Хорошо бы перед прошивкой кассы проверять текущую версию прошивки, чтобы не иметь возможность не прошивать уже прошитые кассы. Так же хорошо бы проверять ещё и модель, на случай разных файлов с прошивками для разных моделей. Ну и так же не нужно прошивать кассу если на ней открыта смена. Добавляем эти проверки необязательными параметрами и в итоге получаем скрипт firmware.min.js который можно запускать из командной строки и выполнять прошивку ККМ одной командой.
Уведомление пользователя с помощью команды shutdown
Во-первых, нужно предусмотреть возможность уведомления пользователя. Т.к. при подключении ККМ к компьютеру, что по USB, что по COM, c ККМ через драйвер может взаимодействовать только одна программа. И если точка работает круглосуточно, то в тихом режиме такую ККМ мы никогда не перенастроим.
Но как сообщить вошедшему пользователю, что нужно сделать трёхминутный перерыв? Ведь скрипт исполняется в контексте другого административного пользователя или в моём случае от имени системы. И показывать какие-то сообщения бесполезно, другой пользователь их не увидит. Тут я решил использовать простой и давно проверенной мной способ, вызываем через shutdown отложенную перезагрузку и сообщением, а затем отменяем её. Если вы знаете более интересные способы, напишите пожалуйста в комментариях, я думаю они всем пригодятся.
// прерываем работу пользователя
if (!silent) {// если можно прервать работу пользователя
// показываем начальное сообщение пользователю
if (!error) {// если нету ошибок
value = // сообщение для пользователя
"Через 2 минуты на компьютер будет установлено обновление для ККМ. " +
"Нужно будет закрыть кассу программы еФарма. Закрывать смену при этом не нужно. " +
"Установка займёт 3 минуты. После этого вы сможете работать.";
command = 'shutdown /r /t 60 /c "' + value + '"';
shell.run(command, 0, false);
wsh.sleep(30 * 1000);
command = "shutdown /a";
shell.run(command, 0, true);
wsh.sleep(90 * 1000);
};
// принудительно завершаем работу кассовой программы
if (!error) {// если нету ошибок
command = "taskkill /F /IM ePlus.ARMCasherNew.exe /T";
shell.run(command, 0, true);
wsh.sleep(2 * 1000);
};
};
Второй интересный момент. Как из скрипта работать с графическим файлом? В API драйвера фискального регистратора есть метод для загрузки логотипа и размещения его на каждом печатаемом чеке. Но этот метод ожидает не путь к файлу с логотипом, как это было с файлом прошивки, а мудрёную текстовую строку с данными о цвете каждых восьми пикселов этой картинки. Т.е. картинку нужно как-то прочитать и сделать это стандартными средствами операционной системы, чтобы не устанавливать дополнительное программное обеспечение. И если хорошо поискать, то всё-таки можно найти стандартный ActiveX объект, который умеет это делать. Вот его мы и будем использовать для наших целей.
// добавляем логотип в клише
if (logotype) {// если нужно выполнить
// проверяем наличие файла логотипа
if (!error) {// если нужно выполнить
value = logotype;// получаем значение
value = template(value, { model: model });
value = fso.getAbsolutePathName(value);
if (fso.fileExists(value)) {// если файл существует
logotype = value;
} else error = 15;
};
// получаем данные логотипа
if (!error) {// если нету ошибок
image = new ActiveXObject("WIA.ImageFile");
image.loadFile(logotype);// читаем файл
list = [];// список значений для байтов
for (var y = 0, yLen = 128; y < yLen; y++) {// высота
for (var x = 0, xLen = 512; x < xLen; x++) {// ширина
// вычисляем значение пиксела
if (x < image.width && y < image.height) {// если есть пиксел
value = image.ARGBData(x + y * image.width + 1);
value = -16777216 == value ? 1 : 0;// чёрный цвет
} else value = 0;
// формируем данные 8 пикселов
char = x % 8 ? char : 0;
char += value ? Math.pow(2, x % 8) : 0;
if (7 == x % 8) list.push(dec2hex(char, 2));
};
};
};
// загружаем изображение
if (!error) {// если нету ошибок
driver.LineNumber = 0;
driver.LineDataHex = list.join(" ");
driver.WideLoadLineData();
if (!driver.ResultCode) {// если изображение загружено
} else error = 16;
};
};
В-третьих, нужно предусмотреть возможность менять любой параметр кассы. В графическом интерфейсе тест-драйвер умеет сохранять все настройки таблицы ККМ в файл и загружать их из него, но, к сожалению, в API нет аналогичного метода. Но нечего страшного, файл с настройками — это текстовый файл, изучим его структуру и реализуем загрузку данных из файла самостоятельно. Зато у нас будет стандартный формат файла с настройками, и если будет необходимость, то мы сможем загрузить его вручную через графический интерфейс тест-драйвера.
// добавляем данные в таблицы
if (table) {// если нужно выполнить
// проверяем наличие файла таблиц для импорта
if (!error) {// если нужно выполнить
value = table;// получаем значение
value = template(value, { model: model });
value = fso.getAbsolutePathName(value);
if (fso.fileExists(value)) {// если файл существует
table = value;
} else error = 17;
};
// получаем содержимое файла
if (!error) {// если нету ошибок
stream = fso.openTextFile(table, 1, false, -1);
if (!stream.atEndOfStream) {// если файл не пуст
data = stream.readAll();
} else error = 18;
stream.close();
};
// преобразовываем содержимое в список
if (!error) {// если нету ошибок
list = data.split(dLine);
for (var i = 0, iLen = list.length; i < iLen; i++) {
value = list;// сохраняем значение строки
list = list.split(dCell);// разделяем значения в строке
if (list.length > 3 && value.indexOf("//")) {
value = value.split("','")[1] || "";
value = value.substr(0, value.length - 1);
value = template(value, variable || {});
item = {// элимент данных
table: list[0], // таблица
row: list[1], // ряд
field: list[2], // поле
value: value // значение
};
list = item;
} else list = null;
};
};
// выполняем импорт значений таблиц
if (!error) {// если нету ошибок
for (var i = 0, iLen = list.length; i < iLen; i++) {
item = list;// получаем очередной элимен
// читаем текущее значение в таблице
if (item) {// если не пустая строка таблицы
driver.TableNumber = item.table;
driver.RowNumber = item.row;
driver.FieldNumber = item.field;
driver.GetFieldStruct();
if (!driver.ResultCode) {// если данные получены
driver.ReadTable();// получаем данные
if (!driver.ResultCode) {// если данные получены
if (driver.FieldType) value = driver.ValueOfFieldString;
else value = driver.ValueOfFieldInteger;
if (value != item.value) {// если нужно изменить данные
// изменяем значение в таблицы
if (driver.FieldType) driver.ValueOfFieldString = item.value;
else driver.ValueOfFieldInteger = item.value;
driver.WriteTable();// изменяем данные
};
};
};
};
};
};
};
В-четвёртых, т.к. у нас стоит задача иметь возможность в зависимости от точки продаж загружать различную рекламную информацию, то добавляем ещё один параметр, который указывает на файл с данными для шаблонизатора. Эти данные будут загружаться из файла и постанавливается в шаблонизатор в зависимости от начала имени компьютера, на котором исполняется скрипт. А начало имени компьютера зависит от точки продаж. И уже после шаблонизатора мы будем загружать значение в таблицу ККМ.
Так же в шаблонизатор оборачиваем значения параметров, которые принимает скрипт. Что бы можно было использовать шаблоны в параметрах и в итоге получаем скрипт config.min.js который можно запускать из командной строки и выполнять расширенную настройку ККМ одной командой.
cscript firmware.min.js upd-19018.bin 19018 "ШТРИХ-ЛАЙТ-01Ф"
cscript config.min.js false false variable.tsv %model%.bmp %model%.csv true
Поэтому создаём необходимые задачи в планировщике Windows, экспортируем их в xml. Файлы xml вместе со скриптами упаковываем в установочный файл, например с помощью NSIS. И уже привычным нам способом через GPO, WMI, PowerShell или сторонним программным обеспечением распространяем на нужные нам компьютеры, включая компьютеры, которые будут установлены в будущем.
Использование планировщика для постоянного запуска скриптов
И нам остаётся только с помощью специализированного софта, который централизованно мониторит список установленных программ на компьютерах, периодически посматривать за распространением и покрытием.
Установочный пакет выгодно использовать, чтобы фалы с прошивками и картинками не гонялись при каждом запуске скриптами посети из SYSVOL, а были всегда рядом на локальном компьютере. И выездному инженеру, в случае необходимости, гораздо проще скачать из централизованного репозитория установочный файл, установить его и дальше запускать те задачи в планировщике которые он хочет принудительно выполнить, не дожидаясь их планового запуска.
Тут сразу становиться очевидно, что нужно автоматизировать данную задачу. Количество точек не маленькое и нет гарантий, что через месяц не прилетит аналогичная задача, но уже с новой версией прошивки и придётся делать всё заново. Да и кассы постоянно заменяются на точках и хочется, чтобы они настраивались сами и постоянно.
Хорошо что мы всегда были за унификацию оборудования и на всех точках у нас Штрих-М, но правда четырёх разных моделей. Работать с оборудованием одного производителя всегда проще.
Первым делом, для написания скриптов, разобьём задачу на подзадачи:
- Нужно обновить драйвер фискального регистратора.
- Нужно перепрошить сам фискальный регистратор.
- Нужно перенастроить фискальный регистратор.
Скрипт перепрошивки фискального регистратора
Приводить здесь полный код скрипта не вижу смысла, он опубликован в моём профиле на GitHub, вот прямая ссылка. Давайте рассмотрим самые интересные моменты.Во-первых, как взаимодействовать с ККМ? Тут всё оказалось просто. Драйвер фискального регистратора создаёт ActiveX объект, вот через него мы и будем строить своё взаимодействие. Поэтому на сайте производителя помимо свеженького установочного файла драйвера, нам ещё пригодится документ ШТРИХ-М: Драйвер ККТ А4.15. Руководство программиста. На моё удивление в этом документе всё очень чётко, структурированно и понятно расписано, какие свойства и методы есть у этого объекта, и как их вызывать.
// создаём объект для взаимодействия с кассой
if (!error) {// если нету ошибок
try {// пробуем подключиться к кассе
driver = new ActiveXObject("Addin.DrvFR");
speed = driver.BaudRate;
driver.Password = password;
driver.GetECRStatus();
if (!driver.ResultCode) {// если запрос выполнен
} else error = 2;
} catch (e) { error = 2; };
};
Пару слов, про то, как вызывать эти методы. Производитель реализовал достаточно интересный подход к API. Ты создаёшь экземпляр объекта, у него есть свойства и методы, но методы не принимают параметры, в привычном понимании этого. Вместо этого, ты просто перед вызовом метода у экземпляра объекта задаёшь необходимые свойства. Вызываешь метод без параметров. А затем читаешь значения из нужных тебе свойств. По началу данный подход кажется не привычным, но потом находишь его удобным, т.к. тебе не нужно парится об переменных, в которых хранить результаты выполнения методов. Ты просто всегда можешь обратиться к экземпляру объекта и прочитать нужные свойства.
Кстати, в графическом интерфейсе тест-драйвера при наведении на почти все кнопки и поля выскакивают подсказки с интересными названиями. Так вот, это как раз названия методов и свойств, которые нужно вызвать при программной реализации взаимодействия, для получения аналогичного результата. Такой любезное отношение к разработчикам очень порадовало, и сэкономило мне кучу времени на поиске нужного метода. За что производителю отдельное спасибо.
Второй интересный момент. Как загрузить файл прошивки в ККМ? Оказалась тут есть нюансы. Если в фискальный регистратор установлена обычная SD карта, то просто вызываем нужный метод, загружаем файл на эту карту и другим методом перезагружаем ККМ. При включении ККМ обновится.
// загружаем прошивку на карту память
if (!error && !isUpdated) {// если нужно выполнить
driver.FileType = 1;// прошивка
driver.FileName = image;
driver.LoadFileOnSDCard();
if (!driver.ResultCode) {// если данные получены
} else error = 11;
};
// перезагружаем кассу
if (!error && !isUpdated) {// если нужно выполнить
driver.RebootKKT();
if (!driver.ResultCode) {// если данные получены
} else error = 12;
};
Но если SD карты нет, то нужен другой подход. И он зависит от того, как подключена ККМ к компьютеру. Если через USB, то нужно использовать режим DFU.
// обновляем прошивку через usb
if (!error && !isUpdated) {// если нужно выполнить
driver.UpdateFirmwareMethod = 0;// DFU
driver.FileName = image;
driver.UpdateFirmware();
if (!driver.ResultCode) {// если запрос выполнен
while (1 == driver.UpdateFirmwareStatus) wsh.sleep(timeout);
if (!driver.UpdateFirmwareStatus) isUpdated = true;
};
};
Если ККМ подключена к компьютеру через COM порт, то нужно использовать режим XMODEM.
// обновляем прошивку через com
if (!error && !isUpdated) {// если нужно выполнить
driver.UpdateFirmwareMethod = 1;// XMODEM
driver.FileName = image;
driver.UpdateFirmware();
if (!driver.ResultCode) {// если запрос выполнен
while (1 == driver.UpdateFirmwareStatus) wsh.sleep(timeout);
if (!driver.UpdateFirmwareStatus) isUpdated = true;
} else error = 8;
};
В-третьих, после обновления нужно сделать технологическое обнуление, а перед ним нужно сохранить все настройки ККМ и потом восстановить их. Но тут я решил сделать всё просто, сохранить таблицу значений в многомерный массив и потом восстановить её из этого массива.
Хорошо бы перед прошивкой кассы проверять текущую версию прошивки, чтобы не иметь возможность не прошивать уже прошитые кассы. Так же хорошо бы проверять ещё и модель, на случай разных файлов с прошивками для разных моделей. Ну и так же не нужно прошивать кассу если на ней открыта смена. Добавляем эти проверки необязательными параметрами и в итоге получаем скрипт firmware.min.js который можно запускать из командной строки и выполнять прошивку ККМ одной командой.
cscript firmware.min.js <image> [<build> [<model>]]
- <image> - Путь к файлу с прошивкой кассы.
- <build> - Номер сборки прошивки (если не совпадает, то касса обновляется).
- <model> - Фильтр по модели кассы (если не совпадает, то касса не обновляется).
Скрипт настройки фискального регистратора
Приводить здесь полный код скрипта то же не вижу смысла, он опубликован в моём профиле на GitHub, вот прямая ссылка. Давайте так же рассмотрим самые интересные моменты, тут их то же не мало.Во-первых, нужно предусмотреть возможность уведомления пользователя. Т.к. при подключении ККМ к компьютеру, что по USB, что по COM, c ККМ через драйвер может взаимодействовать только одна программа. И если точка работает круглосуточно, то в тихом режиме такую ККМ мы никогда не перенастроим.
Но как сообщить вошедшему пользователю, что нужно сделать трёхминутный перерыв? Ведь скрипт исполняется в контексте другого административного пользователя или в моём случае от имени системы. И показывать какие-то сообщения бесполезно, другой пользователь их не увидит. Тут я решил использовать простой и давно проверенной мной способ, вызываем через shutdown отложенную перезагрузку и сообщением, а затем отменяем её. Если вы знаете более интересные способы, напишите пожалуйста в комментариях, я думаю они всем пригодятся.
// прерываем работу пользователя
if (!silent) {// если можно прервать работу пользователя
// показываем начальное сообщение пользователю
if (!error) {// если нету ошибок
value = // сообщение для пользователя
"Через 2 минуты на компьютер будет установлено обновление для ККМ. " +
"Нужно будет закрыть кассу программы еФарма. Закрывать смену при этом не нужно. " +
"Установка займёт 3 минуты. После этого вы сможете работать.";
command = 'shutdown /r /t 60 /c "' + value + '"';
shell.run(command, 0, false);
wsh.sleep(30 * 1000);
command = "shutdown /a";
shell.run(command, 0, true);
wsh.sleep(90 * 1000);
};
// принудительно завершаем работу кассовой программы
if (!error) {// если нету ошибок
command = "taskkill /F /IM ePlus.ARMCasherNew.exe /T";
shell.run(command, 0, true);
wsh.sleep(2 * 1000);
};
};
Второй интересный момент. Как из скрипта работать с графическим файлом? В API драйвера фискального регистратора есть метод для загрузки логотипа и размещения его на каждом печатаемом чеке. Но этот метод ожидает не путь к файлу с логотипом, как это было с файлом прошивки, а мудрёную текстовую строку с данными о цвете каждых восьми пикселов этой картинки. Т.е. картинку нужно как-то прочитать и сделать это стандартными средствами операционной системы, чтобы не устанавливать дополнительное программное обеспечение. И если хорошо поискать, то всё-таки можно найти стандартный ActiveX объект, который умеет это делать. Вот его мы и будем использовать для наших целей.
// добавляем логотип в клише
if (logotype) {// если нужно выполнить
// проверяем наличие файла логотипа
if (!error) {// если нужно выполнить
value = logotype;// получаем значение
value = template(value, { model: model });
value = fso.getAbsolutePathName(value);
if (fso.fileExists(value)) {// если файл существует
logotype = value;
} else error = 15;
};
// получаем данные логотипа
if (!error) {// если нету ошибок
image = new ActiveXObject("WIA.ImageFile");
image.loadFile(logotype);// читаем файл
list = [];// список значений для байтов
for (var y = 0, yLen = 128; y < yLen; y++) {// высота
for (var x = 0, xLen = 512; x < xLen; x++) {// ширина
// вычисляем значение пиксела
if (x < image.width && y < image.height) {// если есть пиксел
value = image.ARGBData(x + y * image.width + 1);
value = -16777216 == value ? 1 : 0;// чёрный цвет
} else value = 0;
// формируем данные 8 пикселов
char = x % 8 ? char : 0;
char += value ? Math.pow(2, x % 8) : 0;
if (7 == x % 8) list.push(dec2hex(char, 2));
};
};
};
// загружаем изображение
if (!error) {// если нету ошибок
driver.LineNumber = 0;
driver.LineDataHex = list.join(" ");
driver.WideLoadLineData();
if (!driver.ResultCode) {// если изображение загружено
} else error = 16;
};
};
В-третьих, нужно предусмотреть возможность менять любой параметр кассы. В графическом интерфейсе тест-драйвер умеет сохранять все настройки таблицы ККМ в файл и загружать их из него, но, к сожалению, в API нет аналогичного метода. Но нечего страшного, файл с настройками — это текстовый файл, изучим его структуру и реализуем загрузку данных из файла самостоятельно. Зато у нас будет стандартный формат файла с настройками, и если будет необходимость, то мы сможем загрузить его вручную через графический интерфейс тест-драйвера.
// добавляем данные в таблицы
if (table) {// если нужно выполнить
// проверяем наличие файла таблиц для импорта
if (!error) {// если нужно выполнить
value = table;// получаем значение
value = template(value, { model: model });
value = fso.getAbsolutePathName(value);
if (fso.fileExists(value)) {// если файл существует
table = value;
} else error = 17;
};
// получаем содержимое файла
if (!error) {// если нету ошибок
stream = fso.openTextFile(table, 1, false, -1);
if (!stream.atEndOfStream) {// если файл не пуст
data = stream.readAll();
} else error = 18;
stream.close();
};
// преобразовываем содержимое в список
if (!error) {// если нету ошибок
list = data.split(dLine);
for (var i = 0, iLen = list.length; i < iLen; i++) {
value = list;// сохраняем значение строки
list = list.split(dCell);// разделяем значения в строке
if (list.length > 3 && value.indexOf("//")) {
value = value.split("','")[1] || "";
value = value.substr(0, value.length - 1);
value = template(value, variable || {});
item = {// элимент данных
table: list[0], // таблица
row: list[1], // ряд
field: list[2], // поле
value: value // значение
};
list = item;
} else list = null;
};
};
// выполняем импорт значений таблиц
if (!error) {// если нету ошибок
for (var i = 0, iLen = list.length; i < iLen; i++) {
item = list;// получаем очередной элимен
// читаем текущее значение в таблице
if (item) {// если не пустая строка таблицы
driver.TableNumber = item.table;
driver.RowNumber = item.row;
driver.FieldNumber = item.field;
driver.GetFieldStruct();
if (!driver.ResultCode) {// если данные получены
driver.ReadTable();// получаем данные
if (!driver.ResultCode) {// если данные получены
if (driver.FieldType) value = driver.ValueOfFieldString;
else value = driver.ValueOfFieldInteger;
if (value != item.value) {// если нужно изменить данные
// изменяем значение в таблицы
if (driver.FieldType) driver.ValueOfFieldString = item.value;
else driver.ValueOfFieldInteger = item.value;
driver.WriteTable();// изменяем данные
};
};
};
};
};
};
};
В-четвёртых, т.к. у нас стоит задача иметь возможность в зависимости от точки продаж загружать различную рекламную информацию, то добавляем ещё один параметр, который указывает на файл с данными для шаблонизатора. Эти данные будут загружаться из файла и постанавливается в шаблонизатор в зависимости от начала имени компьютера, на котором исполняется скрипт. А начало имени компьютера зависит от точки продаж. И уже после шаблонизатора мы будем загружать значение в таблицу ККМ.
Так же в шаблонизатор оборачиваем значения параметров, которые принимает скрипт. Что бы можно было использовать шаблоны в параметрах и в итоге получаем скрипт config.min.js который можно запускать из командной строки и выполнять расширенную настройку ККМ одной командой.
cscript config.min.js <install> <license> <variable> <logotype> <table> <silent>
- <install> - Путь к файлу установки драйвера или false для пропуска.
- <license> - Шаблон пути к файлу лицензий для касс или false для пропуска.
- <variable> - Шаблон пути к файлу с переменными или false для пропуска.
- <logotype> - Шаблон пути к BMP файлу логотипа для печати вверху чека.
- <table> - Шаблон пути к файлу таблиц для импорта в формате Штрих-М.
- <silent> - Выполнять тихую установку без остановки работы пользователя.
Использование скриптов
С самого начала я планировал использовать эти скрипты в планировщике Windows. Что бы они несколько раз в день проверяли прошивку и настройки, и при необходимости, перенастраивали и прошивали ККМ. Поэтому в скрипте firmware.min.js есть проверка на версию установленной прошивки, а в скрипте config.min.js изменение вносятся в ячейку таблицы, только если её текущее значение не соответствует нужному. За счёт этого, многократное исполнение скриптов не создаёт постоянной перепрошивки ККМ и перезаписи её настроек.cscript firmware.min.js upd-19018.bin 19018 "ШТРИХ-ЛАЙТ-01Ф"
cscript config.min.js false false variable.tsv %model%.bmp %model%.csv true
Поэтому создаём необходимые задачи в планировщике Windows, экспортируем их в xml. Файлы xml вместе со скриптами упаковываем в установочный файл, например с помощью NSIS. И уже привычным нам способом через GPO, WMI, PowerShell или сторонним программным обеспечением распространяем на нужные нам компьютеры, включая компьютеры, которые будут установлены в будущем.
И нам остаётся только с помощью специализированного софта, который централизованно мониторит список установленных программ на компьютерах, периодически посматривать за распространением и покрытием.
Установочный пакет выгодно использовать, чтобы фалы с прошивками и картинками не гонялись при каждом запуске скриптами посети из SYSVOL, а были всегда рядом на локальном компьютере. И выездному инженеру, в случае необходимости, гораздо проще скачать из централизованного репозитория установочный файл, установить его и дальше запускать те задачи в планировщике которые он хочет принудительно выполнить, не дожидаясь их планового запуска.
Делаем автоматическую прошивку и настройку касс в 350 точек продаж
И так представьте, одним прекрасным днём к вам, как к системному администратору, поступает задача. За пару дней обновить все фискальные регистраторы во всех точках продаж, т.к....
habr.com