Как правильно отфильтровать данные регистра накопления по дате через OData и сохранить поле Период?

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

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

Различие между физической и виртуальной таблицами регистра

Для начала проанализируем архитектуру доступа к данным через standard.odata. Когда мы обращаемся к регистру накопления (например, AccumulationRegister_Продажи), платформа 1С может предоставить нам два принципиально разных набора данных:

  1. Основная таблица (физическая): Содержит все записи (движения) регистра. Каждая строка — это отдельное событие, созданное документом-регистратором. В этой таблице всегда есть поле Period.
  2. Виртуальная таблица оборотов: Имеет суффикс _Turnovers. Она возвращает уже агрегированные (сгруппированные) данные. По умолчанию в этой таблице нет поля Period, так как она суммирует показатели за весь запрошенный интервал.

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

Работа с основной таблицей движений

Если ваша цель — получить детальные записи регистра с сохранением даты каждой конкретной продажи, необходимо обращаться к основной таблице. Выясним причину типичной ошибки: использование параметров StartPeriod и EndPeriod внутри функции $filter для основной таблицы недопустимо, так как этих полей в структуре физической таблицы просто не существует.

Для фильтрации физической таблицы мы должны использовать стандартный синтаксис OData и системное поле Period. Рассмотрим пример правильного запроса:


/standard.odata/AccumulationRegister_Продажи?$filter=Period ge datetime'2023-01-01T00:00:00' and Period le datetime'2023-01-31T23:59:59'

В данном примере мы используем операторы ge (greater or equal — больше или равно) и le (less or equal — меньше или равно). Обратите внимание на формат даты: datetime'ГГГГ-ММ-ДДTHH:mm:ss'. Именно такой формат является стандартным для 1С при работе по протоколу OData версии 3 и 4. Для автоматического формирования корректных URL с нужными условиями фильтрации можно использовать генератор запросов OData.

Преимущества этого метода:

Работа с виртуальной таблицей оборотов

Если же нам нужны не детальные записи, а итоги (например, общая сумма продаж по контрагентам), мы используем таблицу _Turnovers. Здесь синтаксис меняется. Параметры периода передаются не через $filter, а в круглых скобках непосредственно после имени таблицы.

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


/standard.odata/AccumulationRegister_Продажи_Turnovers(StartPeriod=datetime'2023-01-01T00:00:00', EndPeriod=datetime'2023-01-31T23:59:59')

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

Как «вернуть» дату в таблицу оборотов?

Часто возникает ситуация: нужны именно обороты (чтобы не тянуть миллионы строк движений), но с разбивкой по дням. К сожалению, стандартный интерфейс OData в 1С не поддерживает параметр Periodicity (периодичность) в виртуальных таблицах так, как это делает язык запросов 1С (где можно указать «День», «Месяц» и т.д.).

Рассмотрим способы обхода этого ограничения:

  1. Группировка на стороне клиента: Мы выгружаем детальные записи из основной таблицы AccumulationRegister_Продажи (как описано в первом способе) и выполняем агрегацию данных в Power BI, Excel или вашем приложении. Это самый надежный способ сохранить точность до секунды.
  2. Использование дополнительных реквизитов: Если конфигурация позволяет вносить изменения, можно добавить в измерения регистра поле ДатаДень (тип Дата). Тогда при обращении к _Turnovers это поле будет доступно как обычное измерение, и 1С автоматически сгруппирует данные по нему, фактически вернув вам обороты в разрезе дней.

Типичные ошибки и способы их решения

Проанализируем ситуацию, описанную в сообщениях форума. Пользователь пытался выполнить запрос:

.../AccumulationRegister_Продажи?$filter=StartPeriod ge datetime'2020-09-01T00:00:00'

Платформа закономерно ответила: «Сегмент пути StartPeriod не найден». Это произошло потому, что StartPeriod — это имя параметра функции для виртуальной таблицы, а не имя поля в базе данных. В основной таблице поле называется Period.

Также стоит помнить о версии OData. Если вы используете OData v4, убедитесь, что в настройках публикации информационной базы на веб-сервере разрешен доступ к нужным объектам. Иногда ошибка 400 (Bad Request) может быть вызвана отсутствием прав доступа у пользователя, под которым выполняется подключение, или тем, что регистр не включен в состав «Состава публикуемых объектов». Для интерактивной проверки и отладки веб-запросов к опубликованной базе подойдёт обработка для тестирования REST API на платформе 1С.

Рекомендации по оптимизации запросов

При получении данных из AccumulationRegister_Продажи рекомендуется всегда ограничивать набор получаемых полей с помощью параметра $select. Это существенно снизит нагрузку на сервер и ускорит передачу данных по сети.

Пример оптимизированного запроса:


/standard.odata/AccumulationRegister_Продажи?$filter=Period ge datetime'2023-09-01T00:00:00'&$select=Period, Summa, Customer_Key, Goods_Key

Подведем итог: если вам нужна дата каждой операции — используйте основную таблицу и фильтр по полю Period. Если нужны итоги за период без детализации по дням — используйте таблицу _Turnovers с параметрами в скобках. Помните, что StartPeriod и Period — это разные сущности, используемые в разных контекстах запроса.

← На главную