При работе с торговым оборудованием АТОЛ через старые версии драйверов (в частности, DTO 8) программисты часто сталкиваются с непонятными ошибками, описание которых отсутствует в стандартных руководствах. Одной из таких проблем является ошибка -3879 (неверный номер конечной зоны), возникающая в момент вызова метода CloseCheck(). В этой статье мы подробно разберем, почему ККТ начинает требовать какие-то «зоны», откуда берется этот режим и как правильно модифицировать код 1С, чтобы чек пробивался корректно.
Проанализируем природу данной ошибки. В ККТ АТОЛ существует так называемый «билетный режим» (или транспортный режим). Он предназначен для использования в автобусах или при продаже билетов на мероприятия, где стоимость позиции зависит от тарифных зон (начальной и конечной). В обычном ритейле этот функционал не используется.
Рассмотрим ситуацию, почему обычный фискальный регистратор (например, АТОЛ 22ПТК) вдруг выдает такую ошибку. Основная причина кроется в использовании Драйвера ККТ версии 8 на современных прошивках касс (Платформа 5.0). Происходит следующее:
BeginItem() и EndItem(), данные в памяти объекта могут накладываться друг на друга.CloseCheck() касса сообщает, что данные для «конечной зоны» переданы неверно или отсутствуют.Проанализируем пример кода, представленный в обсуждении. В рабочем варианте автор использовал метод Registration(). Это высокоуровневый метод, который за один вызов регистрирует позицию с базовыми параметрами. Однако для реализации сложных схем оплаты (аванс, кредит, оплата кредита) программисты часто переходят на связку BeginItem() / EndItem().
Посмотрим на проблемный участок кода:
Объект.BeginItem();
Объект.Department = 1;
Объект.Name = СтрокаТаблицыТоваров.Наименование;
Объект.Quantity = СтрокаТаблицыТоваров.Количество;
Объект.Price = СтрокаТаблицыТоваров.Цена;
Объект.Summ = СтрокаТаблицыТоваров.Сумма;
// Настройка налогов
Объект.TaxMode = 0;
Объект.TaxTypeNumber = 3; // НДС 20%
Объект.TaxSumm = СтрокаТаблицыТоваров.СуммаНДС;
Объект.EndItem();
При использовании BeginItem() в DTO8 объект драйвера становится крайне чувствительным к «мусору» в свойствах. Если до этого в рамках сессии или предыдущего чека использовались другие параметры, они могут «выстрелить» в текущей позиции. В частности, свойства FirstZone и LastZone могут получить случайные значения, что и инициирует билетный режим.
Если нет возможности немедленно перейти на новый драйвер (версии 10), попробуем исправить ситуацию «малой кровью». Разберем, как очистить свойства объекта перед регистрацией каждой позиции. Добавьте явное зануление зон и проверку состояния чека.
Рассмотрим модифицированный цикл регистрации позиций:
Для Каждого СтрокаТаблицыТоваров Из ТаблицаТоваров Цикл
// Сброс параметров позиции (важно для DTO8)
Объект.NewItem(); // Если метод поддерживается драйвером
// Если NewItem нет, принудительно ставим зоны в значение по умолчанию
Попытка
Объект.FirstZone = 0;
Объект.LastZone = 0;
Исключение
// Игнорируем, если свойства недоступны
КонецПопытки;
Объект.BeginItem();
Объект.Name = СтрокаТаблицыТоваров.Наименование;
Объект.Quantity = СтрокаТаблицыТоваров.Количество;
Объект.Price = СтрокаТаблицыТоваров.Цена;
// Работа с налогами
// Важно: на новых прошивках лучше использовать TaxTypeNumber
// и позволять ККТ самой рассчитывать налог, если это не противоречит учету
Объект.TaxTypeNumber = 3;
Объект.EndItem();
КонецЦикла;
Выясним, не включен ли билетный режим в самой кассе на уровне настроек. Иногда после сбоев или некорректных команд в энергонезависимой памяти ККТ (NVRAM) может установиться флаг режима билетов. Выполним следующие шаги:
Проанализируем самый надежный способ решения проблемы. Драйвер 8-й версии официально признан устаревшим и не поддерживает современные требования Платформы 5.0 и ФФД 1.2. Ошибка «неверный номер зоны» — это лишь один из симптомов несовместимости протоколов.
В 10-й версии драйвера (DTO10) архитектура полностью изменена. Вместо установки свойств объекта (Объект.Property = Value) используется передача параметров через методы. Это исключает появление «фантомных» данных в памяти. Посмотрим, как выглядит современный подход к печати чека в 1С:
// Пример логики на Драйвере 10
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_REPORT_TYPE, Драйвер.LIBFPTR_RT_LAST_CHECK_COPY);
// Регистрация позиции
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_COMMODITY_NAME, "Товар 1");
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_PRICE, 100);
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_QUANTITY, 1);
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_TAX_TYPE, Драйвер.LIBFPTR_TAX_VAT20);
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_ITEM_TYPE, Драйвер.LIBFPTR_RE_COMMODITY); // Признак предмета расчета
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_PAYMENT_MODE, Драйвер.LIBFPTR_PM_FULL_PAYMENT); // Признак способа расчета
Драйвер.registration();
// Закрытие чека
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_PAYMENT_TYPE, Драйвер.LIBFPTR_PT_CASH);
Драйвер.setParam(Драйвер.LIBFPTR_PARAM_PAYMENT_SUM, 100);
Драйвер.payment();
Драйвер.closeCheck();
Переход на 10-й драйвер полностью устраняет ошибки, связанные с «зонами», так как в объектной модели DTO10 билетные параметры вынесены в отдельные константы и никогда не передаются случайно.
Разберем еще несколько критических моментов, которые могут вызывать сбои в методе CloseCheck(). Проверьте ваш код на наличие следующих атрибутов:
AttrNumber = 1021 и WriteAttribute(). Важно передавать его до открытия чека или сразу после OpenCheck().TaxSumm. На Платформе 5.0 это часто приводит к конфликтам округления. Рекомендуется передавать только TaxTypeNumber, позволяя кассе самой рассчитать налог от суммы позиции.Важное резюме: Ошибка -3879 — это типичный «глюк» обратной совместимости. Если вы вынуждены остаться на 8-м драйвере, используйте метод Registration() вместо BeginItem() там, где это возможно, и всегда вызывайте методы очистки состояния драйвера перед началом формирования чека. Но лучшим решением будет обновление кода под современные стандарты АТОЛ DTO 10.