При переходе на формат фискальных данных (ФФД) 1.2 для работы с маркированными товарами в 1С:Управление торговлей 10.3, многие пользователи сталкиваются с проблемой некорректной передачи информации о маркировке в систему «Честный ЗНАК» (ЧЗ). Чаще всего, чеки фискализируются и уходят в налоговую, но данные о выбытии маркированного товара не достигают ЧЗ, и на бумажном чеке отсутствует обязательная буква «М», «М+» или «М-». Давайте подробно разберем, почему это происходит, и как мы можем исправить ситуацию, модифицировав конфигурацию 1С и обработку обслуживания контрольно-кассовой техники (ККТ).
Прежде чем перейти к решению, рассмотрим основные сложности, с которыми сталкиваются пользователи:
RequestKM (запрос кода маркировки).GetProcessingResult (получение результатов проверки).ConfirmKM (подтверждение кода маркировки для выбытия).Fiscalization (фискализация чека).В типовой УТ 10.3 часто отсутствует или некорректно реализована логика выполнения первых трех команд, передается только команда фискализации с усеченным или неправильно сформированным кодом маркировки.
AtolKkt.epf или ShtrihMkkt.epf) могут содержать устаревшие компоненты или не реализовывать новые методы, необходимые для ФФД 1.2.Для понимания дальнейших шагов, вспомним ключевые особенности ФФД 1.2 при работе с маркированными товарами:
Прежде чем приступать к изменениям кода, мы должны убедиться, что наше оборудование и программное обеспечение готовы к работе с ФФД 1.2:
AtolKkt.epf, ShtrihMkkt.epf) — есть готовое подключение и обслуживание онлайн-касс на обычных формах. Важно убедиться, что внутри обработки (в ее макетах) находится соответствующая версия интеграционной компоненты драйвера. Если в типовой обработке компонента устаревшая, замените ее вручную на версию из папки с установленным драйвером.Одной из первых проблем может быть некорректная работа самой обработки обслуживания. Мы рассмотрим пример для ККТ Штрих-М, но принципы применимы и к другим ККТ, например Посцентр с поддержкой ФФД 1.2.
ShtrihMkkt.epf в конфигураторе. В макетах обработки найдите и замените устаревшую компоненту на актуальную из комплекта драйвера. Например, если компонента ФФД 1.1 называется SMDrvFR1C.dll, а ФФД 1.2 — SMDrvFR1C34.dll, убедитесь, что используется правильная.ЗапросКМПолучитьРезультатыЗапросаКМПодтвердитьКМОткрытьСессиюРегистрацииКМЗакрытьСессиюРегистрацииКМЭти функции будут вызывать соответствующие методы объекта драйвера ККТ.
// Пример для ShtrihMkkt.epf
// Если отсутствуют, добавляем следующие функции:
Функция ЗапросКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
Результат = ОбъектДрайвера.ЗапросКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.КонтрольнаяМарка, ВыходныеПараметры.ИдентификаторЗапроса);
Возврат Результат;
КонецФункции
Функция ПолучитьРезультатыЗапросаКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
Результат = ОбъектДрайвера.ПолучитьРезультатыЗапросаКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.ИдентификаторЗапроса, ВыходныеПараметры.СтатусЗапроса);
Возврат Результат;
КонецФункции
Функция ПодтвердитьКМ(ОбъектДрайвера, ПараметрыККТ, ВходныеПараметры, ВыходныеПараметры, Идентификатор) Экспорт
Результат = ОбъектДрайвера.ПодтвердитьКМ(ПараметрыККТ.ИДУстройства, ВходныеПараметры.ИдентификаторЗапроса, ВходныеПараметры.ТипПодтверждения);
Возврат Результат;
КонецФункции
// Открытие и закрытие сессии также могут потребоваться
Функция ОткрытьСессиюРегистрацииКМ(ОбъектДрайвера, ИДУстройства) Экспорт
Возврат ОбъектДрайвера.ОткрытьСессиюРегистрацииКМ(ИДУстройства);
КонецФункции
Функция ЗакрытьСессиюРегистрацииКМ(ОбъектДрайвера, ИДУстройства) Экспорт
Возврат ОбъектДрайвера.ЗакрытьСессиюРегистрацииКМ(ИДУстройства);
КонецФункции
СоздатьОбъектДрайвера, чтобы она правильно инициализировала объект.
// Пример модификации функции СоздатьОбъектДрайвера
// (в зависимости от имени новой компоненты)
// В модуле обработки обслуживания (например, ShtrihMkkt.epf)
Если Параметры.ИспользуетсяФФД12 Тогда // Предположим, у нас есть такой параметр
ОбъектДрайвера = Новый COMОбъект("SMDrvFR1C34.Fptr"); // Новая компонента для ФФД 1.2
Иначе
ОбъектДрайвера = Новый COMОбъект("SMDrvFR1C.Fptr"); // Старая компонента
КонецЕсли;
Это самый важный шаг, так как он обеспечивает выполнение полного цикла работы с маркировкой на ККТ. Мы будем модифицировать общий модуль ПодключаемоеОборудованиеУниверсальныйДрайверКлиент, встраивая логику открытия сессии, запроса, получения результата и подтверждения КМ, что особенно важно при внедрении разрешительного режима в рознице — для этого есть фискализация ФФД 1.2 без доработки типовой базы.
ФискализацияЧека модуля ПодключаемоеОборудованиеУниверсальныйДрайверКлиент (ориентировочно строка 1555 в типовых модулях), непосредственно перед вызовом ОбъектДрайвера.СформироватьЧек, мы вставляем наш код для проверки марки.
// Модуль: ОбщийМодуль.ПодключаемоеОборудованиеУниверсальныйДрайверКлиент
// Процедура: ФискализацияЧека
// ... (Существующий код до вызова СформироватьЧек) ...
Иначе // Если не СформироватьЧекКоррекции
Если ПараметрыФискализации.ЕстьПерсональныеДанные Тогда
ДанныеЧека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.
ШтрихкодыУпаковок (или аналогичный), чтобы при сканировании марки сохранять ее полную версию. Этот реквизит и будет использоваться для заполнения поля КонтрольнаяМарка.Для корректной передачи кода маркировки в ККТ и далее в ЧЗ, мы должны убедиться, что XML-пакет, отправляемый на фискализацию, содержит правильный тег и формат кода маркировки.
// Функция для вставки символов-разделителей 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;
КонецФункции
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Строка(ТекущаяПозиция.КонтрольнаяМарка));
// КонецЕсли;
// КонецЕсли;
КонтрольнаяМарка в параметрах ККТ: В модуле МенеджерОборудованияКлиент, в процедуре НачатьВыполнениеКомандыТО, перед выполнением команды, убедитесь, что ВходныеПараметры.КонтрольнаяМарка содержит правильно сформированный код маркировки в Base64.
// Модуль: ОбщийМодуль.МенеджерОборудованияКлиент
// Процедура: НачатьВыполнениеКомандыТО
Попытка
Если ЗначениеЗаполнено(ВходныеПараметры.КонтрольнаяМарка) Тогда
// Убедимся, что в КонтрольнаяМарка находится полная марка с GS1 в Base64
ДанныеКодаТовара = МенеджерОборудованияМаркировкаКлиентСервер.РазобратьШтриховойКодТовара(ВходныеПараметры.КонтрольнаяМарка, Истина);
РеквизитКодаТовара = ДанныеКодаТовара.РеквизитКодаТовара;
Если НЕ ПустаяСтрока(РеквизитКодаТовара) И Не ПустаяСтрока(ДанныеКодаТовара.ШтрихкодBase64) Тогда
ШтрихкодBase64СGS1 = МенеджерОборудованияВызовСервера.ВставкаСимволаРазделителяGS1ВШтрихкод(ДанныеКодаТовара);
ВходныеПараметры.КонтрольнаяМарка = ШтрихкодBase64СGS1;
КонецЕсли;
КонецЕсли;
Исключение
// Обработка ошибок при подготовке марки
КонецПопытки;
// ... (Далее следует типовой код выполнения команд ККТ) ...
Помимо основной логики работы с маркировкой, есть несколько других моментов, которые мы должны учесть для стабильной работы.
ЧекККМ, в функции ПараметрыОперацииФискализацииЧека, необходимо исправить определение типа расчета для чеков возврата. Типовая логика может всегда устанавливать «ПриходДенежныхСредств».
// Модуль: Документ.ЧекККМ
// Функция: ПараметрыОперацииФискализацииЧека
Если ВидОперации = Перечисления.ВидыОперацийЧекККМ.Возврат Тогда
ПараметрыОперацииФискализацииЧека.ТипРасчета = ПредопределенноеЗначение("Перечисление.ТипыРасчетаДенежнымиСредствами.ВозвратДенежныхСредств");
Иначе
ПараметрыОперацииФискализацииЧека.ТипРасчета = ПредопределенноеЗначение("Перечисление.ТипыРасчетаДенежнымиСредствами.ПриходДенежныхСредств");
КонецЕсли;
МенеджерОборудованияВызовСервера, в функции РевизияИнтерфейсаДрайверов, мы должны убедиться, что возвращается правильная ревизия интерфейса драйвера, соответствующая ФФД 1.2 (например, 3004).
// Модуль: ОбщийМодуль.МенеджерОборудованияВызовСервера
// Функция: РевизияИнтерфейсаДрайверов
// ...
РевизияИнтерфейса = 3004; // Устанавливаем версию, соответствующую ФФД 1.2
// ...
КассыККМ, в функции ПараметрыКассыККМ, убедитесь, что запрос корректно выбирает нужную кассу ККМ, учитывая компьютер и статус подключения.
// Модуль: Справочник.КассыККМ
// Функция: ПараметрыКассыККМ
Запрос.Текст ="ВЫБРАТЬ
| КассыККМ.Ссылка КАК КассаККМ,
| КассыККМ.Владелец КАК Организация,
| КассыККМ.СерийныйНомер КАК СерийныйНомер,
| ТорговоеОборудование.Идентификатор КАК ИдентификаторУстройства
|ИЗ
| Справочник.КассыККМ КАК КассыККМ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ТорговоеОборудование КАК ТорговоеОборудование
| ПО КассыККМ.Ссылка = ТорговоеОборудование.КассаККМ
|ГДЕ
| КассыККМ.Ссылка = &Ссылка
| И ТорговоеОборудование.Компьютер = &Компьютер // Добавляем условие по компьютеру
| И ТорговоеОборудование.Подключено = ИСТИНА"; // И по статусу подключения
Запрос.УстановитьПараметр("Ссылка", КассаККМ);
Запрос.УстановитьПараметр("Компьютер", ИмяКомпьютера);
ТорговоеОборудование, в функции ПолучитьПараметрыРегистрацииУстройства, мы можем явно установить версии ФФД для ККТ и ФН, чтобы система корректно инициализировала процесс проверки кодов маркировки фискальным регистратором.
// Модуль: Справочник.ТорговоеОборудование
// Функция: ПолучитьПараметрыРегистрацииУстройства
// ... (Существующий код) ...
РезультатОперации.ВерсияФФДККТ = "1.2";
РезультатОперации.ВерсияФФДФН = "1.2";
Возврат РезультатОперации;
РозничныеПродажиКлиент, в процедуре ПроверитьКодМаркировкиСредствамиККТ, убедитесь, что для продаж правильно устанавливается ВидОперацииИСМП.
// Модуль: ОбщийМодуль.РозничныеПродажиКлиент
// Процедура: ПроверитьКодМаркировкиСредствамиККТ
// ... (Существующий код) ...
Попытка
// Иначе всегда будет "Возврат в оборот при розничной реализации"
Если ФормаВладелец.ВидОперации = Перечисления.ВидыОперацийЧекККМ.Продажа Тогда
ПараметрыСканирования.ВидОперацииИСМП = Перечисления.ВидыОперацийИСМП.ВыводИзОборотаРозничнаяПродажа;
КонецЕсли;
Исключение
// Обработка ошибок
КонецПопытки;
// ...
Настройка ФФД 1.2 в 1С:УТ 10.3 для работы с маркированными товарами требует существенных доработок конфигурации и обработки обслуживания ККТ. Мы рассмотрели комплексный подход, включающий обновление компонентов, внедрение полного цикла проверки маркировки на ККТ (ОткрытьСессиюРегистрацииКМ, ЗапросКМ, ПолучитьРезультатыЗапросаКМ, ПодтвердитьКМ) и корректное формирование XML-пакета с полным кодом маркировки в Base64. Применяя эти шаги, вы сможете добиться того, что на чеках будет печататься «М+», а коды маркировки будут успешно выбывать из оборота в системе «Честный ЗНАК».
Помните, что данные доработки затрагивают критически важные участки кода, поэтому всегда делайте резервные копии информационной базы перед внесением изменений и тщательно тестируйте функциональность на тестовом контуре.