Как организовать добавление нескольких строк в документ 1С при выполнении разных условий

Программист 1С v8.3 (Обычные формы)
← На главную

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

Анализ проблемы: почему ИначеЕсли не подходит

Рассмотрим ситуацию, описанную автором темы. В коде проверяются несколько полей (M1, M2, N1 и т.д.). Если значение в поле больше нуля, в документ должна добавиться строка с соответствующей номенклатурой. Автор использовал конструкцию Если ... ИначеЕсли ... КонецЕсли.

Проанализируем логику работы этого оператора: программа проверяет первое условие, и если оно истинно, выполняет блок кода и выходит из всей конструкции. Даже если условия для M2 или N3 тоже верны, система до них просто не дойдет. Выясним причину ошибки автора при попытке разделить условия: если оставить команду Добавить() вне блоков Если, то будет создана только одна строка, которая будет перезаписываться при каждом срабатывании условия, а в итоге в документе окажется результат только последней проверки.

Решение 1: Использование независимых блоков Если

Чтобы система проверила каждое условие независимо от того, сработало ли предыдущее, мы должны использовать последовательные блоки Если ... КонецЕсли. При этом создание новой строки Добавить() должно происходить строго внутри каждого блока. Посмотрим на правильную структуру кода:


// Правильный подход с независимыми проверками
Если стр.M1 > 0 Тогда
    СтрКомисиионера = НовыйДокумент.Услуги.Добавить();
    СтрКомисиионера.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00-00000019");
    СтрКомисиионера.Количество = стр.M1;
    СтрКомисиионера.Цена = стр.Контрагент.M1;
КонецЕсли;

Если стр.M2 > 0 Тогда
    СтрКомисиионера = НовыйДокумент.Услуги.Добавить();
    СтрКомисиионера.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00-00000023");
    СтрКомисиионера.Количество = стр.M2;
    СтрКомисиионера.Цена = стр.Контрагент.M2;
КонецЕсли;

Если стр.N3 > 0 Тогда
    СтрКомисиионера = НовыйДокумент.Услуги.Добавить();
    СтрКомисиионера.Номенклатура = Справочники.Номенклатура.НайтиПоКоду("00-00000025");
    СтрКомисиионера.Количество = стр.N3;
    СтрКомисиионера.Цена = стр.Контрагент.N3;
КонецЕсли;

В данном примере, если у объекта заполнены и M1, и N3, в документ будут добавлены две разные строки. Это решает основную задачу автора.

Решение 2: Оптимизация через универсальную процедуру (DRY)

Код выше содержит много дублирований (Copy-Paste). Согласно принципу Don't Repeat Yourself, повторяющиеся действия лучше вынести в отдельный алгоритм. Проанализируем, что меняется в каждом блоке: это только имя поля и код номенклатуры. Мы можем создать вспомогательную процедуру или использовать общую логику заполнения.


// Пример оптимизации заполнения
Процедура ДобавитьСтрокуЕслиНужно(ТабличнаяЧасть, ЗначениеПоля, ЦенаПоля, КодНоменклатуры)
    Если ЗначениеПоля > 0 Тогда
        НоваяСтрока = ТабличнаяЧасть.Добавить();
        НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоКоду(КодНоменклатуры);
        НоваяСтрока.Количество = ЗначениеПоля;
        НоваяСтрока.Цена = ЦенаПоля;
    КонецЕсли;
КонецПроцедуры

// Вызов в основном цикле
ДобавитьСтрокуЕслиНужно(НовыйДокумент.Услуги, стр.M1, стр.Контрагент.M1, "00-00000019");
ДобавитьСтрокуЕслиНужно(НовыйДокумент.Услуги, стр.M2, стр.Контрагент.M2, "00-00000023");

Решение 3: Проблема производительности (Поиск в цикле)

Важный технический нюанс: использование НайтиПоКоду внутри цикла — это «антипаттерн». Каждый такой вызов провоцирует отдельный запрос к базе данных. Если строк в документе много, это критически замедлит работу системы. Профессиональный подход подразумевает предварительную подготовку данных.

Разберем по шагам, как оптимизировать поиск:

  1. Создадим массив всех кодов номенклатуры, которые участвуют в алгоритме.
  2. Одним запросом найдем все ссылки на эти объекты и поместим их в Соответствие (ключ — код, значение — ссылка).
  3. В цикле будем получать готовую ссылку из Соответствие, не обращаясь к базе.

// Оптимизированный поиск номенклатуры
Коды = Новый Массив;
Коды.Добавить("00-00000019");
Коды.Добавить("00-00000023");
// ... добавить остальные коды

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка, Код ИЗ Справочник.Номенклатура ГДЕ Код В (&Коды)";
Запрос.УстановитьПараметр("Коды", Коды);
Выборка = Запрос.Выполнить().Выбрать();

КэшНоменклатуры = Новый Соответствие;
Пока Выборка.Следующий() Цикл
    КэшНоменклатуры.Вставить(Выборка.Код, Выборка.Ссылка);
КонецЦикла;

// Теперь в цикле используем:
НоменклатураСсылка = КэшНоменклатуры.Получить("00-00000019");
Если НоменклатураСсылка <> Неопределено И НЕ НоменклатураСсылка.Пустая() Тогда
    // Заполняем строку...
КонецЕсли;

Решение 4: Повышение надежности (Отказ от кодов)

В ходе обсуждения на форуме возник важный вопрос: насколько надежно искать номенклатуру по коду? Код может изменить администратор или пользователь, и алгоритм «сломается». Рассмотрим альтернативы:

  1. Предопределенные элементы: Если номенклатура создается в конфигураторе как предопределенная, мы можем обращаться к ней напрямую: Справочники.Номенклатура.Доставка. Это самый надежный способ для системных элементов.
  2. Дополнительные реквизиты или свойства: Можно пометить нужную номенклатуру специальным признаком в режиме «1С:Предприятие» и искать по этому признаку.
  3. Регистр сведений (Настройки): Создадим регистр «Настройки заполнения», где свяжем идентификатор (например, "Услуга_М1") с конкретной ссылкой на номенклатуру. Это позволит пользователю самому менять товар для подстановки без правки программного кода.

Итоги

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

← На главную