Как объединить несколько документов в один общий счет на оплату в 1С?

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

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

Анализируем постановку задачи

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

Вариант 1: Использование штатных механизмов типовых конфигураций

Рассмотрим, как эта задача решается в стандартных продуктах 1С, так как это лучший источник идей для собственной разработки. Во многих конфигурациях (например, в БП 3.0 или УТ 11) уже есть кнопки типа «Добавить из документа» или рабочие места для пакетного оформления документов.

  1. В документе-приемнике создается команда, открывающая форму выбора документов.
  2. Пользователь отмечает нужные документы одного и того же контрагента.
  3. Программа итерационно обходит табличные части выбранных объектов и копирует строки в текущий счет.

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

Вариант 2: Программная реализация объединения через объектную модель

Разберем по шагам, как программно собрать данные из нескольких документов. Предположим, у нас есть массив ссылок на документы-основания МассивОснований. Посмотрим на пример кода, который выполняет перенос данных:


// Очищаем текущую табличную часть перед заполнением
Объект.Товары.Очистить();

Для Каждого СсылкаНаДокумент Из МассивОснований Цикл
    // Проверяем, что контрагент совпадает
    Если СсылкаНаДокумент.Контрагент <> Объект.Контрагент Тогда
        Продолжить; // Или выводим предупреждение пользователю
    КонецЕсли;

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

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

Вариант 3: Объединение и свертка данных через таблицу значений

Чтобы счет выглядел аккуратно, одинаковые позиции лучше сгруппировать. Выясним, как это сделать максимально эффективно с помощью метода Свернуть. Для этого мы сначала выгрузим все данные во временную таблицу значений.


// Создаем временную таблицу для накопления данных
ТЗ = Объект.Товары.ВыгрузитьКолонки();

Для Каждого Док Из МассивОснований Цикл
    Для Каждого Стр Из Док.Товары Цикл
        НоваяСтр = ТЗ.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтр, Стр);
    КонецЦикла;
КонецЦикла;

// Группируем данные по ключевым полям, суммируя количество и сумму
ТЗ.Свернуть("Номенклатура, Цена, СтавкаНДС, ЕдиницаИзмерения", "Количество, Сумма, СуммаНДС");

// Загружаем результат обратно в документ
Объект.Товары.Загрузить(ТЗ);

Важный нюанс: при свертке нельзя использовать поля, которые уникальны для каждой строки (например, номер строки или специфическое содержание), иначе группировка не сработает.

Вариант 4: Использование запроса для сбора данных

Рассмотрим более профессиональный подход — использование объекта Запрос. Это работает быстрее, если документов много, и позволяет сразу отсеять ненужные данные (например, помеченные на удаление или непроведенные документы).

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


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

Запрос.УстановитьПараметр("МассивСсылок", МассивОснований);
РезультатЗапроса = Запрос.Выполнить();
Объект.Товары.Загрузить(РезультатЗапроса.Выгрузить());

Архитектурные советы по хранению связей

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

Контрольные проверки при объединении

Выясним причину возможных ошибок при слиянии документов. Перед записью итогового счета обязательно выполним следующие проверки:

  1. Валюта: Нельзя объединять документы в рублях и долларах в один рублевый счет без пересчета курсов.
  2. Налогообложение: Убедимся, что все исходные документы имеют одинаковую настройку НДС (сверху или в сумме).
  3. Тип цен: Если в счете должна быть единая колонка «Цена», проверьте соответствие цен в исходных заказах.

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

← На главную