Как получить корректную себестоимость по менеджерам, если в регистре себестоимости отсутствует это измерение?

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

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

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

Рассмотрим ситуацию на конкретном примере. Предположим, в одном документе реализации были проданы «Тапочки меховые» в количестве 3 штук. Из них 1 штука закреплена за менеджером Ивановым, а 2 штуки — за Петровым (это возможно, если менеджер указывается в табличной части документа). В регистре Продажи мы увидим две строки. Однако в регистре ПродажиСебестоимость аналитика по менеджеру отсутствует, и там будет зафиксирована одна запись на общую сумму себестоимости для всех 3 штук.

При обычном левом или внутреннем соединении по номенклатуре и регистратору мы получим ситуацию, когда к каждой строке продаж (и Иванова, и Петрова) прицепится вся сумма себестоимости документа, либо данные распределятся непредсказуемо при использовании агрегатных функций. Наша задача — распределить общую себестоимость пропорционально количеству проданного товара каждым менеджером.

Решение 1: Распределение себестоимости через запрос (математический метод)

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

Рассмотрим пример реализации такого запроса:


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

Важный нюанс: В этом подходе мы используем ВНУТРЕННЕЕ СОЕДИНЕНИЕ по полям Номенклатура и Регистратор. Обратите внимание, что в подзапросе себестоимости мы предварительно суммируем все записи, чтобы получить «вес» документа в целом. Это позволяет избежать дублирования сумм при соединении с несколькими менеджерами.

Решение 2: Использование временных таблиц для оптимизации

Использование подзапросов в соединении (как в примере выше) считается плохой практикой в 1С, так как это затрудняет работу оптимизатора СУБД. Разберем, как сделать этот запрос более «правильным» с точки зрения производительности.

  1. Создаем временную таблицу продаж: Выбираем данные из регистра продаж с группировкой по менеджеру и номенклатуре.
  2. Создаем временную таблицу себестоимости: Выбираем данные из регистра себестоимости, группируя только по номенклатуре и регистратору.
  3. Соединяем таблицы: В финальном запросе выполняем расчет пропорции.

Проанализируем преимущество этого метода: система сначала подготовит два компактных набора данных, проиндексирует их по регистратору и номенклатуре, и только потом выполнит соединение. Это значительно ускорит выполнение отчета на больших объемах данных.

Решение 3: Архитектурное изменение (добавление измерения или реквизита)

Если отчет планируется использовать часто и на больших базах, постоянные сложные вычисления в запросах могут перегрузить сервер. В таком случае стоит рассмотреть изменение структуры регистра ПродажиСебестоимость.

Здесь есть два пути:

  1. Добавление измерения "Менеджер": Это самый радикальный метод. Он позволит получать данные простым соединением без всяких расчетов. Однако помните о рисках: добавление измерения увеличивает размер таблиц итогов и может замедлить проведение документов «Расчет себестоимости», так как системе придется хранить остатки и обороты в более глубоком разрезе.
  2. Добавление реквизита "Менеджер": Реквизиты не участвуют в формировании итогов, поэтому они практически не влияют на производительность при записи. Вы сможете заполнять этот реквизит при проведении документа реализации. Для отчета это будет идеальным решением: вы просто выбираете данные напрямую из регистра себестоимости по этому реквизиту.

Как отмечают участники обсуждения, если конфигурация нетиповая (или находится на поддержке с возможностью изменений), добавление аналитики в регистр — наиболее надежный путь, исключающий ошибки округления при делении в запросах.

Технические нюансы и подводные камни

При реализации любого из предложенных решений следует учитывать специфику работы механизмов себестоимости в типовых решениях (например, в УПП или КА):

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

2. Корректировки стоимости. Помните, что окончательная себестоимость часто формируется в конце месяца регламентным документом (например, «Расчет себестоимости»). Этот документ может делать записи без привязки к конкретным строкам табличной части реализации. Если вы соединяете данные по полю Регистратор, убедитесь, что корректировочные записи также имеют ссылку на исходный документ продажи.

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

4. Округление. При делении суммы себестоимости на общее количество и последующем умножении на долю менеджера могут возникать погрешности в копейках. Для финансовой отчетности это может быть критично. Если требуется абсолютная точность, последний менеджер в списке должен получать «остаток» от общей суммы себестоимости, чтобы сумма частей всегда равнялась целому.

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

← На главную