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