Как получить себестоимость номенклатуры в реализациях 1С:Бухгалтерии, избегая задвоений и медленных запросов?

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

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

Понимание проблемы: Задвоение данных и некорректный расчет себестоимости

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


ВЫБРАТЬ
    ЛОЖЬ КАК Признак,
    РеализацияТоваровУслугТовары.Ссылка.Дата КАК Дата,
    РеализацияТоваровУслугТовары.Ссылка КАК ДокументПартии,
    РеализацияТоваровУслугТовары.Номенклатура,
    РеализацияТоваровУслугТовары.Цена,
    РеализацияТоваровУслугТовары.Количество КАК КоличествоОтгружено,
    РеализацияТоваровУслугТовары.Коэффициент,
    РеализацияТоваровУслугТовары.СтавкаНДС,
    РеализацияТоваровУслугТовары.Сумма КАК СуммаОтгружено,
    РеализацияТоваровУслугТовары.СуммаНДС КАК СуммаНДСОтгружено,
    РеализацияТоваровУслугТовары.Склад,
    РеализацияТоваровУслугТовары.ЕдиницаИзмерения,
    1 КАК Курс,
    ПоступлениеТоваровУслугТовары.ЦенаВРубляхБезНДС
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        ПО РеализацияТоваровУслугТовары.Ссылка = РеализацияТоваровУслуг.Ссылка
        ПОЛНОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
        ПО (ПоступлениеТоваровУслугТовары.Номенклатура = РеализацияТоваровУслугТовары.Номенклатура)
ГДЕ
    РеализацияТоваровУслугТовары.Ссылка.Контрагент = &Контрагент
    И РеализацияТоваровУслугТовары.Ссылка.Проведен
    И РеализацияТоваровУслугТовары.Ссылка.Дата < &Дата
    И РеализацияТоваровУслугТовары.Номенклатура = &Номенклатура
УПОРЯДОЧИТЬ ПО
    Дата УБЫВ

Основная причина задвоения данных в этом запросе кроется в строке:


ПОЛНОЕ СОЕДИНЕНИЕ Документ.ПоступлениеТоваровУслуг.Товары КАК ПоступлениеТоваровУслугТовары
ПО (ПоступлениеТоваровУслугТовары.Номенклатура = РеализацияТоваровУслугТовары.Номенклатура)

Когда мы используем ПОЛНОЕ СОЕДИНЕНИЕ (или даже ЛЕВОЕ СОЕДИНЕНИЕ) таблицы товаров из реализации с таблицей товаров из поступления только по полю Номенклатура, возникает следующая ситуация: по одной и той же номенклатуре может быть несколько документов поступления, и каждый из них может иметь свою цену. Запрос попытается связать каждую строку реализации с каждой подходящей строкой поступления, что приводит к появлению множества одинаковых строк реализации с разными ценами поступления. Именно это вызывает задвоение, когда для одной реальной реализации система выводит 5-10 строк с разными ценами поступления, и лишь одна из них может быть косвенно верной для конкретной партии, если вообще такая связь имеет смысл.

Более того, прямое взятие ПоступлениеТоваровУслугТовары.ЦенаВРубляхБезНДС из документа поступления не является корректным способом определения фактической себестоимости реализованного товара. Себестоимость товара в 1С определяется в соответствии с учетной политикой организации (например, по средней стоимости, ФИФО) и окончательно рассчитывается регламентными операциями при закрытии месяца. Цена в документе поступления – это всего лишь цена приобретения, а не себестоимость отгруженной партии, которая могла быть сформирована из разных поступлений.

Корректное получение себестоимости отгрузок через регистр бухгалтерии

Для получения истинной себестоимости реализованных товаров нам необходимо обратиться к РегиструБухгалтерии.Хозрасчетный. Именно здесь фиксируются проводки, отражающие списание себестоимости товаров при их реализации. В бухгалтерском учете операция реализации товара сопровождается проводкой по дебету счета учета себестоимости продаж (например, 90.02 "Себестоимость продаж") и кредиту счета учета товаров (например, 41 "Товары"). Сумма, отраженная по дебету счета 90.02, и будет являться фактической себестоимостью отгруженного товара.

Разберем по шагам, как построить запрос для получения себестоимости:

  1. Исходные данные: Начнем с таблицы товаров документа РеализацияТоваровУслуг. Это будет наша "левая" таблица в соединении.
  2. Регистр бухгалтерии: Присоединим к ней виртуальную таблицу ДвиженияССубконто регистра бухгалтерии Хозрасчетный. Эта таблица предоставляет информацию о проводках, включая счета дебета/кредита, субконто и суммы.
  3. Условия соединения:
    • Свяжем РеализацияТоваровУслугТовары.Ссылка (ссылку на документ реализации) с ХозрасчетныйДвиженияССубконто.Регистратор. Это гарантирует, что мы рассматриваем проводки, сформированные именно этой реализацией.
    • Отфильтруем движения по счету дебета. В большинстве конфигураций 1С:Бухгалтерия для отражения себестоимости реализованных товаров используется счет 90.02 "Себестоимость продаж". Таким образом, условие будет ХозрасчетныйДвиженияССубконто.СчетДт = &СчетСебестоимостиПродаж.
    • Дополнительно можем связать по номенклатуре, используя субконто. В зависимости от настроек учета, номенклатура может быть одним из субконто счета 90.02 (например, ХозрасчетныйДвиженияССубконто.СубконтоДт1 = РеализацияТоваровУслугТовары.Номенклатура).
  4. Тип соединения: Используем ЛЕВОЕ СОЕДИНЕНИЕ, чтобы получить все строки из реализации, даже если по какой-то причине соответствующая проводка не найдена (хотя для проведенных документов это маловероятно).

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


ВЫБРАТЬ
    РеализацияТоваровУслугТовары.Ссылка.Дата КАК ДатаРеализации,
    РеализацияТоваровУслугТовары.Ссылка КАК ДокументРеализации,
    РеализацияТоваровУслугТовары.Номенклатура,
    РеализацияТоваровУслугТовары.Количество КАК КоличествоОтгружено,
    РеализацияТоваровУслугТовары.Сумма КАК СуммаРеализации,
    ХозрасчетныйДвижения.Сумма КАК СебестоимостьОтгрузки,
    ХозрасчетныйДвижения.КоличествоДт КАК КоличествоВПроводке
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
            НАЧАЛОПЕРИОДА(&ДатаНачала, ДЕНЬ),
            КОНЕЦПЕРИОДА(&ДатаОкончания, ДЕНЬ),
            СчетДт = &СчетСебестоимостиПродаж,
            ВидСубконтоДт1 = &ВидСубконтоНоменклатура,
            СубконтоДт1 В ИЕРАРХИИ (&Номенклатура)
        ) КАК ХозрасчетныйДвижения
        ПО РеализацияТоваровУслугТовары.Ссылка = ХозрасчетныйДвижения.Регистратор
        И РеализацияТоваровУслугТовары.Номенклатура = ХозрасчетныйДвижения.СубконтоДт1
ГДЕ
    РеализацияТоваровУслугТовары.Ссылка.Контрагент = &Контрагент
    И РеализацияТоваровУслугТовары.Ссылка.Проведен
    И РеализацияТоваровУслугТовары.Ссылка.Дата < &ДатаФильтрПоДатеРеализации
УПОРЯДОЧИТЬ ПО
    ДатаРеализации УБЫВ

В этом запросе мы используем виртуальную таблицу ДвиженияССубконто с параметрами периода и фильтром по счету дебета и субконто. Это позволяет значительно сузить объем данных, выбираемых из регистра бухгалтерии, до соединения, что положительно сказывается на производительности. Параметры &ДатаНачала и &ДатаОкончания должны охватывать период, в который могли произойти реализации. &СчетСебестоимостиПродаж обычно равен предопределенному значению ПланыСчетов.Хозрасчетный.СебестоимостьПродаж или, если его нет, можно найти по коду (например, "90.02"). &ВидСубконтоНоменклатура также можно получить из метаданных или через запрос к ПланамВидовХарактеристик.

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

Оптимизация запросов с использованием временных таблиц

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

Принцип работы с временными таблицами:

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

Пример структуры запроса с временными таблицами:


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

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

// Шаг 3: Соединяем временные таблицы и получаем итоговый результат
ВЫБРАТЬ
    ВТ_Реализации.ДатаРеализации,
    ВТ_Реализации.ДокументРеализации,
    ВТ_Reaлизация.Номенклатура,
    ВТ_Реализации.КоличествоОтгружено,
    ВТ_Реализации.СуммаРеализации,
    ВТ_Себестоимость.ОбщаяСебестоимость,
    ВТ_Себестоимость.ОбщееКоличествоСебестоимость
ИЗ
    ВТ_Реализации КАК ВТ_Реализации
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Себестоимость КАК ВТ_Себестоимость
        ПО ВТ_Реализации.ДокументРеализации = ВТ_Себестоимость.ДокументРеализации
        И ВТ_Реализации.Номенклатура = ВТ_Себестоимость.Номенклатура
УПОРЯДОЧИТЬ ПО
    ВТ_Реализации.ДатаРеализации УБЫВ

Такой подход позволяет СУБД сначала обработать меньшие объемы данных, создать для них эффективные индексы во временных таблицах, а затем выполнить быстрое соединение уже подготовленных данных. Это особенно эффективно на больших объемах информации.

Важность правильного выбора типа соединения

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

Подведем итог. Для получения достоверной себестоимости реализованной номенклатуры в 1С:Бухгалтерии необходимо:

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

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

← На главную