Как реализовать автоматическую генерацию уникальных номеров партий в 1С:УНФ?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой Управленческий учет Торговля и дистрибуция
← На главную

В процессе автоматизации учета в конфигурации 1С:Управление нашей фирмой (УНФ) часто возникает задача обеспечения сквозной прослеживаемости товаров. Одной из ключевых подзадач здесь является автоматическая генерация уникальных номеров партий или серий для каждой строки документа поступления или заказа. Рассмотрим подробно, как реализовать этот механизм, обеспечив уникальность и корректную структуру данных.

Архитектурный подход: связь партии с документом

Прежде чем приступать к написанию кода, проанализируем структуру данных. Для того чтобы номера партий были уникальными и их было легко искать в контексте конкретной поставки, рекомендуется добавить в справочник ПартииНоменклатуры дополнительный реквизит. Назовем его, например, ДокументОснование (тип: ссылка на ваш документ, например, ЗаказПокупателя или ПриходнаяНакладная).

Почему это важно? Поиск по текстовому наименованию в базе данных — операция медленная и ненадежная (из-за возможного изменения даты или номера документа). Наличие прямой ссылки на объект-основание позволяет мгновенно отобрать все партии, созданные конкретным документом, и вычислить следующий порядковый номер.

Разработка процедуры генерации партий на сервере

Рассмотрим основной алгоритм, который будет обходить табличную часть документа, проверять заполнение партий и создавать новые элементы справочника. Проанализируем пример кода, который выполняет эти действия в рамках одной транзакции:


&НаСервере
Процедура АМ_СгенерироватьПартииНаСервере()
    
    ВладелецПартии = Неопределено; // Можно уточнить владельца, если требуется
    СтатусПартии = Перечисления.СтатусыПартий.СобственныеЗапасы;
    
    // Формируем базовую часть наименования на основе номера и даты
    НомерДок = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(Объект.Номер, Истина, Истина);
    ДатаДок = СокрЛП(Формат(Объект.Дата,"ДФ=ddMMyyyy"));
    НаименованиеШаблон = НомерДок + "(" + ДатаДок + ")";
    
    НачатьТранзакцию();
    Попытка
        Для каждого Строка Из Объект.Запасы Цикл
            // Проверяем, нужно ли создавать партию для данной строки
            Если Не ЗначениеЗаполнено(Строка.Партия) И ЗначениеЗаполнено(Строка.Номенклатура) Тогда
                
                // Здесь мы должны вычислить уникальный суффикс (номер) для партии
                НовыйНомер = ПолучитьСледующийНомерПартии(Объект.Ссылка, НаименованиеШаблон);
                ПолноеНаименование = НаименованиеШаблон + "_" + НовыйНомер;
                
                НоваяПартия = СоздатьПартиюНоменклатуры(Строка.Номенклатура, ВладелецПартии, СтатусПартии, ПолноеНаименование);
                
                Если ЗначениеЗаполнено(НоваяПартия) Тогда
                    Строка.Партия = НоваяПартия;
                КонецЕсли;
            КонецЕсли;
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
        Модифицированность = Истина;
    Исключение
        ОтменитьТранзакцию();
        // Сообщить об ошибке пользователю
    КонецПопытки;

КонецПроцедуры

Реализация функции создания элемента справочника

Разберем вспомогательную функцию СоздатьПартиюНоменклатуры. Важно помнить, что в 1С:УНФ работа с партиями может быть выключена для конкретной номенклатуры. Программа должна автоматически включать этот признак, если мы хотим вести партионный учет.


&НаСервере
Функция СоздатьПартиюНоменклатуры(Номенклатура, ВладелецПартии, СтатусПартии, НаименованиеПартии)
    
    // Сначала убедимся, что у номенклатуры включен учет по партиям
    Если Не Номенклатура.ИспользоватьПартии Тогда
        ОбъектНоменклатура = Номенклатура.ПолучитьОбъект();
        ОбъектНоменклатура.ИспользоватьПартии = Истина;
        Попытка
            ОбъектНоменклатура.Записать();
        Исключение
            Возврат Неопределено;
        КонецПопытки;
    КонецЕсли;

    // Создаем непосредственно элемент справочника Партии
    НоваяПартия = Справочники.ПартииНоменклатуры.СоздатьЭлемент();
    НоваяПартия.Владелец = Номенклатура; // В УНФ владельцем партии является Номенклатура
    НоваяПартия.Статус = СтатусПартии;
    НоваяПартия.Наименование = НаименованиеПартии;
    
    // Добавляем ссылку на документ для последующего поиска (если реквизит добавлен)
    // НоваяПартия.ДокументОснование = Объект.Ссылка; 
    
    Попытка
        НоваяПартия.Записать();
        Возврат НоваяПартия.Ссылка;
    Исключение
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

Поиск уникального номера и работа с шаблонами

Выясним, как гарантировать уникальность номера в пределах одного документа. Нам потребуется запрос, который найдет уже существующие партии, созданные этим документом, и определит максимальный порядковый номер. Рассмотрим пример запроса с использованием оператора ПОДОБНО:


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

Важные нюансы и рекомендации

Проанализируем критические моменты, которые могут повлиять на стабильность работы данного механизма:

  1. Блокировка данных: В многопользовательской среде два пользователя могут одновременно запустить генерацию. Чтобы избежать дублей, перед выполнением запроса на получение номера следует установить исключительную блокировку на справочник ПартииНоменклатуры через объект БлокировкаДанных.
  2. Оптимизация запроса: Использование оператора ПОДОБНО с процентом в конце ("Название_%") позволяет SQL-серверу использовать индексы. Однако если вы добавите процент в начало ("%Название"), запрос станет крайне медленным. Поэтому всегда придерживайтесь структуры Префикс + УникальныйНомер.
  3. Серийные номера: Если ваша задача требует учета каждого конкретного экземпляра (например, электроника с серийными номерами), рассмотрите использование штатного механизма Серии в 1С:УНФ. Он уже содержит отчеты по движению каждой единицы товара, что избавляет от необходимости «раздувать» справочник партий.
  4. Транзакционность: Всегда оборачивайте цикл создания партий в НачатьТранзакцию() ... ЗафиксироватьТранзакцию(). Это гарантирует, что если на 10-й строке произойдет ошибка, то первые 9 партий не останутся «висеть» в базе как мусор, а вся операция будет отменена.
  5. Префиксы для РИБ: Если вы работаете в распределенной базе данных, обязательно добавляйте префикс узла в номер партии. Это предотвратит коллизии, когда в двух разных филиалах создаются партии с одинаковыми номерами.

Таким образом, мы рассмотрели комплексный подход к генерации уникальных номеров. Сочетание привязки к документу-основанию и грамотного поиска по шаблону позволяет создать надежную систему прослеживаемости продукции от момента закупки или производства до реализации конечному клиенту.

← На главную