Как программно заполнить Акт сверки взаиморасчетов в 1С:Бухгалтерия 3.0 и быстро получить долг контрагента

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

Приветствуем вас! Довольно часто в практике разработчика 1С возникает классическая архитектурная дилемма: реальная бизнес-задача подменяется сложным техническим решением, которое в итоге перегружает систему и работает неэффективно. В этой статье мы подробно разберем именно такой случай.

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

Часть 1. Как программно заполнить «Акт сверки взаиморасчетов» в БП 3.0

Начнем с технического решения первоначального вопроса автора. Метод Д.Заполнить(ЗН.ЭтотОбъект), который пытался применить разработчик в первом сообщении, предназначен для заполнения документа на основании другого объекта (например, договора или счета). Он не запускает штатный механизм анализа проводок и расчета сальдо по бухгалтерским счетам.

В конфигурации «1С:Бухгалтерия предприятия 3.0» (БП 3.0) расчет данных для акта сверки реализован на стороне сервера и тесно связан с логикой проведения и анализа проводок. Мы можем заполнить документ программно двумя путями: через эмуляцию работы формы или напрямую через вызов серверных процедур общего модуля.

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


// 1. Создаем новый документ и заполняем его шапку
НовыйАкт = Документы.АктСверкиВзаиморасчетов.СоздатьДокумент();
НовыйАкт.Дата = ТекущаяДата();
НовыйАкт.Организация = Справочники.Организации.НайтиПоНаименованию("ООО ""Ромашка""");
НовыйАкт.Контрагент = СсылкаНаКонтрагента;
НовыйАкт.ДатаНачала = НачалоМесяца(ТекущаяДата());
НовыйАкт.ДатаОкончания = КонецМесяца(ТекущаяДата());

// Документ необходимо предварительно записать, чтобы у него появилась ссылка
НовыйАкт.Записать(РежимЗаписиДокумента.Запись);

// 2. Получаем форму созданного документа
ПараметрыФормы = Новый Структура("Ключ", НовыйАкт.Ссылка);
ФормаДокумента = ПолучитьФорму("Документ.АктСверкиВзаиморасчетов.Форма.ФормаДокумента", ПараметрыФормы);

// 3. Вызываем штатный экспортный метод формы для заполнения табличных частей.
// Параметр "Истина" указывает системе заполнить данные "Только по нашей организации".
ФормаДокумента.ЗаполнитьПоДаннымБухгалтерскогоУчета(Истина);

// 4. Сохраняем измененную форму обратно в базу данных
ФормаДокумента.Записать();

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


// Создаем документ и заполняем основные реквизиты
НовыйАкт = Документы.АктСверкиВзаиморасчетов.СоздатьДокумент();
НовыйАкт.Дата = ТекущаяДата();
НовыйАкт.Организация = ОрганизацияСсылка;
НовыйАкт.Контрагент = КонтрагентСсылка;
НовыйАкт.ДатаНачала = ДатаНачала;
НовыйАкт.ДатаОкончания = ДатаОкончания;

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

// Вызываем метод заполнения из общего модуля или модуля менеджера
Документы.АктСверкиВзаиморасчетов.ЗаполнитьТабличныеЧастиДокумента(НовыйАкт, ПараметрыЗаполнения);

// Записываем полностью заполненный документ
НовыйАкт.Записать(РежимЗаписиДокумента.Запись);

Часть 2. Почему создание Акта сверки для получения долга — это ошибка

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

  1. Низкая скорость работы: Программное создание, заполнение и запись документа занимает несколько секунд из-за необходимости выполнения сложных запросов и записи транзакции в СУБД. Клиент на телефоне не будет ждать.
  2. Замусоривание базы данных: В системе будут плодиться сотни черновых «мусорных» документов актов сверок, которые не несут никакой практической ценности для учета.
  3. Блокировки базы данных: При интенсивной работе менеджеров постоянная запись документов в транзакции может вызывать взаимные блокировки таблиц базы данных.

Часть 3. Эффективное получение долга через запрос к регистру бухгалтерии

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

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

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


Функция ПолучитьДолгКонтрагента(Организация, Контрагент) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЕСТЬNULL(ХозрасчетныйОстатки.СуммаОстатокДт, 0) КАК ДолгПокупателя,
        |	ЕСТЬNULL(ХозрасчетныйОстатки.СуммаОстатокКт, 0) КАК АвансПокупателя
        |ИЗ
        |	РегистрБухгалтерии.Хозрасчетный.Остатки(
        |		&Период,
        |		Счет В (&СчетаРасчетов),
        |		,
        |		Организация = &Организация
        |			И Субконто1 = &Контрагент
        |	) КАК ХозрасчетныйОстатки";

    // Указываем текущую дату для получения оперативного остатка
    Запрос.УстановитьПараметр("Период", Новый Граница(ТекущаяДата(), ВидГраницы.Включая));
    Запрос.УстановитьПараметр("Организация", Организация);
    Запрос.УстановитьПараметр("Контрагент", Контрагент);

    // Определяем счета взаиморасчетов с покупателями
    СчетаРасчетов = Новый Массив;
    СчетаРасчетов.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСПокупателямиИЗаказчиками); // Счет 62
    // При необходимости можно добавить и другие счета расчетов (например, 76.05, 76.06)
    Запрос.УстановитьПараметр("СчетаРасчетов", СчетаРасчетов);

    Результат = Запрос.Выполнить();
    Если Не Результат.Пустой() Тогда
        Выборка = Результат.Выбрать();
        Выборка.Следующий();
        
        // Долг контрагента нам — это дебетовый остаток. 
        // Если есть аванс (кредитовый остаток), мы вычитаем его для получения чистого сальдо.
        ЧистыйДолг = Выборка.ДолгПокупателя - Выборка.АвансПокупателя;
        Возврат ЧистыйДолг;
    КонецЕсли;

    Возврат 0;

КонецФункции

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

Часть 4. Как вывести долг в интерфейс формы списка контрагентов

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

Пример интеграции запроса остатков в динамический список контрагентов:


ВЫБРАТЬ
	СправочникКонтрагенты.Ссылка КАК Ссылка,
	СправочникКонтрагенты.Наименование КАК Наименование,
	// Расчет чистого дебетового сальдо
	ЕСТЬNULL(ВзаиморасчетыОстатки.СуммаОстатокДт, 0) - ЕСТЬNULL(ВзаиморасчетыОстатки.СуммаОстатокКт, 0) КАК ТекущийДолг
ИЗ
	Справочник.Контрагенты КАК СправочникКонтрагенты
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Остатки(
		&Период,
		Счет В (&СчетаРасчетов),
		,
		Организация = &Организация
	) КАК ВзаиморасчетыОстатки
	ПО ВзаиморасчетыОстатки.Субконто1 = СправочникКонтрагенты.Ссылка

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

Резюмируем: Программное заполнение Акта сверки взаиморасчетов незаменимо, если вам нужно подготовить печатную форму документа для отправки контрагенту. Но если цель — оперативный контроль задолженности «на лету» во время звонка клиента, всегда используйте легкие прямые запросы к виртуальным таблицам остатков регистра бухгалтерии.

← На главную