Интеграция с системой Мониторинга движения лекарственных препаратов (МДЛП, она же «Честный знак» для фармы) на начальных этапах казалась разработчикам и системным администраторам настоящим техническим кошмаром. Огромный объем транзакций, строгие требования к сетевой безопасности, запутанные бизнес-процессы агрегирования и расформирования упаковок — все это требовало нестандартных архитектурных ходов. В рамках данной статьи мы подробно разберем, как решать ключевые проблемы интеграции, спроектировать надежную базу данных, правильно настроить торговое оборудование и обойти ограничения платформы 1С.
Давайте проанализируем ситуацию, с которой сталкивается крупный дистрибьютор или крупная аптечная сеть. При обороте в 30 миллионов упаковок в месяц база данных за год должна будет вместить сотни миллионов уникальных кодов маркировки (sGTIN). Если записывать каждый код непосредственно в стандартные регистры сведений или справочники информационной базы 1С, это неминуемо приведет к лавинообразному росту размера базы (на терабайты данных) и катастрофическому падению производительности СУБД.
Для решения этой проблемы рассмотрим гибридную архитектуру. Вместо хранения кодов в 1С мы выносим весь помарочный учет во внешнюю специализированную базу данных (например, на MS SQL Server или PostgreSQL), а в самой 1С храним только ссылки на документы и агрегированные идентификаторы пакетов. Наша система 1С будет общаться с внешней базой через механизмы ADO (ActiveX Data Objects) или посредством HTTP-запросов к специально написанному микросервису.
Ниже приведем практический пример кода на языке 1С, реализующий получение кодов sGTIN из внешней базы данных MS SQL для конкретного документа поступления:
// Функция выполняет запрос к внешней базе данных для получения списка sGTIN
Функция ПолучитьМаркиИзВнешнейБД(ИдентификаторДокумента1С) Экспорт
Соединение = Новый ADODB.Connection;
СтрокаПодключения = "Driver={SQL Server};Server=MdlpServerAddress;Database=MdlpStore;Uid=1c_integration;Pwd=SecurePassword123;";
Попытка
Соединение.Open(СтрокаПодключения);
Исключение
ЗаписатьЛогСобытий("Ошибка подключения к внешней БД МДЛП: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
Возврат Неопределено;
КонецПопытки;
ЗапросSQL = "
|SELECT sGTIN, CodeStatus
|FROM dbo.SgtinStorage
|WHERE DocUUID = '" + Строка(ИдентификаторДокумента1С) + "'";
НаборЗаписей = Новый ADODB.Recordset;
Попытка
НаборЗаписей = Соединение.Execute(ЗапросSQL);
Исключение
ЗаписатьЛогСобытий("Ошибка выполнения запроса к БД: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
Соединение.Close();
Возврат Неопределено;
КонецПопытки;
ТаблицаКодов = Новый ТаблицаЗначений;
ТаблицаКодов.Колонки.Добавить("sGTIN", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(27)));
ТаблицаКодов.Колонки.Добавить("Статус", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(50)));
Пока НЕ НаборЗаписей.EOF() Цикл
НоваяСтрока = ТаблицаКодов.Добавить();
НоваяСтрока.sGTIN = Строка(НаборЗаписей.Fields("sGTIN").Value);
НоваяСтрока.Статус = Строка(НаборЗаписей.Fields("CodeStatus").Value);
НаборЗаписей.MoveNext();
КонецЦикла;
Соединение.Close();
Возврат ТаблицаКодов;
КонецФункции
Такой подход позволяет разгрузить транзакционный контур 1С. При этом в самой конфигурации 1С мы дорабатываем только те места проведения документов, где требуется валидация наличия кодов, вызывая внешние функции проверки перед транзакцией записи.
Рассмотрим сетевые нюансы работы с API Честного Знака. На этапе тестирования и ранней интеграции разработчики часто сталкиваются с ошибками сетевого тайм-аута. Выясним причину: в целях защиты от DDoS-атак и несанкционированного доступа СУЗ (Станция управления заказами) и сам шлюз МДЛП могут требовать предварительной регистрации статического публичного IP-адреса вашей организации. Без внесения вашего IP-адреса в белый список на стороне сервера Честного Знака, ваши запросы будут просто отбрасываться файрволом («падать по тайм-ауту»). Поэтому перед началом программирования обязательно согласуйте со своим провайдером выделение белого статического IP-адреса и отправьте заявку на его регистрацию в техподдержку ЦРПТ.
Второй частый подводный камень — кодировка передаваемых файлов и сообщений. В официальных мануалах повсеместно декларируется стандарт UTF-8. Однако при интеграции с тестовыми контурами и при выгрузке некоторых файлов отчетов (особенно в формате CSV) вы можете столкнуться с кодировкой Windows-1251. Если ваше кассовое или складское ПО сформирует XML/JSON в неверной кодировке, сервер МДЛП вернет ошибку валидации схемы. Принудительно устанавливайте кодировку при формировании HTTP-запросов и файлов обмена в коде 1С, как показано далее:
// Пример правильной установки кодировки при отправке JSON-запроса в API МДЛП
Функция ОтправитьЗапросВМДЛП(АдресРесурса, ТелоЗапросаСтрока, ТокенАвторизации)
HTTPСоединение = Новый HTTPСоединение("api.mdlp.crpt.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
HTTPЗапрос = Новый HTTPRequest(АдресРесурса);
HTTPЗапрос.Заголовки.Вставить("Authorization", "Token " + ТокенАвторизации);
// Принудительно указываем UTF-8 для Content-Type
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Передаем строку, предварительно убедившись, что платформа 1С преобразует ее в UTF-8
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапросаСтрока, КодировкаТекста.UTF8, ИспользованиеМаркераПоследовательностиБайтов.НеИспользовать);
Попытка
Ответ = HTTPСоединение.ОтправитьДляОбъекта(HTTPЗапрос);
Возврат Ответ.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Исключение
ЗаписатьЛогСобытий("Ошибка HTTP-запроса: " + ОписаниеОшибки(), УровеньЖурналаРегистрации.Ошибка);
Возврат "";
КонецПопытки;
КонецФункции
Для корректного распознавания кодов DataMatrix на лекарственных упаковках обычные линейные 1D-сканеры не подходят. Необходим качественный 2D-сканер-имиджер. Практическим стандартом в фармацевтической отрасли стал сканер Honeywell Voyager 1450g благодаря оптимальному соотношению цены и качества распознавания замятых или блеклых кодов.
Рассмотрим пошагово процесс подготовки и программирования этого сканера для работы с 1С и МДЛП:
Проанализируем алгоритм обработки считанного штрихкода в коде 1С, учитывающий наличие скрытого разделителя GS:
// Функция разбирает считанный 2D-сканером код маркировки лекарственного средства
Функция РазобратьШтрихкодDataMatrix(Знач СчитанныйШтрихкод) Экспорт
Результат = Новый Структура;
Результат.Вставить("GTIN", "");
Результат.Вставить("СерийныйНомер", "");
Результат.Вставить("ОшибкаРазбора", Истина);
РазделительGS = Символ(29); // ASCII код 29
// В стандартном коде МДЛП первыми идут идентификаторы применения (AI): 01 (GTIN) и 21 (Серийный номер)
Если Лев(СчитанныйШтрихкод, 2) = "01" Тогда
Результат.GTIN = Сред(СчитанныйШтрихкод, 3, 14);
Если Сред(СчитанныйШтрихкод, 17, 2) = "21" Тогда
ОстатокСтроки = Сред(СчитанныйШтрихкод, 19);
ПозицияGS = Найти(ОстатокСтроки, РазделительGS);
Если ПозицияGS > 0 Тогда
Результат.СерийныйНомер = Лев(ОстатокСтроки, ПозицияGS - 1);
Иначе
// Если разделитель GS не найден, серийный номер может идти до конца строки
// Это бывает, если криптохвост отсутствует или сканер настроен некорректно
Результат.СерийныйНомер = ОстатокСтроки;
КонецЕсли;
Результат.ОшибкаРазбора = Ложь;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Для дистрибьюторов и крупных аптечных складов критически важна операция агрегирования (объединения индивидуальных sGTIN в групповые транспортные коробки и паллеты со своими уникальными кодами SSCC). Рассмотрим, как устроен этот процесс.
Приемка и отгрузка паллетами существенно ускоряет работу склада: вместо сканирования сотен отдельных пачек оператор сканирует один штрихкод SSCC, и система автоматически понимает, какие именно лекарства находятся внутри. Однако в реальной жизни происходят процессы расформирования (разагрегирования) коробок из-за брака, пересорта или частичной продажи. Система МДЛП позволяет расформировать коробку и собрать её заново с другим составом sGTIN под тем же самым или новым кодом SSCC.
Чтобы избежать путаницы в WMS-системе склада, настоятельно рекомендуем не пытаться хранить в 1С бесконечную историю изменения состава одной и той же коробки SSCC. При любой операции разагрегирования уничтожайте связь состава с этим SSCC в вашей базе данных, а при повторной упаковке генерируйте новый уникальный код SSCC. Это спасет вашу базу от коллизий данных и расхождения с реестром Честного Знака.
С технической и юридической точки зрения возврат лекарств имеет строгую специфику. По закону РФ качественные лекарственные препараты возврату не подлежат. Но что делать, если произошел ошибочный отпуск, или препарат оказался некачественным/бракованным?
Современные конфигурации 1С (такие как «1С:Розница. Аптека») полностью поддерживают необходимые бизнес-процессы возврата выведенных из оборота препаратов. При оформлении чека возврата на кассе, программа автоматически формирует уведомление по схеме 391 (возврат лекарственных препаратов в оборот). Этот документ подписывается УКЭП организации и отправляется в МДЛП. После подтверждения со стороны системы код маркировки снова становится активным и может быть повторно продан или списан по процедуре утилизации.
Интеграция с МДЛП — динамический процесс. С 2025 года для лекарственных средств вводится обязательный разрешительный режим на кассах. Если раньше кассовая программа просто отправляла отчет о выбытии постфактум, то теперь касса перед пробитием чека обязана в онлайн-режиме запросить МДЛП о статусе данного конкретного кода DataMatrix. Если сервер вернет информацию о том, что срок годности лекарства истек, код заблокирован государственными органами, или он уже был выведен из оборота ранее — кассовое ПО технически заблокирует продажу. Это требует от разработчиков 1С внедрения новых API-запросов онлайн-проверки и тонкой настройки таймаутов соединения, чтобы покупатели на кассах не стояли в очередях из-за зависших интернет-запросов.