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

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

В процессе разработки в системе 1С:Предприятие часто возникает необходимость вывести на форму документа оперативную информацию, которая не хранится в самом документе, но важна для пользователя. Одной из таких задач является получение данных о продажах по конкретному контрагенту за предыдущий месяц. Рассмотрим, как это реализовать в управляемых формах, какие методы использовать и на что обратить внимание в современных конфигурациях, таких как УТ 11, ERP или КА 2.

Постановка задачи и выбор подхода

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

Проанализируем два основных способа получения данных:

  1. Использование прямого обращения к менеджеру регистра через метод Обороты().
  2. Написание запроса к виртуальной таблице оборотов регистра.

Разберем каждый из этих подходов по шагам.

Способ 1. Использование метода менеджера регистра (подход «в одну строку»)

Многие разработчики, привыкшие к работе в «обычных формах» (1С 8.2 и ранее), ищут способ получить данные одной строкой кода. В платформе действительно существует метод Обороты() у объекта РегистрНакопленияМенеджер. Рассмотрим пример реализации такой функции на сервере.

Выясним причину, почему этот метод редко используется в типовых решениях: он возвращает ТаблицаЗначений или ВыборкаИзРезультатаЗапроса, и хотя он кажется компактным, он менее гибкий, чем полноценный запрос. Тем не менее, посмотрим на пример кода:


&НаСервере
Функция ПолучитьПродажиЗаПрошлыйМесяц(ВыбранныйКонтрагент)
    
    // Определяем период: начало и конец предыдущего месяца
    ДатаНачала = НачалоМесяца(ДобавитьМесяц(ТекущаяДата(), -1));
    ДатаОкончания = КонецМесяца(ДобавитьМесяц(ТекущаяДата(), -1));
    
    // Формируем структуру отбора
    Отбор = Новый Структура;
    Отбор.Вставить("Контрагент", ВыбранныйКонтрагент);
    
    // Обращаемся к менеджеру регистра (имя регистра зависит от конфигурации)
    // В УТ 11 это может быть ВыручкаИСебестоимостьПродаж
    ТаблицаОборотов = РегистрыНакопления.ВыручкаИСебестоимостьПродаж.Обороты(ДатаНачала, ДатаОкончания, Отбор, "СуммаВыручки");
    
    Если ТаблицаОборотов.Количество() > 0 Тогда
        Возврат ТаблицаОборотов[0].СуммаВыручки;
    Иначе
        Возврат 0;
    КонецЕсли;

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

Важный момент: в управляемых формах обращение к объекту РегистрыНакопления доступно только на стороне сервера. Поэтому вызов этой функции из формы должен происходить внутри серверной процедуры.

Способ 2. Использование запроса (рекомендуемый метод)

Профессиональная разработка в 1С подразумевает использование механизма запросов. Это позволяет системе оптимально построить план выполнения на уровне SQL и задействовать индексы виртуальных таблиц. Проанализируем, как составить такой запрос к регистру накопления.

Рассмотрим структуру запроса к виртуальной таблице Обороты. Нам необходимо передать параметры периода и условие по контрагенту непосредственно в параметры виртуальной таблицы, чтобы база данных не считывала лишнюю информацию.


&НаСервереБезКонтекста
Функция ПолучитьСуммуПродажЗапросом(КонтрагентСсылка)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	СУММА(ВыручкаОбороты.СуммаВыручкиОборот) КАК Сумма
        |ИЗ
        |	РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода, , Контрагент = &Контрагент) КАК ВыручкаОбороты";
    
    // Рассчитываем даты
    ТекущаяДата = ТекущаяДатаСеанса();
    Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ДобавитьМесяц(ТекущаяДата, -1)));
    
    // Для точности используем Границу, чтобы включить последнюю секунду месяца
    КонецМесяца = КонецМесяца(ДобавитьМесяц(ТекущаяДата, -1));
    Запрос.УстановитьПараметр("КонецПериода", Новый Граница(КонецМесяца, ВидГраницы.Включая));
    
    Запрос.УстановитьПараметр("Контрагент", КонтрагентСсылка);
    
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    
    Если ВыборкаДетальныеЗаписи.Следующий() Тогда
        Возврат ВыборкаДетальныеЗаписи.Сумма;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Обратите внимание на использование объекта Граница. В 1С это считается "хорошим тоном", так как позволяет гарантированно захватить все движения, произошедшие ровно в 23:59:59 последнего дня месяца.

Особенности современных конфигураций (УТ 11, ERP, КА)

Разберем ситуацию, упомянутую в обсуждении: в современных конфигурациях на базе УТ 11 (или ERP 2) привычного регистра Продажи может не существовать или он используется для других целей.

Основные регистры для анализа продаж в актуальных версиях:

Как вызвать получение данных в форме

Посмотрим на пример того, как интегрировать получение данных в логику управляемой формы. Лучше всего делать это при изменении контрагента или при открытии формы.


&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    
    // Вызываем серверную функцию для получения данных
    ОбъемЗакупок = ПолучитьСуммуПродажЗапросом(Объект.Контрагент);
    
    // Выводим информацию пользователю (например, в декорацию или реквизит формы)
    ТекстИнформации = "Продажи за прошлый месяц: " + ОбъемЗакупок + " руб.";
    
КонецПроцедуры

Резюме и рекомендации

Подведем итог нашему анализу:

  1. Не ищите способ сделать всё «в одну строку» в ущерб производительности. Запрос к виртуальной таблице — самый быстрый и правильный метод в 1С 8.3.
  2. Всегда учитывайте контекст. Работа с регистрами (РегистрыНакопления) возможна только &НаСервере.
  3. Проверяйте имена регистров. В УТ 11 и ERP данные о выручке лежат в регистре ВыручкаИСебестоимостьПродаж, а не в Продажи.
  4. Используйте типовые механизмы. Если задача сложная, рассмотрите возможность программного использования СКД или вызова функций из общих модулей конфигурации.

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

← На главную