При создании внешних отчетов на Системе Компоновки Данных (СКД) в 1С:Управление торговлей 10.3, особенно когда речь идет о расчете валовой прибыли и себестоимости, пользователи часто сталкиваются с ситуацией, когда данные по себестоимости корректно отображаются в консоли запросов, но исчезают при формировании отчета СКД. Давайте разберем эту проблему подробнее и выясним причины такого поведения, а также предложим варианты ее решения.
Наш пользователь столкнулся именно с такой ситуацией: он формирует отчет по валовой прибыли, где себестоимость рассчитывается на основании данных регистра накопления "Закупки". В консоли запросов все работает, но в СКД поле "Себестоимость" остается пустым или содержит нули.
Рассмотрим предложенный запрос пользователя, который лежит в основе отчета:
ВЫБРАТЬ
ЗакупкиОбороты.Период,
ЗакупкиОбороты.Организация,
ЗакупкиОбороты.ДокументЗакупки.СкладОрдер КАК Склад,
ЗакупкиОбороты.Номенклатура,
СУММА(ЗакупкиОбороты.КоличествоОборот) КАК Количество,
СУММА(ЗакупкиОбороты.СтоимостьОборот) КАК Сумма
ПОМЕСТИТЬ ТабСебестоимости
ИЗ
РегистрНакопления.Закупки.Обороты(, , ГОД, НЕ ДокументЗакупки.Ссылка = ЗНАЧЕНИЕ(Документ.ПоступлениеТоваровУслуг.ПустаяСсылка)) КАК ЗакупкиОбороты
СГРУППИРОВАТЬ ПО
ЗакупкиОбороты.Организация,
ЗакупкиОбороты.Номенклатура,
ЗакупкиОбороты.Период,
ЗакупкиОбороты.ДокументЗакупки.СкладОрдер
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПродажиОбороты.Регистратор,
ПродажиОбороты.Организация,
ПродажиОбороты.Контрагент,
ВЫБОР
КОГДА НЕ ПродажиОбороты.Регистратор.Склад ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.Склад
КОГДА НЕ ПродажиОбороты.Регистратор.СкладОрдер ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.СкладОрдер
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
КОНЕЦ КАК Склад,
ПродажиОбороты.Номенклатура,
ПродажиОбороты.КоличествоОборот,
ПродажиОбороты.СтоимостьОборот КАК СтоимостьОборот,
ВЫБОР
КОГДА ЕСТЬNULL(ТабСебестоимости.Количество, 0) <> 0
ТОГДА ПродажиОбороты.КоличествоОборот / ЕСТЬNULL(ТабСебестоимости.Количество, 0) * ЕСТЬNULL(ТабСебестоимости.Сумма, 0)
ИНАЧЕ 0
КОНЕЦ КАК Себестоимость,
ПродажиОбороты.ПериодДень,
ПродажиОбороты.ПериодНеделя,
ПродажиОбороты.ПериодДекада,
ПродажиОбороты.ПериодМесяц,
ПродажиОбороты.ПериодКвартал,
ПродажиОбороты.ПериодПолугодие,
ПродажиОбороты.ПериодГод,
ПродажиОбороты.НДСОборот,
ПродажиОбороты.СтоимостьБезСкидокОборот КАК СтоимостьОборотБезСкидок
ИЗ
РегистрНакопления.Продажи.Обороты(, , Авто, ) КАК ПродажиОбороты
ЛЕВОЕ СОЕДИНЕНИЕ ТабСебестоимости КАК ТабСебестоимости
ПО ПродажиОбороты.Номенклатура = ТабСебестоимости.Номенклатура
И (ВЫБОР
КОГДА НЕ ПродажиОбороты.Регистратор.Склад ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.Склад
КОГДА НЕ ПродажиОбороты.Регистратор.СкладОрдер ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.СкладОрдер
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
КОНЕЦ = ТабСебестоимости.Склад)
И ПродажиОбороты.Организация = ТабСебестоимости.Организация
И (ПродажиОбороты.ПериодДень МЕЖДУ ТабСебестоимости.Период И КОНЕЦПЕРИОДА(ТабСебестоимости.Период, ГОД))
Одна из наиболее распространенных причин такого поведения кроется в том, как СКД обрабатывает параметры периода для виртуальных таблиц. Когда вы создаете отчет на СКД и используете виртуальные таблицы регистров накопления, такие как РегистрНакопления.Закупки.Обороты или РегистрНакопления.Продажи.Обороты, система компоновки данных по умолчанию автоматически применяет установленные пользователем параметры начала и конца периода отчета ко всем виртуальным таблицам, если для них не заданы явные параметры.
В нашем случае, пользователь задает период для отчета (например, один день или месяц). СКД подставляет эти же границы периода в обе виртуальные таблицы: ПродажиОбороты и ЗакупкиОбороты (которая используется для формирования временной таблицы ТабСебестоимости).
Виртуальная таблица ПродажиОбороты: Здесь период может быть задан как (, , Авто, ), что означает, что СКД будет подставлять свои параметры начала и конца периода.
Виртуальная таблица ЗакупкиОбороты: В первой части запроса, формирующей ТабСебестоимости, период задан как (, , ГОД, ...). Это означает, что обороты будут браться за год, но без явного указания границ. Если СКД применит к ней свой период (например, один месяц), то вместо годовых данных мы получим данные только за этот месяц.
Если пользователь установил в отчете СКД короткий период (например, "Текущий день" или "Текущая неделя"), то при формировании ТабСебестоимости данные о закупках будут браться только за этот короткий период. Вполне вероятно, что за такой короткий срок продаж могло быть много, а закупок — ни одной или очень мало, что приведет к тому, что ЕСТЬNULL(ТабСебестоимости.Количество, 0) в выражении для "Себестоимости" будет равно нулю. Деление на ноль или умножение на нулевое количество приведет к нулевой себестоимости.
Чтобы обеспечить корректное отображение себестоимости, нам необходимо явно указать СКД, какой период использовать для получения данных о закупках. Есть несколько подходов:
Мы можем модифицировать запрос, чтобы для регистра "Закупки" всегда брался более широкий период, независимо от основного периода отчета. Для этого используются параметры СКД в фигурных скобках {&НачПериодаЗакупок} и {&КонПериодаЗакупок}. Эти параметры могут быть настроены в СКД как "Автозаполнение" или "Выражение", чтобы они всегда охватывали, например, год, месяц или любой другой нужный вам интервал, относительно основного периода отчета.
Модифицируем первую часть запроса так:
ВЫБРАТЬ
ЗакупкиОбороты.Период,
ЗакупкиОбороты.Организация,
ЗакупкиОбороты.ДокументЗакупки.СкладОрдер КАК Склад,
ЗакупкиОбороты.Номенклатура,
СУММА(ЗакупкиОбороты.КоличествоОборот) КАК Количество,
СУММА(ЗакупкиОбороты.СтоимостьОборот) КАК Сумма
ПОМЕСТИТЬ ТабСебестоимости
ИЗ
РегистрНакопления.Закупки.Обороты(
{&НачПериодаЗакупок}, // Явно указываем параметр начала периода для закупок
{&КонПериодаЗакупок}, // Явно указываем параметр конца периода для закупок
ГОД,
НЕ ДокументЗакупки.Ссылка = ЗНАЧЕНИЕ(Документ.ПоступлениеТоваровУслуг.ПустаяСсылка)
) КАК ЗакупкиОбороты
СГРУППИРОВАТЬ ПО
ЗакупкиОбороты.Организация,
ЗакупкиОбороты.Номенклатура,
ЗакупкиОбороты.Период,
ЗакупкиОбороты.ДокументЗакупки.СкладОрдер
;
Далее, в схеме компоновки данных:
Перейдите на вкладку "Параметры".
Создайте два новых параметра: НачПериодаЗакупок и КонПериодаЗакупок.
Настройте их значения. Например, для НачПериодаЗакупок можно установить выражение НАЧАЛОПЕРИОДА(&НачПериода, "ГОД"), а для КонПериодаЗакупок — КОНЕЦПЕРИОДА(&КонПериода, "ГОД"). Где &НачПериода и &КонПериода — это стандартные параметры периода вашего отчета.
Таким образом, даже если пользователь выберет период отчета "Текущий день", данные по закупкам будут браться за весь год, что значительно увеличит вероятность нахождения себестоимости.
Если вы не хотите менять текст запроса, вы можете попробовать настроить параметры виртуальной таблицы непосредственно в схеме компоновки данных:
Откройте вкладку "Наборы данных" в схеме компоновки данных.
Разверните ваш набор данных, основанный на запросе.
Найдите в списке полей виртуальную таблицу РегистрНакопления.Закупки.Обороты.
В ее свойствах вы можете увидеть, как СКД автоматически сопоставляет параметры. Здесь можно попробовать явно установить значения для параметров начала и конца периода этой виртуальной таблицы, или убедиться, что они не переопределяются параметрами основного отчета.
Важный момент: убедитесь, что в условии соединения
И (ПродажиОбороты.ПериодДень МЕЖДУ ТабСебестоимости.Период И КОНЕЦПЕРИОДА(ТабСебестоимости.Период, ГОД))
ТабСебестоимости.Период в вашем запросе сгруппирован по году, что делает сравнение с ПродажиОбороты.ПериодДень несколько неточным, если вы хотите найти себестоимость для конкретного дня, но берете ее "за год". Возможно, стоит пересмотреть логику группировки в ТабСебестоимости или условие соединения, если вы стремитесь к более точечной себестоимости, а не к среднегодовой.
Помимо настроек СКД, давайте проанализируем и другие аспекты, которые могут влиять на корректность расчета себестоимости и отображение данных в вашем отчете. Обратим внимание на замечания, высказанные в обсуждении на форуме.
Пользовательская методика расчета себестоимости по принципу "средняя за год из закупок" является упрощенной и может давать значительные отклонения от реальной фактической себестоимости, особенно в условиях динамичного рынка и сложной логистики.
В вашем запросе себестоимость рассчитывается как
ПродажиОбороты.КоличествоОборот / ЕСТЬNULL(ТабСебестоимости.Количество, 0) * ЕСТЬNULL(ТабСебестоимости.Сумма, 0)
Почему это может быть проблемой:
Партионный учет: 1С:УТ 10.3 по умолчанию использует партионный учет (ФИФО, ЛИФО, по средней), который гораздо точнее отражает себестоимость конкретной проданной партии товара. При "уничтоженном руками бухов" партионном учете (как упоминает автор), приходится прибегать к таким упрощениям. Но даже в этом случае, "средняя за год" может быть слишком обобщенной.
Динамика цен: Если закупочные цены сильно меняются в течение года, средняя цена за год не даст адекватной картины себестоимости товаров, проданных в конкретный месяц или квартал.
Дополнительные расходы: Ваш расчет не учитывает транспортные, таможенные, страховые и другие расходы, которые должны включаться в себестоимость товара. 1С:УТ 10.3 имеет механизмы для распределения дополнительных расходов, которые могут быть настроены для корректного увеличения стоимости партии.
Что можно сделать при "уничтоженном" партионном учете:
Вместо среднегодовой цены можно попробовать рассчитать среднюю себестоимость на конец предыдущего периода или скользящую среднюю. Это сложнее реализуется в запросе, но дает более точные результаты. Например, брать среднюю цену закупок за месяц или квартал, предшествующий продажам, а не за весь год.
Рассмотрим условие соединения по организации: И ПродажиОбороты.Организация = ТабСебестоимости.Организация.
Пользователь упоминает сложную схему учета, когда "товар покупается на одну контору, а продается с другой" через перемещения, а затем "убирают из перемещения". Это крайне нетипичный и проблематичный подход к учету.
Если товар действительно покупается на Организацию А, а продается с Организации Б, то условие ПродажиОбороты.Организация = ТабСебестоимости.Организация приведет к тому, что для продаж с Организации Б не будет найдено соответствующих закупок, если эти закупки были на Организацию А. В результате себестоимость снова будет нулевой.
Решение: Если межфирменные продажи (интеркампани) действительно существуют, необходимо пересмотреть логику соединения. Возможно, потребуется дополнительная временная таблица, которая будет связывать закупки одной организации с продажами другой, или же отказ от условия по организации в соединении, если это допустимо по учетной политике предприятия (что крайне редко). Корректным подходом при межфирменных продажах является оформление документа "Передача товаров между организациями" (или аналога), который формирует продажу одной организацией и покупку другой, с формированием себестоимости у принимающей организации.
В запросе используется следующее выражение для определения склада:
ВЫБОР
КОГДА НЕ ПродажиОбороты.Регистратор.Склад ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.Склад
КОГДА НЕ ПродажиОбороты.Регистратор.СкладОрдер ЕСТЬ NULL
ТОГДА ПродажиОбороты.Регистратор.СкладОрдер
ИНАЧЕ ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
КОНЕЦ
Обратите внимание, что ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) не является NULL. В выражении КОГДА НЕ ... ЕСТЬ NULL, если поля Склад и СкладОрдер будут NULL, то будет возвращена пустая ссылка. Однако в дальнейшем соединении с ТабСебестоимости.Склад, если ТабСебестоимости.Склад также содержит пустые ссылки, соединение будет работать корректно. Но если в ТабСебестоимости.Склад в аналогичных случаях ожидаются NULL, а не пустые ссылки, это может привести к нестыковкам. Всегда старайтесь использовать однотипные значения (либо NULL, либо пустые ссылки) для сравнения в условиях соединения.
Валовая прибыль и себестоимость — это комплексные показатели, на которые влияют многие факторы:
Отрицательные остатки: Если в системе возникают отрицательные остатки товаров (товар продали, а поступления еще нет), это может привести к некорректному расчету себестоимости, так как нет информации о цене закупки. Регулярно проверяйте отчеты "Ведомость по товарам на складах" или "Контроль отрицательных остатков".
Ввод документов задним числом: Исправление или ввод документов прошлым числом нарушает последовательность партионного учета, что требует перепроведения всех зависимых документов и повторного расчета себестоимости для корректного ее формирования.
Неучтенные затраты: Как уже упоминалось, если не учитываются дополнительные расходы (транспорт, страховка, таможня и т.д.), себестоимость будет занижена.
Регламентные операции: В 1С:УТ 10.3 для корректного расчета себестоимости крайне важна регламентная операция "Закрытие месяца". Она выполняет распределение затрат, списание партий по выбранному методу учета и формирует окончательную фактическую себестоимость. Если эта операция не выполняется или выполняется некорректно, данные о себестоимости могут быть неполными или неверными.
Настройки учетной политики: Проверьте настройки учетной политики организации в 1С:УТ 10.3. Особенно важны флажки "Вести партионный учет по складам" и выбранный метод списания партий (ФИФО, по средней). Отсутствие партионного учета по складам, например, может приводить к тому, что себестоимость будет рассчитываться по складу в целом, а не по конкретному складу, откуда отгружается товар.
Возвраты, оприходования, комплектации: Все эти операции также влияют на количество и стоимость товаров на складе, а значит, и на себестоимость. Ваш текущий запрос их не учитывает.
Для повышения точности и надежности вашего отчета по валовой прибыли, а также для решения проблемы с отображением себестоимости в СКД, рекомендуем выполнить следующие шаги:
Исправьте параметры периода для Закупок в СКД: Это первостепенная задача. Убедитесь, что ТабСебестоимости получает данные за достаточно широкий период, чтобы можно было найти закупки для всех продаж. Используйте явные параметры СКД, как описано выше.
Проанализируйте логику соединения по организации и складу: Если у вас есть межфирменные продажи, или же поля склада могут быть NULL или пустой ссылкой в разных регистрах, убедитесь, что условия соединения корректно обрабатывают эти сценарии.
Пересмотрите методологию расчета себестоимости: Понимая, что партионный учет "уничтожен", мы не можем использовать его полностью. Однако, можно рассмотреть более продвинутые методы, чем среднегодовая цена. Например, рассчитывать среднюю закупочную цену за предыдущий месяц или квартал. Это потребует более сложного запроса с учетом остатков и оборотов за предыдущие периоды.
По возможности, восстановите или наладьте типовой учет: Если есть шанс исправить работу бухгалтерии, то использование типовых механизмов расчета себестоимости и формирования отчетов по валовой прибыли в 1С:УТ 10.3 всегда предпочтительнее. Эти механизмы учитывают все нюансы торговых операций, включая закрытие месяца, дополнительные расходы, возвраты и т.д. В случае серьезных проблем с ведением учета, целесообразно провести инвентаризацию и скорректировать данные, чтобы выйти на корректные остатки и обороты.
Контроль отрицательных остатков: Регулярно используйте типовые отчеты для выявления и исправления отрицательных остатков, так как они являются частой причиной некорректного расчета себестоимости.
При тщательном анализе запроса, правильной настройке параметров СКД и учете особенностей вашего учета, вы сможете добиться корректного отображения себестоимости и получить адекватный отчет по валовой прибыли.