При использовании большого парка сетевых фискальных регистраторов (например, АТОЛ 22Ф), подключенных по локальной сети через интерфейс Ethernet или Wi-Fi, администраторы и разработчики часто сталкиваются с аппаратным дрейфом встроенных часов реального времени (RTC). Со временем расхождение между реальным астрономическим временем сервера и кассы может составлять несколько минут.
Согласно требованиям законодательства и фискальным регламентам, отклонение времени на кассовом аппарате от реального не должно превышать 5 минут. В старых версиях интеграционной компоненты Библиотеки подключаемого оборудования (БПО) встроенный метод установки времени может отсутствовать. В таком случае задачу можно решить прямым обращением к драйверу ККТ или средствами сетевых настроек самого устройства.
Разберем детально, как выполнить программную синхронизацию времени по TCP/IP, какие ограничения необходимо соблюдать и как избежать типичных ошибок при написании кода.
Прежде чем отправлять команды корректировки времени в кассовый аппарат, проанализируем критические аппаратные и фискальные требования:
Рассмотрим прямое подключение к сетевой кассе через COM-объект AddIn.FPrnM45. Создадим экземпляр драйвера, укажем сетевые реквизиты кассы, проверим статус смены и скорректируем время.
Обратим внимание на частую ошибку: нельзя вызывать функцию ТекущаяДата() раздельно для каждого параметра (часы, минуты, секунды). Если выполнение кода совпадет со сменой минуты или часа (например, на стыке 12:59:59), касса получит некорректное время. Сначала сохраняем время в одну переменную, а затем разбираем ее на составляющие.
Посмотрим на пример правильной реализации:
// Создаем экземпляр драйвера ККМ АТОЛ
ECR = Новый COMОбъект("AddIn.FPrnM45");
// Настраиваем сетевое подключение
ECR.АдресХоста = "10.51.7.59:5555";
ECR.НомерПорта = 99; // Номер порта для сетевого соединения
// Занимаем порт устройства
ECR.DeviceEnabled = 1;
Если ECR.ResultCode <> 0 Тогда
Сообщить("Ошибка подключения к ККМ: " + ECR.ResultDescription);
Возврат;
КонецЕсли;
// Считываем текущее состояние кассы
Если ECR.GetStatus() <> 0 Тогда
Сообщить("Не удалось получить статус ККМ: " + ECR.ResultDescription);
ECR.DeviceEnabled = 0;
Возврат;
КонецЕсли;
// Проверяем, закрыта ли смена
Если ECR.SessionOpened = 0 Тогда
// Фиксируем точное время в единую переменную
ВремяСинхронизации = ТекущаяДата();
ECR.Час = Час(ВремяСинхронизации);
ECR.Минута = Минута(ВремяСинхронизации);
ECR.Секунда = Секунда(ВремяСинхронизации);
// Записываем время в ККТ
Если ECR.SetTime() <> 0 Тогда
Сообщить("Ошибка установки времени: " + ECR.ResultDescription);
Иначе
Сообщить("Время на ККМ успешно синхронизировано.");
КонецЕсли;
Иначе
Сообщить("Смена открыта, корректировка времени невозможна!");
КонецЕсли;
// Обязательно освобождаем порт
ECR.DeviceEnabled = 0;
Если на рабочих местах используется современная 10-я версия драйверов (ДТО 10), работа с объектом выполняется через Native API или COM-объект AddIn.Fptr10. Метод writeDateTime() позволяет одновременно передать полную дату и время.
Разберем по шагам вызов через ДТО 10:
Драйвер = Новый COMОбъект("AddIn.Fptr10");
// Устанавливаем параметры сетевого соединения
Драйвер.setSingleSetting(Драйвер.LIBFPTR_SETTING_MODEL, Строка(Драйвер.LIBFPTR_MODEL_ATOL_AUTO));
Драйвер.setSingleSetting(Драйвер.LIBFPTR_SETTING_PORT, Строка(Драйвер.LIBFPTR_PORT_TCPIP));
Драйвер.setSingleSetting(Драйвер.LIBFPTR_SETTING_IPADDRESS, "10.51.7.59");
Драйвер.setSingleSetting(Драйвер.LIBFPTR_SETTING_IPPORT, "5555");
Драйвер.applySingleSettings();
Если Драйвер.open() <> 0 Тогда
Сообщить("Не удалось установить связь с ККТ: " + Драйвер.errorDescription());
Возврат;
КонецЕсли;
// Проверяем состояние смены
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_DATA_TYPE, Драйвер.LIBFPTR_DT_STATUS);
Драйвер.queryData();
СостояниеСмены = Драйвер.getParamInt(Драйвер.LIBFPTR_PARAM_SHIFT_STATE);
// Значение 0 соответствует закрытой смене (LIBFPTR_SS_CLOSED)
Если СостояниеСмены = Драйвер.LIBFPTR_SS_CLOSED Тогда
// Передаем текущую дату и время
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_DATE_TIME, ТекущаяДата());
Если Драйвер.writeDateTime() <> 0 Тогда
Сообщить("Ошибка при записи времени: " + Драйвер.errorDescription());
Иначе
Сообщить("Время успешно установлено.");
КонецЕсли;
Иначе
Сообщить("Смена не закрыта. Синхронизация отменена.");
КонецЕсли;
// Закрываем соединение
Драйвер.close();
Для сетевых касс АТОЛ на современных прошивках (Платформа 5.0) наиболее надежным решением является использование встроенного NTP-клиента.
В этом случае фискальный регистратор будет самостоятельно корректировать время встроенного таймера в фоновом режиме в моменты, когда кассовая смена закрыта.
Если в инфраструктуре задействовано несколько десятков касс, выполнять синхронизацию вручную кассирами перед открытием смены нерационально. Оптимальный подход — настроить регламентное задание 1С, которое запускается ночью (например, в 03:00, когда торговые точки закрыты):
ПодключаемоеОборудование.