Почему не уходит код маркировки из 1С 7.7 в ОФД и как это исправить?

Программист 1С v7.7 Торговля и дистрибуция
← На главную

При работе с маркированными товарами в 1С 7.7 многие сталкиваются с проблемой: код маркировки (КМ) не передается в ОФД, хотя в коде 1С вроде бы все прописано. Часто при попытке отправить КМ напрямую через тест-драйвер ККТ возникает ошибка "115: команда не поддерживается в данном режиме". Разберем, почему это происходит и как исправить обработку печати чека для корректной передачи данных о маркировке.

Проанализируем ситуацию на примере стандартной обработки для фискальных регистраторов "ШТРИХ-М", но принципы будут схожи и для других моделей ККТ.

Причина №1: Использование устаревших методов регистрации товаров

Основная причина, по которой код маркировки не передается, — использование устаревших методов драйвера ККТ для регистрации товарных позиций в чеке. В старых обработках часто можно встретить такой код:


Если ПризнВозврата = 0 Тогда
    Объект.Sale();
Иначе
    Объект.ReturnSale();
КонецЕсли;

Методы Sale() и ReturnSale() были разработаны до введения обязательной маркировки и не поддерживают передачу тега 1162 ("Код товара"), который и содержит данные о коде маркировки. Для работы с маркировкой необходимо полностью переписать логику регистрации позиций, используя современные методы, предусмотренные производителем драйвера.

Причина №2: Неверная последовательность вызова команд

Вторая ключевая ошибка — неправильный порядок вызова команд. Ошибка "115: команда не поддерживается в данном режиме" прямо указывает на то, что ККТ находится в неверном состоянии для выполнения запрошенной операции. Нельзя просто так отправить код маркировки. Фискальный накопитель (ФН) ожидает, что КМ будет привязан к конкретной товарной позиции в чеке.

Неправильная последовательность:

  1. Отправить код маркировки (FNSendItemCodeData).
  2. Зарегистрировать товар (например, через Sale или FNOperation).

Правильная последовательность:

  1. Открыть чек.
  2. Заполнить все данные по товарной позиции (наименование, цена, количество, НДС и т.д.).
  3. Зарегистрировать товарную позицию в ФН (метод FNOperation).
  4. Сразу после регистрации позиции отправить связанный с ней код маркировки (метод FNSendItemCodeData).
  5. Повторить пункты 2-4 для всех товаров в чеке.
  6. Закрыть чек.

Как указано в документации к драйверам "ШТРИХ-М": метод FNSendItemCodeData должен вызываться только после метода FNOperation.

Пошаговая инструкция по доработке обработки печати

Рассмотрим, как переписать функцию печати чека для корректной работы с маркировкой.

Шаг 1. Заменяем открытие чека

Вместо того чтобы вызывать Sale() или ReturnSale() в цикле для каждого товара, нам нужно в самом начале один раз открыть чек нужного типа. Для этого полностью удаляем старую конструкцию с Sale()/ReturnSale().

В начале функции ПечататьЧек добавляем следующий код:


// Определяем тип чека: «0» - продажа, «2» - возврат продажи.
Если ПризнВозврата = 0 Тогда
    Объект.CheckType = 0;
Иначе
    Объект.CheckType = 2;
КонецЕсли;

// Открываем чек на ККТ
рез = Объект.OpenCheck();
Если рез <> 0 Тогда
    Сообщить("Ошибка открытия нового чека: " + Объект.ResultCodeDescription);
    // Здесь должна быть логика отмены операции
    Возврат 0;
КонецЕсли;

Шаг 2. Модифицируем цикл регистрации товаров

Теперь внутри цикла по товарам (Пока СписокТоваров.ПолучитьСтроку() = 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 Тогда
            // Обработка ошибки отправки КМ
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Шаг 3. Завершаем печать чека

После того как все товары обработаны в цикле, необходимо завершить чек: передать данные об оплате и закрыть его.


// ... код после цикла по товарам ...

// Передаем сумму оплаты
Объект.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; // Успех
КонецФункции

Важные моменты

Переход на новую схему работы с ККТ — ключевой шаг для корректной передачи кодов маркировки. Следуя описанному алгоритму, вы сможете успешно доработать вашу систему на платформе 1С 7.7.

← На главную