При работе с маркировкой товаров в современных конфигурациях 1С (ERP, КА, УТ 11) программисты часто сталкиваются с необходимостью автоматизировать создание упаковок — палет или коробов (а пользователям часто требуются дополнительные колонки со штрихкодами в справочнике номенклатуры). Типовой справочник ШтрихкодыУпаковокТоваров имеет сложную внутреннюю логику, из-за которой данные, видимые в отладчике перед записью, могут бесследно исчезнуть или обнулиться после выполнения метода Записать(). В этой статье мы подробно разберем, как правильно наполнять этот справочник программно (что актуально, например, при загрузке штрихкодов из StoreHouse), почему очищается реквизит Количество и как работать с вложенными структурами данных.
Рассмотрим ситуацию, когда разработчик пытается создать элемент справочника и заполнить его табличную часть ВложенныеШтрихкоды строковыми значениями QR-кодов (DataMatrix). На первый взгляд код выглядит логично: создается объект (или выполняется загрузка кодов маркировки из XML), заполняются основные реквизиты, добавляются строки в таблицу. Однако после записи поле Количество становится равным нулю, а табличная часть пустой. Выясним причину этого поведения.
Основная ошибка заключается в несоответствии типов данных. В справочнике ШтрихкодыУпаковокТоваров табличная часть ВложенныеШтрихкоды содержит реквизит Штрихкод, который имеет тип СправочникСсылка.ШтрихкодыУпаковокТоваров. Это означает, что справочник ссылается сам на себя (рекурсивная структура). Если мы попытаемся записать туда строку с кодом маркировки вместо ссылки на уже существующий элемент этого же справочника, 1С не сможет сопоставить типы и фактически оставит поле пустым.
Вторая важная причина — работа типового обработчика ПередЗаписью. В модуле объекта этого справочника прописана жесткая логика пересчета итогов. Давайте проанализируем, что происходит внутри системы при вызове метода записи.
В типовых решениях процедура ПередЗаписью выполняет автоматический расчет многих полей. Посмотрим на фрагмент кода, который отвечает за это:
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Не (ДополнительныеСвойства.Свойство("НеРассчитыватьКоличествоВложенныхШтрихкодов") И ДополнительныеСвойства.НеРассчитыватьКоличествоВложенныхШтрихкодов) Тогда
РассчитатьКоличествоВложенныхШтрихкодов;
КонецЕсли;
// ... расчет хеш-сумм и заполнение служебных полей
КонецПроцедуры
Обратите внимание на вызов процедуры РассчитатьКоличествоВложенныхШтрихкодов. Система игнорирует то значение, которое вы установили в реквизит Количество вручную в коде. Она берет данные из табличной части вложенных штрихкодов, проверяет их наличие в базе данных, определяет их тип и заново вычисляет итоговое количество. Если табличная часть заполнена неверно (строками вместо ссылок) или вложенные элементы еще не записаны в базу, функция вернет 0, который и будет записан в объект.
Для того чтобы данные корректно сохранились, необходимо соблюдать строгую последовательность действий. Представим, что нам нужно создать «Палет», внутри которого находятся две «Коробки» (или две единицы продукции). Правильный алгоритм действий (который также стоит учитывать, если вы реализуете перенос штрихкодов и упаковок между номенклатурой) будет выглядеть следующим образом:
Ссылка).ВложенныеШтрихкоды палета мы добавляем именно ссылки, полученные на шаге 2.РассчитатьКоличествоВложенныхШтрихкодов увидит в базе вложенные ссылки и корректно посчитает итоговое количество.Посмотрим на пример кода, реализующий этот подход:
// 1. Создаем первый вложенный код (например, потребительскую упаковку)
ЭлементВложенный1 = Справочники.ШтрихкодыУпаковокТоваров.СоздатьЭлемент();
ЭлементВложенный1.ЗначениеШтрихкода = "КодМаркировки1...";
ЭлементВложенный1.ТипУпаковки = Перечисления.ТипыУпаковок.МаркированныйТовар;
ЭлементВложенный1.Номенклатура = СсылкаНоменклатура;
ЭлементВложенный1.Записать();
// 2. Создаем второй вложенный код
ЭлементВложенный2 = Справочники.ШтрихкодыУпаковокТоваров.СоздатьЭлемент();
ЭлементВложенный2.ЗначениеШтрихкода = "КодМаркировки2...";
ЭлементВложенный2.ТипУпаковки = Перечисления.ТипыУпаковок.МаркированныйТовар;
ЭлементВложенный2.Номенклатура = СсылкаНоменклатура;
ЭлементВложенный2.Записать();
// 3. Создаем общую упаковку (Палет)
НовыйПалет = Справочники.ШтрихкодыУпаковокТоваров.СоздатьЭлемент();
НовыйПалет.ЗначениеШтрихкода = "КодПалета...";
НовыйПалет.ТипУпаковки = Перечисления.ТипыУпаковок.МонотоварнаяУпаковка;
НовыйПалет.Номенклатура = СсылкаНоменклатура;
// Добавляем в ТЧ ссылки на созданные ранее элементы
НоваяСтрока = НовыйПалет.ВложенныеШтрихкоды.Добавить();
НоваяСтрока.Штрихкод = ЭлементВложенный1.Ссылка;
НоваяСтрока = НовыйПалет.ВложенныеШтрихкоды.Добавить();
НоваяСтрока.Штрихкод = ЭлементВложенный2.Ссылка;
// Записываем палет. Теперь Количество заполнится автоматически как 2.
НовыйПалет.Записать();
Если в вашей специфической задаче автоматический расчет 1С работает некорректно (например, при сложной агрегации, данные о которой еще не полностью переданы в ГИС МТ), вы можете «обмануть» систему — упростить обмен поможет готовый модуль обмена с Честным Знаком. Для этого используется механизм ДополнительныеСвойства.
Ранее мы видели в коде ПередЗаписью проверку флага НеРассчитыватьКоличествоВложенныхШтрихкодов. Мы можем установить его программно перед вызовом Записать(). В этом случае 1С примет ваше значение реквизита Количество «как есть» и не будет пытаться его пересчитать.
НовыйПалет.Количество = НужноеМнеЧисло;
НовыйПалет.ДополнительныеСвойства.Вставить("НеРассчитыватьКоличествоВложенныхШтрихкодов", Истина);
НовыйПалет.Записать();
Однако будьте осторожны: использование этого флага возлагает на разработчика полную ответственность за консистентность данных. Если количество не будет соответствовать реальному числу строк в табличной части, это может вызвать ошибки в дальнейшем при отгрузке маркированной продукции или при проверках в ГИС МТ.
Выясним несколько важных технических нюансов, которые помогут избежать ошибок при интеграции:
ЗначениеШтрихкода всегда используйте типовые функции разбора. Коды DataMatrix часто содержат спецсимволы (например, GS1 Group Separator), которые визуально не видны, но важны для уникальности. Используйте РазборКодаМаркировкиИССлужебный.РазобратьКодМаркировки для получения чистого значения.Загрузка = Истина), обязательно вызывайте метод пересчета хеша, иначе сканеры на складе могут не распознать содержимое палета.ТипыУпаковок. Для конечного товара это всегда МаркированныйТовар. Для агрегатов — МонотоварнаяУпаковка (если внутри один артикул) или СоставнаяУпаковка (если внутри разные товары). Ошибки в этом поле блокируют возможность проведения документов «Маркировка товаров ИСМП».Справочники.ШтрихкодыУпаковокТоваров.НайтиПоРеквизиту("ЗначениеШтрихкода", ...).Таким образом, мы выяснили, что секрет успешной записи реквизитов кроется в правильной последовательности создания объектов и соблюдении типов данных в табличной части. Следуя этим правилам, вы сможете корректно автоматизировать процессы маркировки в вашей организации — для этого разработан модуль интеграции и печати этикеток маркировки.