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

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

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

Способ 1. Использование метода НайтиСтроки для поиска и суммирования

Рассмотрим классический программный алгоритм обхода строк. Для проверки наличия номенклатуры в целевой табличной части применяется метод НайтиСтроки(). В качестве параметра отбора передается объект Структура, содержащий имя колонки и искомое значение.

Разберем по шагам, как выполняется данный алгоритм:

  1. Обходим строки табличной части исходного документа.
  2. Для каждой строки формируем структуру отбора по ключевому полю (номенклатуре).
  3. Вызываем метод НайтиСтроки() для табличной части документа-приемника.
  4. Если массив найденных строк не пуст, берем первую найденную строку и увеличиваем ее количество на значение из текущего документа.
  5. Если массив пуст, добавляем новую строку через метод Добавить() и заполняем реквизиты.

Посмотрим на пример реализации данного алгоритма:


Для Каждого Стр Из Проведение.Товары Цикл
    ПараметрыОтбора = Новый Структура("Номенклатура", Стр.Номенклатура);
    НайденныеСтроки = Смета.Товары.НайтиСтроки(ПараметрыОтбора);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        НайденныеСтроки[0].КолФ = НайденныеСтроки[0].КолФ + Стр.Количество;
    Иначе
        НоваяСтрока = Смета.Товары.Добавить();
        НоваяСтрока.Номенклатура = Стр.Номенклатура;
        НоваяСтрока.КолФ = Стр.Количество;
    КонецЕсли;
КонецЦикла;

Способ 2. Пакетное объединение и метод Свернуть

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

Рассмотрим программную реализацию этого способа:


// Выгружаем текущие данные целевого документа
ТЗСмета = Смета.Товары.Выгрузить();

// Добавляем все строки из текущего документа
Для Каждого Стр Из Проведение.Товары Цикл
    НоваяСтр = ТЗСмета.Добавить();
    НоваяСтр.Номенклатура = Стр.Номенклатура;
    НоваяСтр.КолФ = Стр.Количество;
КонецЦикла;

// Сворачиваем таблицу по номенклатуре, суммируя фактическое количество
ТЗСмета.Свернуть("Номенклатура", "КолФ");

// Загружаем результат обратно в табличную часть
Смета.Товары.Загрузить(ТЗСмета);

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

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

  1. Взаимоблокировки (Deadlocks): если несколько пользователей одновременно проводят разные перемещения по одной и той же смете, СУБД накладывает исключительные блокировки на один объект. В результате сеансы начинают ожидать освобождения ресурса, что приводит к ошибкам превышения времени ожидания или взаимоблокировкам.
  2. Неконсистентность данных при отмене проведения: если исходный документ будет отменен, помечен на удаление или изменен задним числом, данные в смете останутся измененными. Ручной контроль актуальности табличной части становится невозможным.
  3. Каскадные сбои транзакций: запись стороннего документа выполняется во вложенной транзакции. Если смета не сможет провестись (например, из-за нехватки остатков или проверок заполнения), будет отменено проведение и исходного перемещения.
  4. Нарушение последовательности документов: перепроведение сметы задним числом приводит к неконтролируемому сдвигу границ последовательностей и пересчету итогов регистров.

Правильное решение: использование регистров накопления

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

Разберем стандартную схему реализации учета материалов по сметам:

  1. Создаем регистр накопления (вид: остатки или обороты) МатериалыПоСметам с измерениями Смета, Номенклатура и ресурсами КоличествоПлан, КоличествоФакт.
  2. Документ «Смета» при своем проведении формирует движения по ресурсу КоличествоПлан (приход). Табличная часть сметы остается неизменной и хранит исходный утвержденный план.
  3. Документ «Перемещение» в процедуре ОбработкаПроведения делает движение по ресурсу КоличествоФакт с указанием соответствующей сметы в измерении.
  4. Для отображения текущего расхода и остатков по смете используются отчеты на базе схемы компоновки данных (СКД) или динамический расчет на форме документа через запрос к виртуальной таблице регистра ОстаткиИОбороты.

Такой подход полностью исключает блокировки сторонних документов, гарантирует целостность базы при отмене или групповом перепроведении документов и соответствует стандартам разработки фирмы «1С».

← На главную