Как реализовать заполнение документа Монтаж на основании Заказа покупателя с пересчетом стоимости

Программист 1С v8.3 (Управляемые формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Разбор архитектуры решения

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

Вариант 1: Использование объектной техники (перебор строк)

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

Для реализации этого метода в модуле объекта документа Монтаж напишем следующий код:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    // Проверяем, что основанием является именно Заказ покупателя
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
        
        // Заполняем шапку документа
        Контрагент = ДанныеЗаполнения.Контрагент;
        Организация = ДанныеЗаполнения.Организация;
        
        // Начинаем перебор строк табличной части "Товары"
        Для Каждого ТекСтрокаТовары Из ДанныеЗаполнения.Товары Цикл
            
            НоваяСтрока = Товары.Добавить();
            // Копируем стандартные реквизиты
            ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрокаТовары);
            
            // Обращаемся к реквизиту "Монтаж" через ссылку на Номенклатуру
            // Предположим, что нам нужно рассчитать 40% от значения в справочнике
            Если ЗначениеЗаполнено(ТекСтрокаТовары.Номенклатура) Тогда
                ЗначениеИзСправочника = ТекСтрокаТовары.Номенклатура.Монтаж;
                
                // Выполняем расчет (умножаем на 0.4 для получения 40% или на 1.4 для наценки)
                НоваяСтрока.СуммаМонтажа = ЗначениеИзСправочника * 0.4;
            КонецЕсли;
            
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Важный момент: Использование конструкции ТекСтрокаТовары.Номенклатура.Монтаж внутри цикла — это простое, но не самое оптимальное решение. В 1С это называется "обращением через точку". Проблема заключается в том, что при каждой итерации цикла система будет делать отдельный запрос к базе данных, чтобы получить значение из справочника. Если в заказе 100 строк, система сделает 100 лишних микро-запросов. Для оптимизации лучше использовать запросы.

Вариант 2: Оптимизированное заполнение через запрос

Проанализируем ситуацию с точки зрения производительности. Чтобы избежать лишних обращений к серверу БД, мы можем одним запросом получить все необходимые данные из табличной части заказа и сразу «подтянуть» значение реквизита Монтаж из справочника номенклатуры. Рассмотрим, как это сделать.


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЗаказТовары.Номенклатура КАК Номенклатура,
        |   ЗаказТовары.Количество КАК Количество,
        |   ЗаказТовары.Номенклатура.Монтаж КАК МонтажБазовый,
        |   ЗаказТовары.ЕдиницаИзмерения КАК ЕдиницаИзмерения
        |ИЗ
        |   Документ.ЗаказПокупателя.Товары КАК ЗаказТовары
        |ГДЕ
        |   ЗаказТовары.Ссылка = &СсылкаОснование";
        
        Запрос.УстановитьПараметр("СсылкаОснование", ДанныеЗаполнения);
        
        РезультатЗапроса = Запрос.Выполнить();
        Выборка = РезультатЗапроса.Выбрать();
        
        Пока Выборка.Следующий() Цикл
            НоваяСтрока = Товары.Добавить();
            НоваяСтрока.Номенклатура = Выборка.Номенклатура;
            НоваяСтрока.Количество = Выборка.Количество;
            НоваяСтрока.ЕдиницаИзмерения = Выборка.ЕдиницаИзмерения;
            
            // Выполняем расчет 40% сразу при заполнении
            НоваяСтрока.ЦенаМонтажа = Выборка.МонтажБазовый * 0.4;
            НоваяСтрока.Сумма = НоваяСтрока.ЦенаМонтажа * НоваяСтрока.Количество;
        КонецЦикла;
        
        // Заполнение шапки
        Контрагент = ДанныеЗаполнения.Контрагент;
        
    КонецЕсли;
    
КонецПроцедуры

Этот метод считается профессиональным стандартом в 1С. Мы получаем готовую таблицу данных за одно обращение к серверу. Обратите внимание, что расчет суммы можно производить как непосредственно в запросе, так и при обходе выборки.

Нюансы перехода между обычными и управляемыми формами

Поскольку документ Монтаж использует управляемую форму, а ЗаказПокупателя — обычную, нам нужно учитывать контекст выполнения. Код в ОбработкаЗаполнения работает на сервере, поэтому тип формы основания не имеет значения — ссылка на документ передается корректно. Однако, если после заполнения требуется интерактивное действие (например, открытие формы), следует убедиться, что все реквизиты, необходимые для логики формы (например, Дата, Склад, Валюта), также заполнены в модуле объекта.

Рассмотрим дополнительные рекомендации по работе в УПП:

  1. Проверка типов данных: Если реквизит Монтаж в справочнике Номенклатура имеет тип, отличный от Числа (например, Ссылка), то прямое умножение на 0.4 вызовет ошибку. Всегда проверяйте тип в конфигураторе.
  2. Пересчет итогов: В управляемых формах после программного добавления строк в табличную часть может потребоваться вызов серверной процедуры для пересчета итогов по документу (НДС, Сумма документа). Это лучше делать в модуле формы в обработчике ПриСозданииНаСервере, если данные заполнялись через ОбработкаЗаполнения.
  3. Использование типовых функций: В УПП есть множество общих модулей, таких как ОбщегоНазначения или ОбработкаТабличныхЧастей. Если вам нужно рассчитать НДС от полученной суммы монтажа, лучше использовать экспортные функции этих модулей, чтобы расчет соответствовал учетной политике организации.

Заключение

Мы выяснили, что для решения задачи оптимально использовать запрос к табличной части документа-основания с левым соединением к справочнику Номенклатура. Это обеспечивает высокую скорость работы системы даже при больших объемах данных в заказах. Не забывайте обрабатывать возможные пустые значения (NULL) в запросе или проверять значения на заполненность перед математическими операциями, чтобы избежать ошибок рантайма.

← На главную