Как написать запрос в 1С для проведения взаимозачета и очистки встречных долгов между организациями

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

В практике программирования на платформе 1С часто встречается задача, когда необходимо из «сырых» данных о долгах получить чистую картину взаимоотношений между контрагентами. Типичный пример: организация А должна организации Б, а организация Б, в свою очередь, должна организации А. В отчете мы хотим видеть не две строки с долгами, а одну — с итоговым сальдо. Рассмотрим, как решить эту задачу исключительно средствами языка запросов 1С, не прибегая к механизмам СКД или постобработке на встроенном языке.

Метод 1: Нормализация данных (Метод «Обобщенного контрагента»)

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

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

  1. Создание единого списка участников: Мы используем оператор ОБЪЕДИНИТЬ ВСЕ, чтобы превратить таблицу с двумя колонками в таблицу с одной колонкой Контрагент.
  2. Присвоение знаков: Для тех, кто записан в колонке «Должник», мы оставляем сумму положительной. Для тех, кто в колонке «Кредитор» — инвертируем знак (умножаем на -1).
  3. Группировка: Схлопываем все записи по конкретному контрагенту. В результате получаем «чистое» сальдо по каждому участнику.

Посмотрим на пример кода, реализующего этот подход:


ВЫБРАТЬ
    Тест.Должник КАК Контрагент,
    Тест.СуммаДолга КАК Сумма
ПОМЕСТИТЬ ВТ_ВсеПотоки
ИЗ
    Документ.Взаимозачет.ТабличнаяЧасть КАК Тест

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    Тест.Кредитор,
    -Тест.СуммаДолга
ИЗ
    Документ.Взаимозачет.ТабличнаяЧасть КАК Тест;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ.Контрагент КАК Контрагент,
    СУММА(ВТ.Сумма) КАК ЧистоеСальдо
ПОМЕСТИТЬ ВТ_ИтоговыеОстатки
ИЗ
    ВТ_ВсеПотоки КАК ВТ
ГРУППИРОВАТЬ ПО
    ВТ.Контрагент;

Теперь у нас есть таблица, где для каждого контрагента понятно: должен он (сумма > 0) или должны ему (сумма < 0). Это база, от которой мы можем строить финальный отчет.

Метод 2: Сопоставление должников и кредиторов

После того как мы получили чистые остатки, нам нужно снова «связать» должников с кредиторами для эталонного вида отчета. Выясним причину, почему это не всегда получается сделать простым соединением: суммы долгов могут не совпадать копейка в копейку, если мы рассматриваем сложную сеть из множества компаний.

Однако в простом случае (когда суммы зеркальны) мы можем применить левое соединение таблицы самой с собой:


ВЫБРАТЬ
    Должники.Контрагент КАК Должник,
    Кредиторы.Контрагент КАК Кредитор,
    Должники.ЧистоеСальдо КАК СуммаДолга
ИЗ
    ВТ_ИтоговыеОстатки КАК Должники
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИтоговыеОстатки КАК Кредиторы
        ПО Должники.ЧистоеСальдо = -Кредиторы.ЧистоеСальдо
        И Должники.Контрагент <> Кредиторы.Контрагент
ГДЕ
    Должники.ЧистоеСальдо > 0

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

Метод 3: Реализация логики ФИФО для сложных цепочек

Если задача стоит более масштабно — распределить общую массу долгов между всеми кредиторами максимально эффективно — нам потребуется механизм нарастающих итогов. В 1С это реализуется через соединение временной таблицы с самой собой по условию «меньше или равно».

Рассмотрим алгоритм действий:

  1. Разделяем чистые остатки на две временные таблицы: ВТ_Дебиторы (где сумма > 0) и ВТ_Кредиторы (где сумма < 0, берем по модулю).
  2. В каждой таблице вычисляем нарастающий итог суммы. Это позволит нам представить долги как непрерывные отрезки на числовой прямой.
  3. Соединяем эти таблицы по условию пересечения отрезков. Условие пересечения: НачалоОтрезка1 < КонецОтрезка2 И КонецОтрезка1 > НачалоОтрезка2.

Проанализируем пример расчета нарастающего итога в запросе:


ВЫБРАТЬ
    Т1.Контрагент,
    Т1.Сумма,
    СУММА(Т2.Сумма) КАК НарастающийИтог
ПОМЕСТИТЬ ВТ_ДебиторыСИтогом
ИЗ
    ВТ_Дебиторы КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Дебиторы КАК Т2
        ПО Т1.Контрагент >= Т2.Контрагент
ГРУППИРОВАТЬ ПО
    Т1.Контрагент,
    Т1.Сумма

Используя такие «интервалы», мы можем математически точно распределить долг каждого должника между кредиторами в том порядке, в котором они идут в выборке. Это классическая реализация метода ФИФО в языке запросов, которая не требует рекурсии, недоступной в 1С.

Оптимизация и производительность

При работе с большими объемами данных (например, если в документе тысячи строк ТЗ) важно помнить о производительности. Рассмотрим несколько правил:

Таким образом, мы выяснили, что даже без использования объектной модели или сложных циклов на встроенном языке, можно построить мощный аналитический отчет. Главный секрет заключается в правильной предварительной подготовке данных — переходе от плоской таблицы «кто-кому» к балансовой модели «сальдо по контрагенту».

← На главную