При работе с маркированными товарами в 1С 7.7 многие сталкиваются с проблемой: код маркировки (КМ) не передается в ОФД, хотя в коде 1С вроде бы все прописано. Часто при попытке отправить КМ напрямую через тест-драйвер ККТ возникает ошибка "115: команда не поддерживается в данном режиме". Разберем, почему это происходит и как исправить обработку печати чека для корректной передачи данных о маркировке.
Проанализируем ситуацию на примере стандартной обработки для фискальных регистраторов "ШТРИХ-М", но принципы будут схожи и для других моделей ККТ.
Основная причина, по которой код маркировки не передается, — использование устаревших методов драйвера ККТ для регистрации товарных позиций в чеке. В старых обработках часто можно встретить такой код:
Если ПризнВозврата = 0 Тогда
Объект.Sale();
Иначе
Объект.ReturnSale();
КонецЕсли;
Методы Sale() и ReturnSale() были разработаны до введения обязательной маркировки и не поддерживают передачу тега 1162 ("Код товара"), который и содержит данные о коде маркировки. Для работы с маркировкой необходимо полностью переписать логику регистрации позиций, используя современные методы, предусмотренные производителем драйвера.
Вторая ключевая ошибка — неправильный порядок вызова команд. Ошибка "115: команда не поддерживается в данном режиме" прямо указывает на то, что ККТ находится в неверном состоянии для выполнения запрошенной операции. Нельзя просто так отправить код маркировки. Фискальный накопитель (ФН) ожидает, что КМ будет привязан к конкретной товарной позиции в чеке.
Неправильная последовательность:
FNSendItemCodeData).Sale или FNOperation).Правильная последовательность:
FNOperation).FNSendItemCodeData).Как указано в документации к драйверам "ШТРИХ-М": метод FNSendItemCodeData должен вызываться только после метода FNOperation.
Рассмотрим, как переписать функцию печати чека для корректной работы с маркировкой.
Вместо того чтобы вызывать Sale() или ReturnSale() в цикле для каждого товара, нам нужно в самом начале один раз открыть чек нужного типа. Для этого полностью удаляем старую конструкцию с Sale()/ReturnSale().
В начале функции ПечататьЧек добавляем следующий код:
// Определяем тип чека: «0» - продажа, «2» - возврат продажи.
Если ПризнВозврата = 0 Тогда
Объект.CheckType = 0;
Иначе
Объект.CheckType = 2;
КонецЕсли;
// Открываем чек на ККТ
рез = Объект.OpenCheck();
Если рез <> 0 Тогда
Сообщить("Ошибка открытия нового чека: " + Объект.ResultCodeDescription);
// Здесь должна быть логика отмены операции
Возврат 0;
КонецЕсли;
Теперь внутри цикла по товарам (Пока СписокТоваров.ПолучитьСтроку() = 1 Цикл) мы будем использовать новую логику.
1. Заполняем данные о товаре. Как и раньше, устанавливаем свойства объекта драйвера: Price, Quantity, StringForPrinting, Tax1 и другие.
2. Регистрируем позицию методом FNOperation(). Этот метод отправляет в ФН все данные о товаре, которые мы установили на предыдущем шаге.
3. Отправляем код маркировки методом FNSendItemCodeData(). Сразу после успешной регистрации позиции проверяем, есть ли для нее код маркировки. Если есть, подготавливаем и отправляем его.
Посмотрим на пример кода внутри цикла:
Пока СписокТоваров.ПолучитьСтроку() = 1 Цикл
// ... Установка обычных свойств товара: Цена, Количество, Наименование, НДС ...
Объект.Price = СписокТоваров.Цена;
Объект.Quantity = СписокТоваров.Количество;
Объект.StringForPrinting = СписокТоваров.ТовНаим;
// ... и так далее
// 1. Регистрируем товарную позицию в чеке
Объект.FNOperation();
Если Объект.ResultCode <> 0 Тогда
ОписаниеРезультата = ПолучитьОписаниеРезультата(Объект);
АннулированиеЧека(Объект, Пароль);
Сообщить("Ошибка при регистрации позиции: " + ОписаниеРезультата);
Возврат 0;
КонецЕсли;
// 2. СРАЗУ ПОСЛЕ FNOperation() отправляем код маркировки, если он есть
Если ПустоеЗначение(СокрЛП(СписокТоваров.Маркировка)) = 0 Тогда
КМ = СокрЛП(СписокТоваров.Маркировка);
// Разбираем полный код маркировки на составляющие
// ВАЖНО: структура кода может отличаться для разных товарных групп.
// Этот пример для DataMatrix (GS1)
GTIN = Сред(КМ, 3, 14);
SerialNumber = Сред(КМ, 19, 13);
// Устанавливаем свойства для отправки тега 1162
Объект.MarkingType = 17485; // Это шестнадцатеричное "444D" в десятичном виде
Объект.GTIN = GTIN;
Объект.SerialNumber = SerialNumber;
// Отправляем код маркировки
Объект.FNSendItemCodeData();
Если Объект.ResultCode <> 0 Тогда
// Обработка ошибки отправки КМ
КонецЕсли;
КонецЕсли;
КонецЦикла;
После того как все товары обработаны в цикле, необходимо завершить чек: передать данные об оплате и закрыть его.
// ... код после цикла по товарам ...
// Передаем сумму оплаты
Объект.Summ1 = ПолученоНаличными;
Объект.Summ2 = ПолученоБезнал;
// ... и т.д. для других видов оплат
// Закрываем фискальный чек
Объект.FNCloseCheckEx(); // Рекомендуемый метод
// или Объект.CloseCheck();
Если Объект.ResultCode <> 0 Тогда
ОписаниеРезультата = ПолучитьОписаниеРезультата(Объект);
АннулированиеЧека(Объект, Пароль);
Сообщить("Ошибка при закрытии чека: " + ОписаниеРезультата);
Возврат 0;
КонецЕсли;
Метод FNCloseCheckEx() является более современным аналогом CloseCheck() и предпочтителен при работе с ФФД 1.2, но в большинстве случаев CloseCheck() также сработает.
Ниже приведен обобщенный пример, демонстрирующий полную структуру функции с учетом всех изменений. Обратите внимание: этот код — примерная структура. Вам нужно будет адаптировать его под свою конфигурацию (названия переменных, получение данных и т.д.).
Функция ПечататьЧекСМаркировкой(Объект, Пароль, СписокТоваров, Получено, ПризнВозврата)
// Шаг 1: Открытие чека
Если ПризнВозврата = 0 Тогда
Объект.CheckType = 0; // Продажа
Иначе
Объект.CheckType = 2; // Возврат продажи
КонецЕсли;
рез = Объект.OpenCheck();
Если рез <> 0 Тогда
Сообщить("Ошибка открытия чека: " + Объект.ResultCodeDescription);
Возврат 0;
КонецЕсли;
// Шаг 2: Цикл по товарам
СписокТоваров.ВыбратьСтроки();
Пока СписокТоваров.ПолучитьСтроку() = 1 Цикл
// Устанавливаем параметры товара
Объект.Password = Пароль;
Объект.StringForPrinting = Лев(СписокТоваров.ТовНаим, 48);
Объект.Price = СписокТоваров.Цена;
Объект.Quantity = СписокТоваров.Количество;
Объект.Department = 1;
// ... настройка НДС (Tax1, Tax2...)
// Регистрируем позицию
Объект.FNOperation();
Если Объект.ResultCode <> 0 Тогда
// обработка ошибки
Возврат 0;
КонецЕсли;
// Отправляем код маркировки ПОСЛЕ FNOperation
Если ПустоеЗначение(СокрЛП(СписокТоваров.Маркировка)) = 0 Тогда
КМ = СокрЛП(СписокТоваров.Маркировка);
GTIN = Сред(КМ, 3, 14);
SerialNumber = Сред(КМ, 19, 13);
Объект.MarkingType = 17485;
Объект.GTIN = GTIN;
Объект.SerialNumber = SerialNumber;
Объект.FNSendItemCodeData();
КонецЕсли;
КонецЦикла;
// Шаг 3: Закрытие чека
Объект.Password = Пароль;
Объект.Summ1 = Получено; // Пример для наличной оплаты
Объект.Summ2 = 0;
Объект.Summ3 = 0;
Объект.Summ4 = 0;
Объект.FNCloseCheckEx();
Объект.CloseCheck(); // В некоторых драйверах может требоваться и старый метод
Если Объект.ResultCode <> 0 Тогда
// обработка ошибки
Возврат 0;
КонецЕсли;
Возврат 1; // Успех
КонецФункции
Сред(КМ, 3, 14) и Сред(КМ, 19, 13) является типовым, но может потребовать корректировки.Переход на новую схему работы с ККТ — ключевой шаг для корректной передачи кодов маркировки. Следуя описанному алгоритму, вы сможете успешно доработать вашу систему на платформе 1С 7.7.