В процессе автоматизации учета в конфигурации 1С:Управление нашей фирмой (УНФ) часто возникает задача обеспечения сквозной прослеживаемости товаров. Одной из ключевых подзадач здесь является автоматическая генерация уникальных номеров партий или серий для каждой строки документа поступления или заказа. Рассмотрим подробно, как реализовать этот механизм, обеспечив уникальность и корректную структуру данных.
Прежде чем приступать к написанию кода, проанализируем структуру данных. Для того чтобы номера партий были уникальными и их было легко искать в контексте конкретной поставки, рекомендуется добавить в справочник ПартииНоменклатуры дополнительный реквизит. Назовем его, например, ДокументОснование (тип: ссылка на ваш документ, например, ЗаказПокупателя или ПриходнаяНакладная).
Почему это важно? Поиск по текстовому наименованию в базе данных — операция медленная и ненадежная (из-за возможного изменения даты или номера документа). Наличие прямой ссылки на объект-основание позволяет мгновенно отобрать все партии, созданные конкретным документом, и вычислить следующий порядковый номер.
Рассмотрим основной алгоритм, который будет обходить табличную часть документа, проверять заполнение партий и создавать новые элементы справочника. Проанализируем пример кода, который выполняет эти действия в рамках одной транзакции:
&НаСервере
Процедура АМ_СгенерироватьПартииНаСервере()
ВладелецПартии = Неопределено; // Можно уточнить владельца, если требуется
СтатусПартии = Перечисления.СтатусыПартий.СобственныеЗапасы;
// Формируем базовую часть наименования на основе номера и даты
НомерДок = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(Объект.Номер, Истина, Истина);
ДатаДок = СокрЛП(Формат(Объект.Дата,"ДФ=ddMMyyyy"));
НаименованиеШаблон = НомерДок + "(" + ДатаДок + ")";
НачатьТранзакцию();
Попытка
Для каждого Строка Из Объект.Запасы Цикл
// Проверяем, нужно ли создавать партию для данной строки
Если Не ЗначениеЗаполнено(Строка.Партия) И ЗначениеЗаполнено(Строка.Номенклатура) Тогда
// Здесь мы должны вычислить уникальный суффикс (номер) для партии
НовыйНомер = ПолучитьСледующийНомерПартии(Объект.Ссылка, НаименованиеШаблон);
ПолноеНаименование = НаименованиеШаблон + "_" + НовыйНомер;
НоваяПартия = СоздатьПартиюНоменклатуры(Строка.Номенклатура, ВладелецПартии, СтатусПартии, ПолноеНаименование);
Если ЗначениеЗаполнено(НоваяПартия) Тогда
Строка.Партия = НоваяПартия;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();
Модифицированность = Истина;
Исключение
ОтменитьТранзакцию();
// Сообщить об ошибке пользователю
КонецПопытки;
КонецПроцедуры
Разберем вспомогательную функцию СоздатьПартиюНоменклатуры. Важно помнить, что в 1С:УНФ работа с партиями может быть выключена для конкретной номенклатуры. Программа должна автоматически включать этот признак, если мы хотим вести партионный учет.
&НаСервере
Функция СоздатьПартиюНоменклатуры(Номенклатура, ВладелецПартии, СтатусПартии, НаименованиеПартии)
// Сначала убедимся, что у номенклатуры включен учет по партиям
Если Не Номенклатура.ИспользоватьПартии Тогда
ОбъектНоменклатура = Номенклатура.ПолучитьОбъект();
ОбъектНоменклатура.ИспользоватьПартии = Истина;
Попытка
ОбъектНоменклатура.Записать();
Исключение
Возврат Неопределено;
КонецПопытки;
КонецЕсли;
// Создаем непосредственно элемент справочника Партии
НоваяПартия = Справочники.ПартииНоменклатуры.СоздатьЭлемент();
НоваяПартия.Владелец = Номенклатура; // В УНФ владельцем партии является Номенклатура
НоваяПартия.Статус = СтатусПартии;
НоваяПартия.Наименование = НаименованиеПартии;
// Добавляем ссылку на документ для последующего поиска (если реквизит добавлен)
// НоваяПартия.ДокументОснование = Объект.Ссылка;
Попытка
НоваяПартия.Записать();
Возврат НоваяПартия.Ссылка;
Исключение
Возврат Неопределено;
КонецПопытки;
КонецФункции
Выясним, как гарантировать уникальность номера в пределах одного документа. Нам потребуется запрос, который найдет уже существующие партии, созданные этим документом, и определит максимальный порядковый номер. Рассмотрим пример запроса с использованием оператора ПОДОБНО:
&НаСервере
Функция ПолучитьСледующийНомерПартии(ДокументСсылка, СтрокаШаблона)
// Подготавливаем шаблон для поиска в SQL: добавляем символ процента для поиска всех совпадений
ПоискПоШаблону = СтрокаШаблона + "_%";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ПартииНоменклатуры.Наименование КАК Наименование
|ИЗ
| Справочник.ПартииНоменклатуры КАК ПартииНоменклатуры
|ГДЕ
| ПартииНоменклатуры.Наименование ПОДОБНО &Шаблон
| И ПартииНоменклатуры.ПометкаУдаления = ЛОЖЬ
|УПОРЯДОЧИТЬ ПО
| ПартииНоменклатуры.Наименование УБЫВ";
Запрос.УстановитьПараметр("Шаблон", ПоискПоШаблону);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
// Извлекаем число после последнего подчеркивания и увеличиваем его
ПоследнееИмя = Выборка.Наименование;
ПозицияПодчеркивания = СтрНайти(ПоследнееИмя, "_", НаправлениеПоиска.СКонца);
ЧислоСтрокой = Сред(ПоследнееИмя, ПозицияПодчеркивания + 1);
Попытка
ПоследнийНомер = Число(ЧислоСтрокой);
Исключение
ПоследнийНомер = 0;
КонецПопытки;
Возврат Формат(ПоследнийНомер + 1, "ЧГ=0");
Иначе
// Если партий еще нет, начинаем с единицы
Возврат "1";
КонецЕсли;
КонецФункции
Проанализируем критические моменты, которые могут повлиять на стабильность работы данного механизма:
ПартииНоменклатуры через объект БлокировкаДанных.ПОДОБНО с процентом в конце ("Название_%") позволяет SQL-серверу использовать индексы. Однако если вы добавите процент в начало ("%Название"), запрос станет крайне медленным. Поэтому всегда придерживайтесь структуры Префикс + УникальныйНомер.НачатьТранзакцию() ... ЗафиксироватьТранзакцию(). Это гарантирует, что если на 10-й строке произойдет ошибка, то первые 9 партий не останутся «висеть» в базе как мусор, а вся операция будет отменена.Таким образом, мы рассмотрели комплексный подход к генерации уникальных номеров. Сочетание привязки к документу-основанию и грамотного поиска по шаблону позволяет создать надежную систему прослеживаемости продукции от момента закупки или производства до реализации конечному клиенту.