Как вывести последнюю цену реализации в отчете по товародвижению в 1С:ERP 2.2 и избежать дублирования строк?

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

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

Разбор проблемы: почему дублируются строки?

Проанализируем типичную ошибку. В языке запросов 1С существует жесткое правило: все поля, указанные в секции ВЫБРАТЬ, должны либо быть обернуты в агрегатную функцию (например, СУММА, МАКСИМУМ), либо присутствовать в секции СГРУППИРОВАТЬ ПО.

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

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

Выбор источника данных для цены

В ERP 2.2 для анализа товародвижения чаще всего используется регистр накопления СебестоимостьТоваров. Рассмотрим, какие данные мы можем из него извлечь:

  1. Цена прихода: Рассчитывается как СтоимостьПриход / КоличествоПриход.
  2. Цена расхода (себестоимость): Рассчитывается как СтоимостьРасход / КоличествоРасход.
  3. Учетная цена остатка: Рассчитывается как СтоимостьКонечныйОстаток / КоличествоКонечныйОстаток.

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

Алгоритм получения последней цены через временные таблицы

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

Шаг 1: Получение максимальной даты. Сначала нам нужно выяснить, когда в последний раз была отгрузка или приход по конкретной аналитике (номенклатура, склад, организация).


ВЫБРАТЬ
    СебестоимостьТоваров.АналитикаУчетаНоменклатуры.Номенклатура КАК Номенклатура,
    СебестоимостьТоваров.АналитикаУчетаНоменклатуры.Склад КАК Склад,
    СебестоимостьТоваров.Организация КАК Организация,
    МАКСИМУМ(СебестоимостьТоваров.Период) КАК ДатаПоследнегоРасхода
ПОМЕСТИТЬ ВТ_МаксДаты
ИЗ
    РегистрНакопления.СебестоимостьТоваров.ОстаткиИОбороты(&НачалоВремен, &КонецПериода, Регистратор, , ) КАК СебестоимостьТоваров
ГДЕ
    СебестоимостьТоваров.КоличествоРасход > 0
СГРУППИРОВАТЬ ПО
    СебестоимостьТоваров.АналитикаУчетаНоменклатуры.Номенклатура,
    СебестоимостьТоваров.АналитикаУчетаНоменклатуры.Склад,
    СебестоимостьТоваров.Организация
;

Шаг 2: Получение цены на эту дату. Теперь мы соединяем нашу таблицу ВТ_МаксДаты с самим регистром, чтобы забрать стоимость и количество именно из того регистратора, который сделал последнюю запись.


ВЫБРАТЬ
    ВТ_МаксДаты.Номенклатура,
    ВТ_МаксДаты.Склад,
    ВТ_МаксДаты.Организация,
    МАКСИМУМ(Себестоимость.СтоимостьРасход / Себестоимость.КоличествоРасход) КАК Цена
ПОМЕСТИТЬ ПоследняяОтгрузка
ИЗ
    ВТ_МаксДаты КАК ВТ_МаксДаты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров.ОстаткиИОбороты(&НачалоВремен, &КонецПериода, Регистратор, , ) КАК Себестоимость
    ПО ВТ_МаксДаты.Номенклатура = Себестоимость.АналитикаУчетаНоменклатуры.Номенклатура
        И ВТ_МаксДаты.ДатаПоследнегоРасхода = Себестоимость.Период
        И ВТ_МаксДаты.Склад = Себестоимость.АналитикаУчетаНоменклатуры.Склад
СГРУППИРОВАТЬ ПО
    ВТ_МаксДаты.Номенклатура,
    ВТ_МаксДаты.Склад,
    ВТ_МаксДаты.Организация
;

Объединение логики: цена продажи + цена остатка

Выясним причину, по которой отчет может показывать пустые значения. Если за выбранный период не было продаж, поле Цена будет равно 0 или NULL. Проанализируем ситуацию, когда нам нужно подставить цену из остатков, если реализации не было.

Для этого в финальном запросе мы будем использовать конструкцию ВЫБОР. Рассмотрим пример реализации:


ВЫБРАТЬ
    Движения.Номенклатура,
    Движения.Склад,
    СУММА(Движения.КоличествоПриход) КАК Приход,
    СУММА(Движения.КоличествоРасход) КАК Расход,
    // Расчет цены: приоритет расходу, затем остатку
    ВЫБОР
        КОГДА СУММА(Движения.КоличествоРасход) > 0
            ТОГДА СУММА(Движения.СтоимостьРасход) / СУММА(Движения.КоличествоРасход)
        ИНАЧЕ ВЫБОР
            КОГДА СУММА(Движения.КоличествоКонечныйОстаток) > 0
                ТОГДА СУММА(Движения.СтоимостьКонечныйОстаток) / СУММА(Движения.КоличествоКонечныйОстаток)
            ИНАЧЕ 0
        КОНЕЦ
    КОНЕЦ КАК Цена
ИЗ
    РегистрНакопления.СебестоимостьТоваров.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК Движения
СГРУППИРОВАТЬ ПО
    Движения.Номенклатура,
    Движения.Склад

Важное предостережение: Обратите внимание, что в примере выше расчет цены производится после суммирования. Это критически важно. Мы делим СУММА(Стоимость) на СУММА(Количество). Таким образом, мы получаем среднюю цену за период, что исключает дублирование строк в группировке СГРУППИРОВАТЬ ПО.

Итоговые рекомендации по доработке

Если вы хотите, чтобы ваш отчет работал корректно и не вызывал нареканий пользователей, следуйте этим правилам:

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

← На главную