При работе в 1С часто возникает необходимость вывести дополнительную, нестандартную информацию прямо в списке документов. Например, может потребоваться видеть текущий остаток по взаиморасчетам клиента непосредственно рядом с каждым его заказом. Стандартные возможности конфигурации не всегда предоставляют такой функционал "из коробки". В таких случаях мы прибегаем к программному изменению запроса динамического списка. Давайте подробно рассмотрим, как это сделать, используя механизмы платформы 1С:Предприятие 8.3 на управляемых формах.
Мы столкнулись с задачей в конфигурации 1С:Управление торговлей (УТ 11.4), где в списке документов "Заказ клиента" нужно было отобразить остаток по взаиморасчетам контрагента. Эта информация хранится в регистрах накопления, и для её получения требуется специфический запрос. Разберем по шагам, как модифицировать динамический список для достижения этой цели.
Прежде чем мы приступим к модификациям, давайте выясним, что такое динамический список и как он формирует данные. Динамический список в 1С — это универсальный механизм для отображения данных, который получает информацию из источника данных (чаще всего это запрос к базе данных). Особенностью динамических списков является то, что запрос выполняется на сервере, и данные подгружаются порциями по мере прокрутки списка, что обеспечивает высокую производительность при работе с большими объемами информации.
Для добавления пользовательской информации в динамический список, нам необходимо изменить его основной запрос. Это может быть сделано через конфигуратор, в свойствах элемента формы типа ДинамическийСписок. Основные данные для списка документов, как правило, выбираются из таблиц самого документа. Для получения дополнительных данных, таких как остатки по взаиморасчетам, мы будем использовать соединение с виртуальными таблицами регистров накопления.
Информация о взаиморасчетах клиентов обычно хранится в регистре накопления "ВзаиморасчетыСКлиентами". Этот регистр, как и большинство регистров накопления, предоставляет виртуальные таблицы для получения остатков и оборотов. Нас интересуют виртуальные таблицы Остатки или СрезПоследних, которые позволяют получить конечное сальдо на определенный момент времени.
Модификация запроса динамического списка производится в конфигураторе. Давайте рассмотрим последовательность действий:
Документ.ЗаказКлиента) и откройте его форму списка (например, ФормаСписка).ДинамическийСписок. Выделите его в дереве элементов формы.Использование временных таблиц (ВТ) часто является предпочтительным способом для усложнения запросов динамических списков, особенно когда нам нужно сначала агрегировать данные (например, получить остатки), а затем присоединить их к основному набору данных. Это позволяет сохранить читабельность основного запроса и избежать чрезмерно сложных условий соединения.
Предположим, наша задача заключается в том, чтобы видеть текущий, актуальный остаток по взаиморасчетам для каждого контрагента в списке документов "Заказ клиента". То есть, если у клиента есть несколько заказов, то рядом с каждым из них будет отображаться один и тот же текущий остаток его долга или переплаты.
Для реализации этого сценария мы можем использовать виртуальную таблицу Остатки регистра накопления "ВзаиморасчетыСКлиентами". Нам нужно получить остатки по всем контрагентам на текущую дату (или на некоторую фиксированную дату) и затем присоединить эти данные к основному запросу списка заказов клиента. Мы будем использовать временную таблицу для предварительного сбора остатков, а затем присоединим её к основному запросу:
ВЫБРАТЬ
ВзаиморасчетыОстаткиИОбороты.Контрагент КАК Контрагент,
ВзаиморасчетыОстаткиИОбороты.СуммаВзаиморасчетовКонечныйОстаток КАК ОстатокДолга
ПОМЕСТИТЬ ВТ_ОстаткиВзаиморасчетов
ИЗ
РегистрНакопления.ВзаиморасчетыСКлиентами.Остатки(
&ТекущаяДата,
Организация = &Организация) КАК ВзаиморасчетыОстаткиИОбороты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ЗаказКлиента.Ссылка,
ЗаказКлиента.Дата,
ЗаказКлиента.Номер,
ЗаказКлиента.Контрагент,
ВТ_ОстаткиВзаиморасчетов.ОстатокДолга
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ОстаткиВзаиморасчетов КАК ВТ_ОстаткиВзаиморасчетов
ПО ЗаказКлиента.Контрагент = ВТ_ОстаткиВзаиморасчетов.Контрагент
Давайте подробно разберем этот запрос:
ВТ_ОстаткиВзаиморасчетов. Мы выбираем Контрагент и СуммаВзаиморасчетовКонечныйОстаток из виртуальной таблицы РегистрНакопления.ВзаиморасчетыСКлиентами.Остатки().Остатки() принимает параметры: &ТекущаяДата (момент, на который мы хотим получить остатки) и условия отбора, например, Организация = &Организация. Эти параметры, как &ТекущаяДата и &Организация, должны быть установлены в свойствах динамического списка в закладке "Параметры" или программно, например, в обработчике ПриСозданииНаСервере формы или ПриПолученииДанных динамического списка.ЗаказКлиента и выполняет ЛЕВОЕ СОЕДИНЕНИЕ с нашей временной таблицей ВТ_ОстаткиВзаиморасчетов.ПО ЗаказКлиента.Контрагент = ВТ_ОстаткиВзаиморасчетов.Контрагент связывает каждый заказ с соответствующим контрагентом из таблицы остатков. Мы используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы в списке отображались все заказы, даже если по какому-то контрагенту нет данных о взаиморасчетах (в этом случае поле ОстатокДолга будет NULL).После того как запрос изменен, необходимо добавить новое поле ОстатокДолга в список доступных полей динамического списка и перетащить его на форму списка документа, чтобы оно отображалось в виде колонки.
В некоторых случаях нам может потребоваться видеть остаток взаиморасчетов не на текущую дату, а именно на дату каждого конкретного документа в списке. Например, для заказа, созданного 1 марта, нам нужен остаток на 1 марта, а для заказа от 1 апреля — остаток на 1 апреля. Этот подход является более ресурсоемким, но предоставляет более точную историческую картину.
Для такого сценария мы будем использовать виртуальную таблицу СрезПоследних регистра накопления "ВзаиморасчетыСКлиентами". Особенность СрезПоследних в том, что она позволяет получить последние записи по измерениям регистра на каждый указанный момент времени. В нашем случае, моментом времени будет дата каждого документа ЗаказКлиента.
ВЫБРАТЬ
ЗаказКлиента.Ссылка КАК ЗаказКлиента,
ЗаказКлиента.Дата КАК ДатаЗаказа,
ВзаиморасчетыСКлиентамиСрезПоследних.СуммаВзаиморасчетовКонечныйОстаток КАК ОстатокДолгаНаДатуЗаказа
ИЗ
Документ.ЗаказКлиента КАК ЗаказКлиента
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ВзаиморасчетыСКлиентами.СрезПоследних(
ЗаказКлиента.Дата,
Контрагент = ЗаказКлиента.Контрагент) КАК ВзаиморасчетыСКлиентамиСрезПоследних
ПО ИСТИНА
Проанализируем этот запрос:
ЗаказКлиента с виртуальной таблицей РегистрНакопления.ВзаиморасчетыСКлиентами.СрезПоследних().СрезПоследних мы передаем ЗаказКлиента.Дата. Это означает, что для каждой строки (каждого заказа) виртуальная таблица будет вычислять срез на дату этого конкретного заказа.СрезПоследних мы указываем условия отбора по измерениям, например, Контрагент = ЗаказКлиента.Контрагент. Это гарантирует, что мы получаем остаток именно для того контрагента, которому принадлежит текущий заказ. Также могут потребоваться дополнительные условия, если регистр имеет другие измерения (например, Организация, ДоговорКонтрагента).ПО ИСТИНА используется, когда все необходимые условия соединения уже указаны непосредственно в параметрах виртуальной таблицы. В этом случае система понимает, что соединение происходит по параметрам виртуальной таблицы.Необходимо помнить, что использование СрезПоследних с параметром, зависящим от каждой строки основного запроса, может быть более ресурсоемким, так как для каждой строки документа фактически выполняется отдельный запрос к виртуальной таблице. Для больших объемов данных это может сказаться на производительности.
В процессе реализации таких доработок мы должны учитывать несколько важных моментов, чтобы обеспечить стабильность и производительность системы:
СрезПоследних для каждой строки, как мы рассмотрели во втором варианте, может значительно нагружать сервер, если документов очень много.Контрагент, Организация, ДоговорКонтрагента. Если вы соединяетесь только по Контрагент, а в регистре есть также Организация, то результат будет некорректным, если заказ принадлежит другой организации.&ТекущаяДата, &Организация), их необходимо установить. Это можно сделать двумя способами:
ПриПолученииДанныхНаСервере или ПриСозданииНаСервере формы. В этом случае вы можете устанавливать значения параметров динамически, например, ДинамическийСписок.Параметры.УстановитьЗначение("ТекущаяДата", ТекущаяДата());ОстатокДолга), это поле появится в списке "Доступные поля" динамического списка. Вам нужно перетащить его в "Используемые поля" и затем разместить на самой форме списка, чтобы оно отображалось как колонка.Решение подобных задач требует глубокого понимания принципов работы платформы 1С, запросов и структуры метаданных. Совмещая знания о динамических списках, регистрах накопления и приемах работы с запросами, мы получаем мощный инструмент для адаптации системы под специфические бизнес-требования.