Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
28 мар 2024, 15:54

О штрихкодировании документов

Автор mixqn, 10 июн 2016, 14:21

0 Пользователей и 1 гость просматривают эту тему.

mixqn



На написание данной статьи меня побудили 2 факта:

  • В очередной раз в новой организации столкнулся с проблемами при штрихкодировании документов. Подробнее суть проблем опишу ниже.
  • Тема форума https://forum-baza.ru/index.php?topic=62345.0
Оба эти факта лишний раз убедили меня в том, что задача штрихкодирования документов является в некотором смысле типовой и довольно таки распространенной. Поэтому я решил поделиться своим ноу-хау. Возможно, для кого-то это не станет открытием и где-то что-то подобное уже работает, и кто-то скажет, что я пытаюсь заново изобрести велосипед, но во всяком случае мне эта идея пришла без подсказок извне и на практике я пока этого подхода больше нигде не видел. Так что у меня возникло желание поделиться своими мыслями с 1С-собществом, возможно, кому-то это пригодится. Ну и здоровую критику никто не отменял, интересен будет любой отклик.

Начну я с наверно самого распространенного способа штрихкодирования – составление штрихкода «на лету» на основе параметров документа. Этот метод я называю «классическим». Основной принцип этого подхода заключается в том, что штрихкод (далее по тексту может использоваться сокращение ШК) формируется из некоторого набора ключевых полей, под каждое из которых отводится сколько-то символов. «Классический» вариант структуры штрихкода:

  • Код вида документа (заказ, реализация, доверенность и т.п.) – обычно от 1 до 3-х символов.
  • Код организации (по сути, замена кириллического префикса в номере документа) – обычно от 1 до 3-х символов.
  • Номер документа без префикса – от 6 до 9 символов.
  • Дата документа – от 6 до 8 символов в зависимости от варианта представления (год кодируется 2-мя или 4-мя цифрами).
В целом на первый взгляд все здорово: учли все многообразие видов документов, различные организации, нумерацию, дату - на выходе получим уникальный ШК, который однозначно идентифицирует документ. Но сразу же очевидны и минусы: при обработке штрихкода требуется его обратное преобразование, расшифровка, получение тех самых ключевых полей, который изначально в него зашифровали. И обычно никто не заморачивается на тему реализации универсального алгоритма, настраиваемого параметрически в пользовательском режиме. Хотя вообще то никто не мешает создать некую структуру данных с указанием соответствия цифрового кода объекту метаданных, в организациях можно добавить поле с названием например «код организации для штрихкода» и т.п. Обычно все делается на скорую руку и эти вещи полностью или частично описываются хардкодом. Ну то есть прямо в коде написано что-то типа:
ДокументТип = "000";
Если ТипЗнч(Документ)=Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
ДокументТип = "001";
ИначеЕсли ТипЗнч(Документ)=Тип("ДокументСсылка.ЗаказПокупателя") Тогда
ДокументТип = "002";
КонецЕсли;

К чему все это приводит? Очевидно: к тому, что при любом изменении набора ключевых параметров (как то необходимость вывести штрихкод на новый тип документа, появление новой организации и т.п.) нужно править код. А если есть еще и обмен с другими базами и там тоже нужен поиск документа по штрихкоду, то количество мест, где надо изменить код растет, а вместе с ним растет и вероятность ошибки – забыли адаптировать код, адаптировали но с ошибкой и т.д. и т.п.
Мало того. Бывает еще и такое, что например менеджер ошибся при заведении заказа в базу, указал не ту организацию, после чего зашел бухгалтер (ну или любой другой пользователь с соответствующими правами) и организацию изменил. Очевидно, что теперь при печати документа штрихкод будет уже совершенно другим и по ранее распечатанной бумаге документ в базе найти не удастся. В течение нескольких дней после изменения организации это может и не вызвать проблем, а через полгода кто вспомнит об этом случае?

Основная идея метода, который я предлагаю и который успешно используется в нескольких организациях заключается в следующем: штрихкод должен быть отдельным полем и он должен храниться в базе. Не нужно привязывать его ни к номеру ни к дате ни к другим полям, так как значения этих полей в принципе могут измениться. Понятно, что нужно гарантировать уникальность штрихкодов, поэтому добавление реквизита «штрихкод»  в документ – плохая идея. Да и к тому же выше я уже писал, что штрихкодировать надо разные виды документов – добавлять реквизит во все просто глупо. Очевидное решение: регистр сведений с единственным измерением типа строка – Штрихкод и ресурсом Документ составного типа. Можно указать фиксированный набор документов, либо же тип ДокументСсылка, либо вообще ЛюбаяСсылка. Явным преимуществом такой архитектуры является гарантия уникальности штрихкода на уровне платформы – ни при каких обстоятельствах не получится записать в базу 2 строки с одинаковым ШК и разными документами. Другой вопрос конечно, что можно изменить существующую запись (то есть фактически переприсвоить штрихкод другому документу и таким образом можно получить бумажные варианты 2-ух различных документов с одинаковым ШК ) – но тут уже вопрос ограничения прав доступа + грамотно написанный код, который не допустит такого развития событий.

Итак, архитектура понятна, теперь детали: как получить уникальный ШК? Можно конечно попробовать использовать просто сквозной нумератор, начать с 1 и каждый раз прибавлять на единичку – так тоже можно, но я решил использовать произвольный набор цифр. Точнее не совсем произвольный. ШК получается из уникального идентификатора документа, коим является GUID. Как известно, GUID состоит из 32 значимых символов (цифры и буквы латинского алфавита) + разделители (тире), общая длина 36 символов. По этой причине запихнуть в ШК весь GUID не представляется возможным – потому что на документе ШК заведомо ограниченного размера, могут возникнуть сложности при считывании столь длинного ШК. К тому же, если использовать кодировку GODE128, то количество штрихов на любые символы кроме цифр ровно в 2 раза больше, чем на кодирование цифры. Да и кроме того, ШК такой длины видится избыточным, обычно должно хватать 12-15 символов чтобы обеспечить запас для кодирования документов. Соответственно, решение такое: из GIUD убрать все кроме цифр. Полученный набор цифр довести до нужной длины. В зависимости от количества документов на единицу времени в организации обычно должно хватить 12-15 символов. Полученный таким образом ШК при помощи запроса предварительно проверяется на уникальность – ведь мы же обрезали GUID, уникальность которого гарантирована, стало быть, полученный обрезанный набор цифр уже может оказаться неуникальным и его надо предварительно проверить. Если проверка пройдена – отлично, мы получили искомый ШК, если нет – генерируем ШК на основе произвольного GUID до тех пор, пока не получим уникальный ШК. В конце статьи приведен код, который все это реализует. Сама запись штрихкода происходит по подписке на событие.

При обмене данными с другими системами передается так же и ШК в числе прочих полей. Кстати, учитывая, что ШК уникален, по нему можно вести синхронизацию. В базе-приемнике ШК может быть реквизитом документа. Естественно, уникальность ШК проверяется только в головной базе, база-приемник просто получает готовый ШК и сохраняет его.

О плюсах данного полхода. Главный плюс – это универсальность. Нет зависимости от количества организаций в базе, добавление штрихкодирования нового вида документов делается легко и просто. При желании, можно управлять этим параметрически в режиме пользователя – создать структуру данных, где будет храниться перечень документов, к которым нужно генерировать штрихкод. То же самое и при поиске документа по ШК – никакого разбора не требуется, ведется поиск на равенство, сам алгоритм поиска универсальный и не потребует доработок. При чем во всех базах, участвующих в обмене (опять таки, оговорюсь: при условии, что существует «головная» база, которая генерирует ШК и гарантирует их уникальность, в базах-приемниках ШК генерироваться не должны, только получаться вместе с обменом).

Исходный код:

Функция ПроверитьЗаписатьШтрихкодДокумента(СсылкаНаОбъект) Экспорт

Результат = Ложь;

// первое: получим штрихкод из GUID-а, чтобы сразу в запросе проверить его уникальность, дабы убрать лишний запрос к БД
GUID = СсылкаНаОбъект.УникальныйИдентификатор();
Штрихкод = ПодготовитьШтрихКодИзGIUDа(GUID);

// второе: проверяем наличие штрихкода, а так же уникальность кода в пакетном запросе
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ШтрихкодыДокументов.Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыДокументов КАК ШтрихкодыДокументов
|ГДЕ
| ШтрихкодыДокументов.Документ = &Документ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ШтрихкодыДокументов.Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыДокументов КАК ШтрихкодыДокументов
|ГДЕ
| ШтрихкодыДокументов.Штрихкод = &Штрихкод";

Запрос.УстановитьПараметр("Документ", СсылкаНаОбъект);
Запрос.УстановитьПараметр("Штрихкод", Штрихкод);

Результат = Запрос.ВыполнитьПакет();

ВыборкаДетальныеЗаписи = Результат[0].Выбрать();

Если ВыборкаДетальныеЗаписи.Следующий() Тогда
// штрихкод есть - возвращаем Истину
Возврат Истина
КонецЕсли;       

// третье: штрихкода нет - запишем
// сначала проверим ШК на основе GUID на уникальность:
ВыборкаУникальность = Результат[1].Выбрать();
Если ВыборкаУникальность.Следующий() Тогда
// ШК не уникален. генерируем новый
КодУникален = Ложь;
Пока НЕ КодУникален Цикл
Штрихкод = ПодготовитьШтрихКодИзGIUDа(Новый УникальныйИдентификатор);

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ШтрихкодыДокументов.Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыДокументов КАК ШтрихкодыДокументов
|ГДЕ
| ШтрихкодыДокументов.Штрихкод = &Штрихкод";

Запрос.УстановитьПараметр("Штрихкод", Штрихкод);
Результат = Запрос.Выполнить();
КодУникален = Результат.Пустой();
КонецЦикла;
КонецЕсли;

ЗаписьРегистра = РегистрыСведений.ШтрихкодыДокументов.СоздатьМенеджерЗаписи();
ЗаписьРегистра.Документ = СсылкаНаОбъект;
ЗаписьРегистра.Штрихкод = Штрихкод;
ЗаписьРегистра.GUID = GUID;
ЗаписьРегистра.ДатаСоздания = ТекущаяДата();
ЗаписьРегистра.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Попытка
ЗаписьРегистра.Записать();
Результат = Истина;
Исключение
Результат = Ложь;
КонецПопытки;

Возврат Результат;

КонецФункции

Функция ПодготовитьШтрихКодИзGIUDа(фGIUD, фДлина = 12)

фШтрихКод = фGIUD;

фШтрихКод = СтрЗаменить(фШтрихКод, "-", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "a", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "b", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "c", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "d", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "e", "");
фШтрихКод = СтрЗаменить(фШтрихКод, "f", "");

фШтрихКод = Лев(фШтрихКод, фДлина);

// на случай, если штрихкод оказался меньше нужной длины, дополняем его ведущими нулями
Пока СтрДлина(фШтрихКод) < фДлина Цикл
фШтрихКод = "0" + фШтрихКод;
КонецЦикла;

Возврат фШтрихКод;

КонецФункции //ШтрихКодНовый()

Еламан Мухамбетжанов

у меня такая проблема штихкод выводит на 1 лист 1 штрих код а мне нужно чтобы на 1 лист этикетки поместит 2 и более штих код как этим справиться

Теги:

Похожие темы (1)

Рейтинг@Mail.ru

Поиск