Как настроить ФФД 1.2 в 1С:УТ 10.3 для корректной работы с маркировкой обуви и текстиля?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При переходе на формат фискальных данных (ФФД) 1.2 для работы с маркированными товарами в 1С:Управление торговлей 10.3, многие пользователи сталкиваются с проблемой некорректной передачи информации о маркировке в систему «Честный ЗНАК» (ЧЗ). Чаще всего, чеки фискализируются и уходят в налоговую, но данные о выбытии маркированного товара не достигают ЧЗ, и на бумажном чеке отсутствует обязательная буква «М», «М+» или «М-». Давайте подробно разберем, почему это происходит, и как мы можем исправить ситуацию, модифицировав конфигурацию 1С и обработку обслуживания контрольно-кассовой техники (ККТ).

Основные проблемы, возникающие при переходе на ФФД 1.2 в 1С:УТ 10.3

Прежде чем перейти к решению, рассмотрим основные сложности, с которыми сталкиваются пользователи:

  1. Недоработки в типовой конфигурации 1С:УТ 10.3: Изначально УТ 10.3 не была полностью адаптирована под все требования ФФД 1.2. Обновления 1С, предназначенные для поддержки ФФД 1.2, могут быть неполными или содержать ошибки, из-за чего механизм передачи данных в ЧЗ работает некорректно.
  2. Отсутствие полного цикла проверки марки на ККТ: Согласно требованиям ФФД 1.2, ККТ должна выполнять несколько шагов по проверке и подтверждению кода маркировки перед фискализацией чека:
    • RequestKM (запрос кода маркировки).
    • GetProcessingResult (получение результатов проверки).
    • ConfirmKM (подтверждение кода маркировки для выбытия).
    • Fiscalization (фискализация чека).

    В типовой УТ 10.3 часто отсутствует или некорректно реализована логика выполнения первых трех команд, передается только команда фискализации с усеченным или неправильно сформированным кодом маркировки.

  3. Некорректное формирование XML-пакета для ККТ: Система может передавать в ККТ XML-пакет с данными о товаре, где код маркировки либо отсутствует, либо представлен в неверном формате (например, без криптохвоста, со скобками, или без специальных символов-разделителей GS1). Обязательным требованием является передача полного кода маркировки в формате Base64, содержащего все необходимые символы, включая символы-разделители GS1 (FNC1, ASCII 29).
  4. Проблемы с обработкой обслуживания ККТ: Обработки обслуживания ККТ (например, AtolKkt.epf или ShtrihMkkt.epf) могут содержать устаревшие компоненты или не реализовывать новые методы, необходимые для ФФД 1.2.
  5. Отсутствие символа «М» на чеке и в ЧЗ: Если проверка марки не проходит или данные передаются некорректно, на чеке не печатается «М», «М+» или «М-», и товар не выбывает из оборота в ЧЗ.

Общие принципы работы ФФД 1.2 с маркировкой

Для понимания дальнейших шагов, вспомним ключевые особенности ФФД 1.2 при работе с маркированными товарами:

  1. Обязательность ФФД 1.2: Для маркированных товаров (обувь, текстиль) использование ФФД 1.2 обязательно с 6 августа 2021 года, включая режимы загрузки ККМ off-line.
  2. Взаимодействие ККТ с Честным ЗНАКОМ: Основное отличие ФФД 1.2 — прямое взаимодействие ККТ с системой ЧЗ через Оператора фискальных данных (ОФД). При продаже касса отправляет запросы на проверку маркировки и уведомления о реализации.
  3. Полный код маркировки: В фискальных документах (запрос о коде маркировки, уведомление о реализации) необходимо передавать полный код маркировки с криптохвостом. Он включает GTIN, серийный номер, ключ проверки и код проверки, а также символы-разделители GS1. Хранение криптохвоста в базе данных 1С после печати марки обычно не рекомендуется, однако для передачи в ККТ его наличие критично.
  4. Символы FNC1 (GS): В коде маркировки, особенно при кодировании в Base64 для передачи, должны присутствовать специальные символы FNC1 (ASCII 29), которые указывают на формат GS1 DataMatrix и разделяют группы данных. Неправильное их расположение или отсутствие приводит к ошибкам.
  5. Статусы на чеке: По результатам проверки КМ на чеке печатается «М+» (успешная проверка и выбытие), «М-» (ошибки проверки), «М» (проверка не пройдена, например, из-за отсутствия связи).

Шаг 1: Обновление компонентов и драйверов

Прежде чем приступать к изменениям кода, мы должны убедиться, что наше оборудование и программное обеспечение готовы к работе с ФФД 1.2:

  1. Фискальный накопитель: Убедитесь, что установлен фискальный накопитель нового образца (ФН-М), поддерживающий ФФД 1.2.
  2. Прошивка ККТ: Обновите прошивку вашей онлайн-кассы до актуальной версии, поддерживающей ФФД 1.2. (Например, АТОЛ 5.8.3, 5.8.14 или новее; Штрих C.3.41963 или новее).
  3. Драйвер ККТ: Установите последнюю версию драйвера ККТ — для этого подойдёт обновление драйверов ККТ для маркировки в УТ 10.3. (Например, драйвер АТОЛ 10.9.0.4, 10.9.0.8 или новее; драйвер Штрих 5.16.0.886 или новее).
  4. Обработка обслуживания ККТ: Получите актуальную обработку обслуживания для вашей ККТ (например, AtolKkt.epf, ShtrihMkkt.epf) — есть готовое подключение и обслуживание онлайн-касс на обычных формах. Важно убедиться, что внутри обработки (в ее макетах) находится соответствующая версия интеграционной компоненты драйвера. Если в типовой обработке компонента устаревшая, замените ее вручную на версию из папки с установленным драйвером.
  5. Перерегистрация ККТ: Выполните перерегистрацию ККТ в ФНС с указанием работы с маркированными товарами. Проверьте настройки серверов ОИСМ и ОКП в параметрах ККТ.

Шаг 2: Модификация обработки обслуживания ККТ (пример для Штрих-М и общие принципы)

Одной из первых проблем может быть некорректная работа самой обработки обслуживания. Мы рассмотрим пример для ККТ Штрих-М, но принципы применимы и к другим ККТ, например Посцентр с поддержкой ФФД 1.2.

  1. Замена компоненты драйвера: Откройте обработку ShtrihMkkt.epf в конфигураторе. В макетах обработки найдите и замените устаревшую компоненту на актуальную из комплекта драйвера. Например, если компонента ФФД 1.1 называется SMDrvFR1C.dll, а ФФД 1.2 — SMDrvFR1C34.dll, убедитесь, что используется правильная.
  2. Добавление методов для маркировки: В модуле обработки обслуживания добавьте необходимые функции для работы с маркировкой, если они отсутствуют. Для ФФД 1.2 критически важны функции, управляющие сессией проверки маркировки:
    • ЗапросКМ
    • ПолучитьРезультатыЗапросаКМ
    • ПодтвердитьКМ
    • ОткрытьСессиюРегистрацииКМ
    • ЗакрытьСессиюРегистрацииКМ

    Эти функции будут вызывать соответствующие методы объекта драйвера ККТ.

    
    // Пример для ShtrihMkkt.epf
    // Если отсутствуют, добавляем следующие функции:
    
    Функция ЗапросКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
        Результат = ОбъектДрайвера.ЗапросКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.КонтрольнаяМарка, ВыходныеПараметры.ИдентификаторЗапроса);
        Возврат Результат;
    КонецФункции
    
    Функция ПолучитьРезультатыЗапросаКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
        Результат = ОбъектДрайвера.ПолучитьРезультатыЗапросаКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.ИдентификаторЗапроса, ВыходныеПараметры.СтатусЗапроса);
        Возврат Результат;
    КонецФункции
    
    Функция ПодтвердитьКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
        Результат = ОбъектДрайвера.ПодтвердитьКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.ИдентификаторЗапроса, ВходныеПараметры.ТипПодтверждения);
        Возврат Результат;
    КонецФункции
    
    // Открытие и закрытие сессии также могут потребоваться
    Функция ОткрытьСессиюРегистрацииКМ(ОбъектДрайвера, ИДУстройства) Экспорт
        Возврат ОбъектДрайвера.ОткрытьСессиюРегистрацииКМ(ИДУстройства);
    КонецФункции
    
    Функция ЗакрытьСессиюРегистрацииКМ(ОбъектДрайвера, ИДУстройства) Экспорт
        Возврат ОбъектДрайвера.ЗакрытьСессиюРегистрацииКМ(ИДУстройства);
    КонецФункции
    
  3. Корректировка создания объекта драйвера: Если название компоненты изменилось, мы должны обновить функцию СоздатьОбъектДрайвера, чтобы она правильно инициализировала объект.
  4. 
    // Пример модификации функции СоздатьОбъектДрайвера
    // (в зависимости от имени новой компоненты)
    // В модуле обработки обслуживания (например, ShtrihMkkt.epf)
    Если Параметры.ИспользуетсяФФД12 Тогда // Предположим, у нас есть такой параметр
        ОбъектДрайвера = Новый COMОбъект("SMDrvFR1C34.Fptr"); // Новая компонента для ФФД 1.2
    Иначе
        ОбъектДрайвера = Новый COMОбъект("SMDrvFR1C.Fptr"); // Старая компонента
    КонецЕсли;
    

Шаг 3: Внедрение логики проверки и подтверждения КМ в 1С:УТ 10.3

Это самый важный шаг, так как он обеспечивает выполнение полного цикла работы с маркировкой на ККТ. Мы будем модифицировать общий модуль ПодключаемоеОборудованиеУниверсальныйДрайверКлиент, встраивая логику открытия сессии, запроса, получения результата и подтверждения КМ, что особенно важно при внедрении разрешительного режима в рознице — для этого есть фискализация ФФД 1.2 без доработки типовой базы.

  1. Добавление логики перед фискализацией чека: В процедуре ФискализацияЧека модуля ПодключаемоеОборудованиеУниверсальныйДрайверКлиент (ориентировочно строка 1555 в типовых модулях), непосредственно перед вызовом ОбъектДрайвера.СформироватьЧек, мы вставляем наш код для проверки марки.
  2. 
    // Модуль: ОбщийМодуль.ПодключаемоеОборудованиеУниверсальныйДрайверКлиент
    // Процедура: ФискализацияЧека
    
    // ... (Существующий код до вызова СформироватьЧек) ...
    
    Иначе // Если не СформироватьЧекКоррекции
        Если ПараметрыФискализации.ЕстьПерсональныеДанные Тогда
            ДанныеЧекаXML = ПараметрыФискализации.ДанныеЧекаXMLПерсональныеДанные;
        Иначе
            ДанныеЧекаXML = ПараметрыФискализации.ДанныеЧекаXML;
        КонецЕсли;
    
        // *** НАШ КОД ДЛЯ ПРОВЕРКИ И ПОДТВЕРЖДЕНИЯ КОДОВ МАРКИРОВКИ ***
        Попытка
            // Проверяем, что работаем с ФФД 1.2 и есть марки в чеке
            Если ПараметрыФискализации.РевизияИнтерфейса >= 3004 И ТипЗНЧ(ВходныеПараметры) = Тип("Массив") И ВходныеПараметры.Количество = 1 Тогда
                ПараметрыФискализацииЧека = ВходныеПараметры[0];
                ЕстьКМ = Ложь;
                Для Каждого СтрокаЧека из ПараметрыФискализацииЧека.ПозицииЧека Цикл
                    Если СтрокаЧека.Свойство("КонтрольнаяМарка") И ЗначениеЗаполнено(СтрокаЧека.КонтрольнаяМарка) Тогда
                        ЕстьКМ = Истина;
                        Прервать;
                    КонецЕсли;
                КонецЦикла;
    
                Если ЕстьКМ Тогда
                    // Открытие новой сессии проверки марок на ККТ
                    // Открытая сессия автоматически закрывается при фискализации чека
                    СессияОткрыта = ОбработкаОбслуживания.ОткрытьСессиюРегистрацииКМ(ОбъектДрайвера, ПараметрыПодключения.ИДУстройства); // Обращаемся к нашей обработке
                    Если СессияОткрыта Тогда
                        ОписаниеОшибки = "";
                        Для Каждого СтрокаЧека из ПараметрыФискализацииЧека.ПозицииЧека Цикл
                            Если СтрокаЧека.Свойство("КонтрольнаяМарка") И ЗначениеЗаполнено(СтрокаЧека.КонтрольнаяМарка) Тогда
                                // Формирование запроса на проверку КМ на ККТ.
                                // Поле «MarkingCode» заполняется значением полной КМ в BASE64.
                                ПараметрыОперации = Новый Структура("КонтрольнаяМарка,ИдентификаторЗапроса,ПланируемыйСтатусТовара", СтрокаЧека.КонтрольнаяМарка, Новый УникальныйИдентификатор, Перечисления.ПланируемыйСтатусМаркируемогоТовара.ШтучныйТоварРеализован);
                                ПараметрыОперацииXML = МенеджерОборудованияВызовСервера.СформироватьXMLДляЗапросаКМ(ПараметрыОперации);
                                РезультатОперацииXML = "";
                                    
                                // Вызов метода ЗапросКМ из обработки обслуживания
                                Результат = ОбработкаОбслуживания.ЗапросКМ(ОбъектДрайвера, ПараметрыККТ, ПараметрыОперации, ВыходныеПараметры, Идентификатор); // Передаем параметры
                                Если НЕ Результат Тогда
                                    ОбъектДрайвера.ПолучитьОшибку(ОписаниеОшибки);
                                    Прервать;
                                Иначе
                                    // Получение результата проверки КМ.
                                    СтатусЗапроса = -1;
                                    Счетчик = 0;
                                    Пока СтатусЗапроса <> 0 И СтатусЗапроса <> 2 И Счетчик < 10 Цикл
                                        РезультатОперацииXML = "";
                                            
                                        // Вызов метода ПолучитьРезультатыЗапросаКМ из обработки обслуживания
                                        Результат = ОбработкаОбслуживания.ПолучитьРезультатыЗапросаКМ(ОбъектДрайвера, ПараметрыККТ, ПараметрыОперации, ВыходныеПараметры, Идентификатор); // Передаем параметры
                                        Если НЕ Результат Тогда
                                            ОбъектДрайвера.ПолучитьОшибку(ОписаниеОшибки);
                                            Прервать;
                                        КонецЕсли;
                                        СтатусЗапроса = ВыходныеПараметры.СтатусЗапроса; // Получаем статус из выходных параметров
                                            
                                        Если СтатусЗапроса = 0 Тогда
                                            Прервать;
                                        КонецЕсли;
                                        // Небольшая задержка, чтобы не спамить ККТ запросами
                                        ТекВремя = ТекущаяДата;
                                        Пока ТекВремя = ТекущаяДата Цикл КонецЦикла; 
                                        Счетчик = Счетчик + 1;
                                    КонецЦикла;
    
                                    Если СтатусЗапроса = 0 Тогда
                                        // Подтверждение КМ для последующего включения в чек.
                                        // Если пользователь соглашается – ТипПодтверждения=0 (подтвердить).
                                        Результат = ОбработкаОбслуживания.ПодтвердитьКМ(ОбъектДрайвера, ПараметрыККТ, ПараметрыОперации, ВыходныеПараметры, Идентификатор); // ТипПодтверждения=0
                                        Если НЕ Результат Тогда
                                            ОбъектДрайвера.ПолучитьОшибку(ОписаниеОшибки);
                                            Прервать;
                                        КонецЕсли;
                                    Иначе
                                        ОписаниеОшибки = ?(СтатусЗапроса = 2, "Проверка марки: результата не может быть получен", ?(ЗначениеЗаполнено(ОписаниеОшибки), ОписаниеОшибки, "Проверка марки: результат не получен за 10 сек"));
                                        Прервать;
                                    КонецЕсли;
                                КонецЕсли;
                            КонецЕсли;
                        КонецЦикла;
    
                        Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
                            Попытка
                                ОбработкаОбслуживания.ЗакрытьСессиюРегистрацииКМ(ОбъектДрайвера, ПараметрыПодключения.ИДУстройства);
                            Исключение
                            КонецПопытки;
                            СформироватьОшибку(ВыходныеПараметры, ОписаниеОшибки);
                            Возврат Ложь;
                        КонецЕсли;
                    КонецЕсли;
                КонецЕсли;
            КонецЕсли;
        Исключение
            // Обработка ошибок в процессе проверки КМ
            Результат = Ложь;
            СформироватьОшибкуДрайвера(ВыходныеПараметры, "Ошибка проверки КМ", ОписаниеОшибки);
        КонецПопытки;
        // *** КОНЕЦ НАШЕГО КОДА ***
    
        // Типовой вызов метода СформироватьЧек
        Попытка
            Если ПараметрыФискализации.РевизияИнтерфейса >= 3000 Тогда // Версия стандарта 3.0 (ОФД 1.1)
                Результат = ОбъектДрайвера.СформироватьЧек(ПараметрыПодключения.ИДУстройства, ПараметрыФискализации.Электронно, ДанныеЧекаXML, ПараметрыФискализации.РезультатОперацииXML);
            Иначе // Версия стандарта 2.2 и выше (ОФД 1.0.5)
                Результат = ОбъектДрайвера.СформироватьЧек(ПараметрыПодключения.ИДУстройства, ПараметрыФискализации.Электронно, ДанныеЧекаXML, ПараметрыФискализации.НомерЧекаККТ, ПараметрыФискализации.НомерСменыККТ, ПараметрыФискализации.ФискальныйПризнак, ПараметрыФискализации.АдресСайтаПроверки);
            КонецЕсли;
            ПараметрыФискализации.ДатаВремяЧека = ДатаСеанса;
        Исключение
            Результат = Ложь;
            СформироватьОшибкуДрайвера(ВыходныеПараметры, "СформироватьЧек", ОписаниеОшибки);
        КонецПопытки;
    КонецЕсли;
    

    Обратите внимание, что в данном коде мы вызываем методы ОткрытьСессиюРегистрацииКМ, ЗапросКМ, ПолучитьРезультатыЗапросаКМ, ПодтвердитьКМ через объект ОбработкаОбслуживания. Это требует, чтобы в вашей обработке обслуживания ККТ эти методы были реализованы и экспортированы.

    Также важно, что структура ПараметрыОперации формируется с КонтрольнаяМарка, которая должна содержать полный код маркировки в Base64.

  3. Добавление реквизита для хранения полной марки: Так как УТ 10.3 может не всегда хранить полный код маркировки с криптохвостом, мы можем добавить дополнительный реквизит в структуру фискальной строки или в справочник ШтрихкодыУпаковок (или аналогичный), чтобы при сканировании марки сохранять ее полную версию. Этот реквизит и будет использоваться для заполнения поля КонтрольнаяМарка.

Шаг 4: Корректировка формирования XML-пакета для чека

Для корректной передачи кода маркировки в ККТ и далее в ЧЗ, мы должны убедиться, что XML-пакет, отправляемый на фискализацию, содержит правильный тег и формат кода маркировки.

  1. Формирование полного кода маркировки с GS1 символами: Изначально, код маркировки, считываемый сканером, может быть строкой без явных символов-разделителей GS1. Для корректной обработки ККТ и ЧЗ, мы должны вставить эти символы в правильные позиции и затем закодировать всю строку в Base64. Символ GS1 соответствует ASCII 29.
    
    // Функция для вставки символов-разделителей GS1 и кодирования в Base64
    // (Может быть добавлена в общий модуль, например, МенеджерОборудованияМаркировкаКлиентСервер или МенеджерОборудованияВызовСервера)
    
    Функция ВставкаСимволаРазделителяGS1ВШтрихкод(ДанныеКодаТовара) Экспорт
        РазделительGS1 = Символ(29); // Символ GS1 (FNC1)
    
        Штрихкод = Base64ВШтрихкод(ДанныеКодаТовара.ШтрихкодBase64); // Декодируем, если уже в Base64
    
        Если Найти(Штрихкод, РазделительGS1) > 0 Тогда
            Возврат ДанныеКодаТовара.ШтрихкодBase64; // Если уже есть, ничего не делаем
        КонецЕсли;
    
        // Предполагаем, что Штрихкод содержит GTIN (первые 14 цифр), затем серийный номер (6 символов),
        // затем криптохвост.
        // Структура DataMatrix для обуви/текстиля часто: (01)GTIN(21)СерийныйНомер(91)КлючПроверки(92)КодПроверки
        // Где (01), (21), (91), (92) - идентификаторы применения.
        // GS1 символы вставляются после групп данных.
    
        // Упрощенный пример для вставки GS1 после 31-го и 38-го символов
        // (может потребоваться адаптация под конкретную структуру маркировки)
        ПозицияСерийногоНомера = Найти(Штрихкод, ДанныеКодаТовара.СерийныйНомер); // Если у нас есть СерийныйНомер отдельно
    
        Если ПозицияСерийногоНомера > 0 Тогда
            ЛеваяЧастьШтрихкода = Лев(Штрихкод, ПозицияСерийногоНомера - 1 + СтрДлина(ДанныеКодаТовара.СерийныйНомер)); // GTIN + SN
            СредняяЧастьШтрихкода = РазделительGS1 + Сред(Штрихкод, СтрДлина(ЛеваяЧастьШтрихкода) + 1, 6) + РазделительGS1; // Предполагаемый фрагмент с AI (91)
            ПраваяЧастьШтрихкода = Сред(Штрихкод, СтрДлина(ЛеваяЧастьШтрихкода) + 7); // Криптохвост
    
            Штрихкод = ЛеваяЧастьШтрихкода + СредняяЧастьШтрихкода + ПраваяЧастьШтрихкода;
        Иначе
            // Альтернативный подход, если нет СерийногоНомера или позиция не найдена
            // Вставляем GS1 после 31-го символа (GTIN+SN) и после 38-го символа (после AI(21))
            Если СтрДлина(Штрихкод) >= 38 Тогда
                Штрихкод = Лев(Штрихкод, 31) + РазделительGS1 + Сред(Штрихкод, 32, 6) + РазделительGS1 + Сред(Штрихкод, 38);
            ИначеЕсли СтрДлина(Штрихкод) >= 31 Тогда
                Штрихкод = Лев(Штрихкод, 31) + РазделительGS1 + Сред(Штрихкод, 32);
            КонецЕсли;
        КонецЕсли;
    
        // Кодируем результат обратно в Base64
        Возврат ШтрихкодВBase64(Штрихкод);
    КонецФункции
    
    // Вспомогательные функции, если отсутствуют
    Функция Base64ВШтрихкод(ШтрихкодBase64) Экспорт
        ДвоичныеДанные = Base64Декодировать(ШтрихкодBase64);
        ПотокВПамяти = Новый ПотокВПамяти;
        ДвоичныеДанные.Записать(ПотокВПамяти);
        ПотокВПамяти.УстановитьПозицию(0);
        ЧтениеТекста = Новый ЧтениеТекста(ПотокВПамяти, КодировкаТекста.UTF8); // Или ANSI/Windows-1251
        Возврат ЧтениеТекста.ПрочитатьДоКонца();
    КонецФункции
    
    Функция ШтрихкодВBase64(Штрихкод) Экспорт
        ЗаписьТекста = Новый ЗаписьТекста(Новый ПотокВПамяти(), КодировкаТекста.UTF8); // Или ANSI/Windows-1251
        ЗаписьТекста.Записать(Штрихкод);
        ДвоичныеДанные = ЗаписьТекста.ЗакрытьИПолучитьДвоичныеДанные();
        Возврат Base64Кодировать(ДвоичныеДанные);
    КонецФункции
    

    Важно: При кодировании в Base64 может появиться префикс "77u/". Его необходимо удалить из строки Base64, так как он не является частью маркировки и может привести к ошибкам.

    
    // Пример удаления префикса "77u/" из Base64 строки
    Функция ЗакодироватьКодМаркировкиBase64(КодМаркировки, ТолькоЗ1Симовол = Ложь) Экспорт
        РазделительGS1 = Символ(29); // Символ GS1
        ВременныйФайл = ПолучитьИмяВременногоФайла;
        Запись = Новый ЗаписьТекста(ВременныйФайл, КодировкаТекста.ANSI); // Может быть UTF8, зависит от ККТ/драйвера
        Если ТолькоЗ1Симовол Тогда
            Запись.Записать( Лев(КодМаркировки, 31) );
        Иначе
            Запись.Записать( Лев(КодМаркировки, 31) + РазделительGS1 + Сред(КодМаркировки, 32, 6) + РазделительGS1 + Сред(КодМаркировки, 38) );
        КонецЕсли;
        Запись.Закрыть();
        Дв = Новый ДвоичныеДанные(ВременныйФайл);
        ВремШтрихкодBase64 = Base64Строка(Дв);
        ШтрихкодBase64 = ?(Лев(ВремШтрихкодBase64, 4) = "77u/", Сред(ВремШтрихкодBase64, 5), ВремШтрихкодBase64); // Удаление BOM
        УдалитьФайлы(ВременныйФайл);
        Возврат ШтрихкодBase64;
    КонецФункции
    
  2. Заполнение тега MarkingCode: В общем модуле МенеджерОборудованияВызовСервера, в процедуре СформироватьXMLПакетДляФискализацияЧека, мы должны убедиться, что тег MarkingCode заполняется полным кодом маркировки в Base64 (который мы получили с помощью функции ВставкаСимволаРазделителяGS1ВШтрихкод). При этом важно не дублировать информацию о маркировке в других тегах, таких как GoodCodeData, чтобы избежать ошибки "Повтор реквизита невозможен (1305)".
    
    // Модуль: ОбщийМодуль.МенеджерОборудованияВызовСервера
    // Процедура: СформироватьXMLПакетДляФискализацияЧека
    
    // ... (Существующий код) ...
    
    Если НЕ ПустаяСтрока(ТекущаяПозиция.ШтрихкодBase64) Тогда
        ДанныеКодаТовара = МенеджерОборудованияМаркировкаКлиентСервер.РазобратьШтриховойКодТовара(ТекущаяПозиция.ШтрихкодBase64, Истина);
        РеквизитКодаТовара = ДанныеКодаТовара.РеквизитКодаТовара;
        Если НЕ ПустаяСтрока(РеквизитКодаТовара) И Не ПустаяСтрока(ДанныеКодаТовара.ШтрихкодBase64) Тогда
            // Запись тега 1163. Здесь в MarkingCode передаем полную марку в Base64 с GS1
            ШтрихкодBase64СGS1 = ВставкаСимволаРазделителяGS1ВШтрихкод(ДанныеКодаТовара); // Используем нашу функцию
            ЗаписьXML.ЗаписатьАтрибут("MarkingCode", XMLСтрока(ШтрихкодBase64СGS1));
        КонецЕсли;
    КонецЕсли;
    
    // Важно: закомментировать или убедиться, что в тег GoodCodeData НЕ записывается полная марка,
    // если она уже записана в MarkingCode, чтобы избежать ошибки 1305.
    // Если ПараметрыФискализации.РевизияИнтерфейса >= 3004 Тогда
    //    Если Не ПустаяСтрока(ТекущаяПозиция.КонтрольнаяМарка) Тогда
    //        ЗаписьXML.ЗаписатьАтрибут("MarkingCode", XMLСтрока(ТекущаяПозиция.КонтрольнаяМарка));
    //    КонецЕсли;
    // КонецЕсли;
    
  3. Передача КонтрольнаяМарка в параметрах ККТ: В модуле МенеджерОборудованияКлиент, в процедуре НачатьВыполнениеКомандыТО, перед выполнением команды, убедитесь, что ВходныеПараметры.КонтрольнаяМарка содержит правильно сформированный код маркировки в Base64.
    
    // Модуль: ОбщийМодуль.МенеджерОборудованияКлиент
    // Процедура: НачатьВыполнениеКомандыТО
    
    Попытка
        Если ЗначениеЗаполнено(ВходныеПараметры.КонтрольнаяМарка) Тогда
            // Убедимся, что в КонтрольнаяМарка находится полная марка с GS1 в Base64
            ДанныеКодаТовара = МенеджерОборудованияМаркировкаКлиентСервер.РазобратьШтриховойКодТовара(ВходныеПараметры.КонтрольнаяМарка, Истина);
            РеквизитКодаТовара = ДанныеКодаТовара.РеквизитКодаТовара;
            Если НЕ ПустаяСтрока(РеквизитКодаТовара) И Не ПустаяСтрока(ДанныеКодаТовара.ШтрихкодBase64) Тогда
                ШтрихкодBase64СGS1 = МенеджерОборудованияВызовСервера.ВставкаСимволаРазделителяGS1ВШтрихкод(ДанныеКодаТовара);
                ВходныеПараметры.КонтрольнаяМарка = ШтрихкодBase64СGS1;
            КонецЕсли;
        КонецЕсли;
    Исключение
        // Обработка ошибок при подготовке марки
    КонецПопытки;
    
    // ... (Далее следует типовой код выполнения команд ККТ) ...
    

Шаг 5: Дополнительные исправления и рекомендации

Помимо основной логики работы с маркировкой, есть несколько других моментов, которые мы должны учесть для стабильной работы.

  1. Корректировка типа операции для возврата: В модуле документа ЧекККМ, в функции ПараметрыОперацииФискализацииЧека, необходимо исправить определение типа расчета для чеков возврата. Типовая логика может всегда устанавливать «ПриходДенежныхСредств».
    
    // Модуль: Документ.ЧекККМ
    // Функция: ПараметрыОперацииФискализацииЧека
    
    Если ВидОперации = Перечисления.ВидыОперацийЧекККМ.Возврат Тогда
        ПараметрыОперацииФискализацииЧека.ТипРасчета = ПредопределенноеЗначение("Перечисление.ТипыРасчетаДенежнымиСредствами.ВозвратДенежныхСредств");
    Иначе
        ПараметрыОперацииФискализацииЧека.ТипРасчета = ПредопределенноеЗначение("Перечисление.ТипыРасчетаДенежнымиСредствами.ПриходДенежныхСредств");
    КонецЕсли;
    
  2. Настройка параметра «РевизияИнтерфейса»: В общем модуле МенеджерОборудованияВызовСервера, в функции РевизияИнтерфейсаДрайверов, мы должны убедиться, что возвращается правильная ревизия интерфейса драйвера, соответствующая ФФД 1.2 (например, 3004).
    
    // Модуль: ОбщийМодуль.МенеджерОборудованияВызовСервера
    // Функция: РевизияИнтерфейсаДрайверов
    
    // ...
    РевизияИнтерфейса = 3004; // Устанавливаем версию, соответствующую ФФД 1.2
    // ...
    
  3. Настройка параметров Кассы ККМ: В модуле справочника КассыККМ, в функции ПараметрыКассыККМ, убедитесь, что запрос корректно выбирает нужную кассу ККМ, учитывая компьютер и статус подключения.
    
    // Модуль: Справочник.КассыККМ
    // Функция: ПараметрыКассыККМ
    
    Запрос.Текст ="ВЫБРАТЬ
    | КассыККМ.Ссылка КАК КассаККМ,
    | КассыККМ.Владелец КАК Организация,
    | КассыККМ.СерийныйНомер КАК СерийныйНомер,
    | ТорговоеОборудование.Идентификатор КАК ИдентификаторУстройства
    |ИЗ
    | Справочник.КассыККМ КАК КассыККМ
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТорговоеОборудование КАК ТорговоеОборудование
    | ПО КассыККМ.Ссылка = ТорговоеОборудование.КассаККМ
    |ГДЕ
    | КассыККМ.Ссылка = &Ссылка
    | И ТорговоеОборудование.Компьютер = &Компьютер // Добавляем условие по компьютеру
    | И ТорговоеОборудование.Подключено = ИСТИНА"; // И по статусу подключения
    Запрос.УстановитьПараметр("Ссылка", КассаККМ);
    Запрос.УстановитьПараметр("Компьютер", ИмяКомпьютера);
    
  4. Установка версии ФФД для ККТ и ФН: В модуле справочника ТорговоеОборудование, в функции ПолучитьПараметрыРегистрацииУстройства, мы можем явно установить версии ФФД для ККТ и ФН, чтобы система корректно инициализировала процесс проверки кодов маркировки фискальным регистратором.
    
    // Модуль: Справочник.ТорговоеОборудование
    // Функция: ПолучитьПараметрыРегистрацииУстройства
    
    // ... (Существующий код) ...
    РезультатОперации.ВерсияФФДККТ = "1.2";
    РезультатОперации.ВерсияФФДФН = "1.2";
    Возврат РезультатОперации;
    
  5. Исправление обработки статуса марки для розничной продажи: В модуле РозничныеПродажиКлиент, в процедуре ПроверитьКодМаркировкиСредствамиККТ, убедитесь, что для продаж правильно устанавливается ВидОперацииИСМП.
    
    // Модуль: ОбщийМодуль.РозничныеПродажиКлиент
    // Процедура: ПроверитьКодМаркировкиСредствамиККТ
    
    // ... (Существующий код) ...
    Попытка
        // Иначе всегда будет "Возврат в оборот при розничной реализации"
        Если ФормаВладелец.ВидОперации = Перечисления.ВидыОперацийЧекККМ.Продажа Тогда
            ПараметрыСканирования.ВидОперацииИСМП = Перечисления.ВидыОперацийИСМП.ВыводИзОборотаРозничнаяПродажа;
        КонецЕсли;
    Исключение
        // Обработка ошибок
    КонецПопытки;
    // ...
    
  6. Решение ошибки "d3h код товара не распознан" (для АТОЛ): Если фискальник выдает такую ошибку, мы можем временно разрешить ККТ принимать все коды товаров независимо от их корректности. Зайдите в свойства фискальника через драйвер ККТ АТОЛ, перейдите в Таблицу 17, строка 41 и установите значение "RUS принимать все КТ" = 1. Это может помочь в тестовом режиме, но в боевой среде необходимо стремиться к передаче корректных марок.

Заключение

Настройка ФФД 1.2 в 1С:УТ 10.3 для работы с маркированными товарами требует существенных доработок конфигурации и обработки обслуживания ККТ. Мы рассмотрели комплексный подход, включающий обновление компонентов, внедрение полного цикла проверки маркировки на ККТ (ОткрытьСессиюРегистрацииКМ, ЗапросКМ, ПолучитьРезультатыЗапросаКМ, ПодтвердитьКМ) и корректное формирование XML-пакета с полным кодом маркировки в Base64. Применяя эти шаги, вы сможете добиться того, что на чеках будет печататься «М+», а коды маркировки будут успешно выбывать из оборота в системе «Честный ЗНАК».

Помните, что данные доработки затрагивают критически важные участки кода, поэтому всегда делайте резервные копии информационной базы перед внесением изменений и тщательно тестируйте функциональность на тестовом контуре.

← На главную