Как построить отчет по остаткам и оборотам товаров в разрезе ответственного лица в 1С?

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

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

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

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


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

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

  1. Отсутствие измерения в регистре накопления: В типовой конфигурации регистр ТоварыНаСкладах хранит итоги исключительно в разрезе измерений (Склад, Номенклатура, ХарактеристикаНоменклатуры, СерияНоменклатуры). Поле Ответственный — это реквизит документа (Регистратор), а не регистра. Физически платформа 1С не хранит и не рассчитывает остатки по авторам документов.
  2. Задвоение остатков при соединении: В первой временной таблице остаток сгруппирован по паре «Склад — Номенклатура» (одна строка). Во второй таблице обороты развернуты по документам и ответственным (несколько строк за период). При выполнении соединения ПОЛНОЕ СОЕДИНЕНИЕ одна строка остатка соединяется со всеми строками оборотов. При расчете итогов (СУММА(НачальныйОстаток)) начальный остаток суммируется столько раз, сколько различных движений совершили ответственные лица за выбранный период.
  3. Методологическая некорректность: Понятие «остаток по менеджеру» не имеет физического смысла при типовой схеме учета. Если товар оприходовал один сотрудник, а списал другой, списание не привязывается к партии или менеджеру прихода. В результате по одному сотруднику получится вечно растущий положительный остаток, а по другому — отрицательный.
  4. Снижение производительности: Конструкция Регистратор.Ответственный выполняет неявное левое соединение (LEFT JOIN) ко всем таблицам документов, выступающих регистраторами регистра ТоварыНаСкладах, что существенно замедляет выполнение запроса на реальных базах.

Способ 1. Разделение остатков и оборотов в Системе компоновки данных (СКД)

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

Разберем реализацию этого способа по шагам:

  1. Создадим схему компоновки данных с виртуальной таблицей ОстаткиИОбороты регистра ТоварыНаСкладах с периодичностью Авто или Регистратор.
  2. В запросе выберем поле Регистратор.Ответственный КАК Ответственный.
  3. Перейдем на вкладку Ресурсы:
    1. Для полей КоличествоПриход и КоличествоРасход оставляем стандартное выражение Сумма(КоличествоПриход) и Сумма(КоличествоРасход), рассчитывая их по всем группировкам.
    2. Для полей КоличествоНачальныйОстаток и КоличествоКонечныйОстаток снимаем флаги расчета для группировки Ответственный и Регистратор. Расчет остатка оставляем только для группировок Склад, Номенклатура и ОбщийИтог.
  4. В структуре отчета строим иерархию: Склад -> Номенклатура -> Ответственный. В строках с ответственными лицами будут заполняться только колонки прихода и расхода, а остатки будут корректно выводиться на уровнях номенклатуры и склада без искажения сумм.

Способ 2. Использование материально ответственного лица (МОЛ) склада

Если задача состоит в том, чтобы отслеживать остатки за конкретным материально ответственным лицом, привязку следует делать не через создателя документа, а через справочник Склады. В этом случае остаток однозначно привязан к складу, за который отвечает конкретный сотрудник:


ВЫБРАТЬ
    ТоварыНаСкладахОстаткиИОбороты.Склад КАК Склад,
    ТоварыНаСкладахОстаткиИОбороты.Склад.МОЛ КАК Ответственный,
    ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
    ТоварыНаСкладахОстаткиИОбороты.КоличествоНачальныйОстаток КАК НачальныйОстаток,
    ТоварыНаСкладахОстаткиИОбороты.КоличествоПриход КАК КоличествоПриход,
    ТоварыНаСкладахОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
    ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КонечныйОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&ДатаНач, &ДатаКон, Авто, Движения, ) КАК ТоварыНаСкладахОстаткиИОбороты

Так как МОЛ является реквизитом склада, начальные и конечные остатки рассчитываются средствами платформы 1С и полностью сходятся на любую дату.

Способ 3. Доработка структуры регистра (персональный учет остатков)

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

  1. Добавить новое измерение Ответственный (тип СправочникСсылка.Пользователи или СправочникСсылка.ФизическиеЛица) в регистр накопления ТоварыНаСкладах.
  2. Модифицировать модули проведения всех документов движения товаров (Поступление, Реализация, Перемещение, Списание), чтобы в движения всегда записывался конкретный ответственный.
  3. Доработать алгоритмы списания: при проведении расходных документов контролировать остатки по конкретному ответственному или списывать товар по четко определенным правилам, иначе неизбежно возникновение отрицательных остатков по сотрудникам.

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

← На главную