В процессе автоматизации аптечной деятельности или складского учета лекарственных средств (ЛС) специалисты часто сталкиваются с проблемой: при сканировании кода с упаковки в строке не оказывается явных данных о номере партии или сроке годности. Давайте разберем, как устроена маркировка лекарств, почему коды могут различаться по длине и как правильно реализовать парсинг этой строки в 1С.
Прежде всего, проанализируем терминологию. То, что часто называют «QR-кодом» на упаковках таблеток, на самом деле является кодом DataMatrix. В отличие от обычного QR-кода, DataMatrix позволяет упаковать большой объем информации на очень маленькой площади, что критично для ампул и небольших пачек. В фармацевтике используется стандарт GS1 DataMatrix, который строго регламентирует структуру данных внутри кода.
Данные в коде маркировки не идут случайным потоком. Они разделены на блоки, каждый из которых начинается с двухзначного (иногда трех- или четырехзначного) префикса — идентификатора применения (Application Identifier, AI). Рассмотрим основные префиксы, которые встречаются в маркировке ЛС:
Проанализируем ситуацию, описанную в теме: сканер выдает строку 010460367900592321DLO0000119895. Разберем ее по частям:
01 (префикс) + 04603679005923 (GTIN товара);21 (префикс) + DLO0000119895 (Серийный номер упаковки).Как мы видим, в этом коде физически отсутствуют идентификаторы 10 (партия) и 17 (срок годности). Это так называемый «короткий код» или SGTIN. В этом случае производитель зашифровал в DataMatrix только идентификатор товара и индивидуальный номер пачки.
Выясним причину, почему на сайте информационной системы (ЭБД ЛС или МДЛП) данные о партии при этом отображаются. Все дело в облачной базе данных. Когда вы сканируете SGTIN, ваша учетная программа (1С) должна отправить запрос в государственную информационную систему. Система находит у себя запись: «Упаковка с серийным номером DLO0000119895 принадлежит партии 280425 со сроком годности до 2027-03-31». Таким образом, информация «подтягивается» из внешнего реестра, а не из самого кода.
Одной из самых частых технических проблем является игнорирование символа Group Separator (GS), который соответствует коду ASCII 29. Он используется в GS1 DataMatrix для отделения полей переменной длины (например, серийного номера) от следующих за ними данных.
Если серийный номер имеет переменную длину, а за ним идет номер партии, без разделителя GS программа не поймет, где заканчивается один блок и начинается другой. Чтобы 1С «видела» этот символ, необходимо:
Рассмотрим пример функции, которая может разбирать строку DataMatrix, учитывая идентификаторы применения. Помним, что идентификаторы 01 и 17 имеют фиксированную длину, а 21 и 10 — переменную (до встречи символа GS или конца строки).
Функция РазобратьКодМаркировки(Знач СтрКода) Экспорт
Результат = Новый Структура("GTIN, Серия, Партия, СрокГодности", "", "", "", "");
// Очистим строку от возможных спецсимволов в начале
СтрКода = Сред(СтрКода, 1);
ТекущаяПозиция = 1;
Пока ТекущаяПозиция <= СтрДлина(СтрКода) Цикл
Идентификатор = Сред(СтрКода, ТекущаяПозиция, 2);
Если Идентификатор = "01" Тогда // GTIN
Результат.GTIN = Сред(СтрКода, ТекущаяПозиция + 2, 14);
ТекущаяПозиция = ТекущаяПозиция + 16;
ИначеЕсли Идентификатор = "21" Тогда // Серийный номер
// Ищем разделитель GS (Символ с кодом 29)
ПозРазделителя = Найти(Сред(СтрКода, ТекущаяПозиция + 2), Символ(29));
Если ПозРазделителя = 0 Тогда // Разделителя нет, значит данные до конца строки
Результат.Серия = Сред(СтрКода, ТекущаяПозиция + 2);
ТекущаяПозиция = СтрДлина(СтрКода) + 1;
Иначе
Результат.Серия = Сред(СтрКода, ТекущаяПозиция + 2, ПозРазделителя - 1);
ТекущаяПозиция = ТекущаяПозиция + 2 + ПозРазделителя;
КонецЕсли;
ИначеЕсли Идентификатор = "17" Тогда // Срок годности (ГГММДД)
СрокСтрокой = Сред(СтрКода, ТекущаяПозиция + 2, 6);
Результат.СрокГодности = "20" + Лев(СрокСтрокой, 2) + "-" + Сред(СрокСтрокой, 3, 2) + "-" + Прав(СрокСтрокой, 2);
ТекущаяПозиция = ТекущаяПозиция + 8;
ИначеЕсли Идентификатор = "10" Тогда // Партия
ПозРазделителя = Найти(Сред(СтрКода, ТекущаяПозиция + 2), Символ(29));
Если ПозРазделителя = 0 Тогда
Результат.Партия = Сред(СтрКода, ТекущаяПозиция + 2);
ТекущаяПозиция = СтрДлина(СтрКода) + 1;
Иначе
Результат.Партия = Сред(СтрКода, ТекущаяПозиция + 2, ПозРазделителя - 1);
ТекущаяПозиция = ТекущаяПозиция + 2 + ПозРазделителя;
КонецЕсли;
Иначе
// Прочие идентификаторы (криптохвост и т.д.) пропускаем или обрабатываем аналогично
ТекущаяПозиция = ТекущаяПозиция + 1;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Если после работы функции парсинга поля Партия и СрокГодности остались пустыми, проанализируем следующий алгоритм действий:
SGTIN (комбинация GTIN + Серия).Таким образом, полноценная работа с маркировкой лекарств требует не только умения разбирать текстовую строку, но и настроенного взаимодействия с внешними информационными системами. Помните, что код на упаковке — это лишь «ключ», который открывает доступ к полной карточке товара в государственном реестре.