Как перемножить таблицы в 1С: распределение затрат со счета 25 на счет 20

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

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

Постановка задачи

Рассмотрим ситуацию: у нас есть две таблицы значений. Первая таблица содержит данные по счету 25 (затраты, которые нужно распределить). Вторая таблица содержит данные по счету 20 (база, на которую мы распределяем). Нам необходимо взять каждую строку из 25 счета, разделить её на общий итог по 20 счету (получив долю) и умножить на каждую строку 20 счета. В результате мы должны получить новую таблицу, где затраты распределены пропорционально выбранной базе.

Решение 1: Использование вложенных циклов

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

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


// 1. Получаем итог по базе (счет 20)
ИтогоБаза = Т20.Итог("Сумма");

// Проверка на ноль, чтобы избежать критической ошибки
Если ИтогоБаза = 0 Тогда
    Сообщить("База распределения равна нулю, распределение невозможно!");
    Возврат;
КонецЕсли;

// 2. Создаем таблицу для результата
ТЗ_Результат = Т20.СкопироватьКолонки();
ТЗ_Результат.Колонки.Добавить("СуммаРаспределенная");

// 3. Основной цикл распределения
Для Каждого Стр25 Из Т25 Цикл
    // Вычисляем коэффициент для текущей строки 25 счета
    Коэффициент = Стр25.Сумма / ИтогоБаза;
    
    Для Каждого Стр20 Из Т20 Цикл
        НоваяСтрока = ТЗ_Результат.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Стр20);
        
        // Математическая операция: (Строка25 / Итого20) * Строка20
        НоваяСтрока.СуммаРаспределенная = Коэффициент * Стр20.Сумма;
    КонецЦикла;
КонецЦикла;

Проанализируем этот подход. Метод Итог() позволяет нам быстро получить знаменатель для нашей формулы. Вложенный цикл обеспечивает декартово произведение строк: если в Т25 10 строк, а в Т20 100 строк, на выходе мы получим 1000 строк распределенных затрат. Это именно то, что обычно требуется при закрытии счетов в бухгалтерском учете.

Решение 2: Оптимизация через механизмы запросов

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

Рассмотрим шаги реализации через запрос:

  1. Помещаем таблицу 25 счета во временную таблицу ВТ_Затраты.
  2. Помещаем таблицу 20 счета во временную таблицу ВТ_База.
  3. Вычисляем итог по ВТ_База и передаем его в запрос как параметр.
  4. Выполняем соединение таблиц.

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВТ_Затраты.Сумма КАК СуммаЗатрат,
    |	ВТ_Затраты.СтатьяЗатрат25 КАК СтатьяЗатрат,
    |	ВТ_База.Сумма КАК СуммаБазы,
    |	ВТ_База.НоменклатурнаяГруппа КАК НоменклатурнаяГруппа,
    |	(ВТ_Затраты.Сумма / &ОбщийИтогБазы) * ВТ_База.Сумма КАК Результат
    |ИЗ
    |	ВТ_Затраты КАК ВТ_Затраты
    |		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_База КАК ВТ_База
    |		ПО (ИСТИНА)";

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

Этот метод работает значительно быстрее на больших объемах данных, так как платформа оптимизирует операции соединения таблиц на уровне СУБД.

Важный нюанс: Проблема "копеек" и округления

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

Разберем, как правильно решить проблему "хвоста":

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

Посмотрим на пример кода с контролем округления:


Для Каждого Стр25 Из Т25 Цикл
    ОстатокКРаспределению = Стр25.Сумма;
    КоличествоСтрок = Т20.Количество();
    ТекущийНомерСтроки = 0;
    
    Для Каждого Стр20 Из Т20 Цикл
        ТекущийНомерСтроки = ТекущийНомерСтроки + 1;
        
        Если ТекущийНомерСтроки < КоличествоСтрок Тогда
            // Обычная строка
            РаспределеннаяСумма = Окр((Стр25.Сумма / ИтогоБаза) * Стр20.Сумма, 2);
            ОстатокКРаспределению = ОстатокКРаспределению - РаспределеннаяСумма;
        Иначе
            // Последняя строка - отдаем весь остаток (включая копейки)
            РаспределеннаяСумма = ОстатокКРаспределению;
        КонецЕсли;
        
        // Запись результата...
    КонецЦикла;
КонецЦикла;

Методологические рекомендации

Выясним причину, по которой иногда такое распределение "в лоб" может быть неверным. В бухгалтерском учете счет 25 распределяется на счет 20 не просто "на все строки", а по определенным правилам. Например:

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

Также стоит помнить, что в типовых конфигурациях (1С:Бухгалтерия 3.0, 1С:ERP) механизмы закрытия счетов уже реализованы на уровне ядра. Если вы дорабатываете типовую систему, рассмотрите возможность использования штатных регистров сведений, таких как МетодыРаспределенияРасходов, вместо написания собственного кода перемножения таблиц.

Заключение

Мы рассмотрели несколько способов перемножения таблиц для целей распределения затрат. Использование Для каждого подходит для простых задач и небольших объемов данных. Для высоконагруженных систем правильнее использовать Запрос с декартовым произведением. И в любом случае никогда не забывайте про проверку на деление на ноль и корректную обработку "копеек", чтобы ваш баланс всегда сходился идеально.

← На главную