Мы часто сталкиваемся с ситуацией, когда при формировании отчетов по стоимостной оценке склада в 1С:Управление торговлей 11.4 обнаруживаются проблемы: у некоторых позиций номенклатуры не отображается цена, а общее количество и сумма задваиваются, приводя к завышенным итоговым показателям. Разберем эту проблему подробно и предложим комплексное решение.
Наш клиент столкнулся с похожей задачей. Он формировал отчет «Ведомость по товарам в ценах номенклатуры», используя «цену приобретения», и по всем позициям цена отображалась корректно. Однако при выборе другого «вида цены» (например, розничной или оптовой) цены отображались не у всех позиций. Более того, при попытке создать собственный отчет на основе запроса, номенклатура задваивалась, а общая сумма оказывалась в два раза больше реальной. Последующая ручная перезапись цены для проблемной номенклатуры временно решала проблему для отдельной позиции, что указывало на глубинные проблемы с данными.
Прежде чем перейти к решению, рассмотрим, как устроено ценообразование в 1С:УТ 11.4. В этой конфигурации предусмотрено создание нескольких видов цен, таких как розничная, оптовая, закупочная и другие. Каждый вид цены можно настроить с определенным способом задания: ручное назначение, наценка на другой вид цен, наценка на цену поступления, произвольная формула или произвольный запрос к данным. Важно, что цены могут устанавливаться не только для самой номенклатуры, но и для ее характеристик и серий, если такой учет ведется.
Основными регистрами, которые используются для стоимостной оценки склада, являются:
Мы начинаем диагностику с понимания, почему типовой отчет работает некорректно, и почему возникают дубли в наших собственных запросах. Главная проблема, как мы выяснили в ходе обсуждения, заключается в некорректном получении актуальных цен и объединении данных из регистров.
Когда мы пытаемся получить стоимость остатков товаров, нам необходимо сопоставить количество товаров на складе с их актуальной ценой. Для этого мы используем данные из двух регистров: РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты (для получения количества товаров) и РегистрСведений.ЦеныНоменклатуры.СрезПоследних (для получения актуальных цен).
Для начала, давайте убедимся, что сам регистр цен не содержит дубликатов, которые могут быть причиной задвоения. Выполним простой запрос к регистру ЦеныНоменклатуры.СрезПоследних:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ЦеныНоменклатурыСрезПоследних.Цена КАК Цена,
МАКСИМУМ(ЦеныНоменклатурыСрезПоследних.Период) КАК Период,
ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&дата, ВидЦены = &ВидЦены) КАК ЦеныНоменклатурыСрезПоследних
ГДЕ
ЦеныНоменклатурыСрезПоследних.Цена > 0
СГРУППИРОВАТЬ ПО
ЦеныНоменклатурыСрезПоследних.Цена,
ЦеныНоменклатурыСрезПоследних.Номенклатура
УПОРЯДОЧИТЬ ПО
Номенклатура
В нашем случае, даже этот запрос возвращал дубликаты, например, для одной и той же номенклатуры могли быть указаны разные цены (193 рубля и 205 рублей). Это говорит о том, что в самом регистре цен существуют несколько записей для одной номенклатуры на одну и ту же дату (или близкие даты, которые попадают в «срез последних»).
При дальнейшем анализе мы обнаружили, что номенклатура задваивается из-за использования серий. Оказалось, что Серия является измерением как в регистре «ЦеныНоменклатуры», так и в регистре «ТоварыНаСкладах». Если мы не учитываем серию при объединении этих регистров, то для одной номенклатуры могут быть найдены несколько цен (если цены установлены для разных серий) или несколько остатков (если товары разных серий находятся на складе), что приводит к дублированию строк и некорректным суммам.
Например, если на складе есть 10 штук товара А (серия 1) и 20 штук товара А (серия 2), и мы не связываем по серии, то при получении цены для товара А, система может найти одну цену, которая затем умножится на 10 и на 20, или найти две разные цены (если цены зависят от серии), но не сможет их правильно агрегировать без учета серии как измерения.
Для получения правильной стоимостной оценки склада нам необходимо корректно объединить данные из регистров ТоварыНаСкладах.ОстаткиИОбороты и ЦеныНоменклатуры.СрезПоследних. Ключевым моментом является правильное указание условий связи, включая все релевантные измерения, такие как номенклатура, вид цены и серия.
Предлагаем использовать следующий запрос для формирования стоимостной оценки склада:
ВЫБРАТЬ
ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
СУММА(ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток) КАК КоличествоНаСкладе,
СУММА(ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток * ЦеныНоменклатурыСрезПоследних.Цена) КАК СуммаОценки
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты КАК ТоварыНаСкладахОстаткиИОбороты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
ПО (ТоварыНаСкладахОстаткиИОбороты.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
И ТоварыНаСкладахОстаткиИОбороты.Серия = ЦеныНоменклатурыСрезПоследних.Серия
И ЦеныНоменклатурыСрезПоследних.ВидЦены = &ВидЦены)
ГДЕ
ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток > 0
СГРУППИРОВАТЬ ПО
ТоварыНаСкладахОстаткиИОбороты.Номенклатура
УПОРЯДОЧИТЬ ПО
Номенклатура
Разберем этот запрос по частям:
ИЗ РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты КАК ТоварыНаСкладахОстаткиИОбороты: Мы начинаем с получения всех остатков и оборотов товаров на складах. Виртуальная таблица ОстаткиИОбороты позволяет нам получить конечный остаток товаров на определенную дату (которая неявно передается в параметрах виртуальной таблицы, если запрос строится в СКД, или должна быть явно указана).ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних: Мы выполняем левое соединение с регистром сведений «ЦеныНоменклатуры», используя его виртуальную таблицу СрезПоследних. Это гарантирует, что мы получим только актуальные (последние) цены на интересующую нас дату.ПО (ТоварыНаСкладахОстаткиИОбороты.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура И ТоварыНаСкладахОстаткиИОбороты.Серия = ЦеныНоменклатурыСрезПоследних.Серия И ЦеныНоменклатурыСрезПоследних.ВидЦены = &ВидЦены): Это самый критичный участок запроса. Здесь мы указываем условия связи:
ТоварыНаСкладахОстаткиИОбороты.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура: связываем по самой номенклатуре.ТоварыНаСкладахОстаткиИОбороты.Серия = ЦеныНоменклатурыСрезПоследних.Серия: обязательно связываем по серии! Это предотвращает задвоение записей, если цены или остатки учитываются в разрезе серий.ЦеныНоменклатурыСрезПоследних.ВидЦены = &ВидЦены: фильтруем по конкретному виду цены, который нам нужен для оценки (например, «Цена приобретения», «Розничная цена» и т.д.). Передаем это значение как параметр запроса.Перенос условия по ВидЦены в условие связи ПО для ЛЕВОЕ СОЕДИНЕНИЕ является предпочтительным, так как это позволяет получить все товары со склада, даже если для них нет цены выбранного вида, но при этом гарантирует, что цена будет присоединена только при совпадении вида.
ГДЕ ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток > 0: Мы фильтруем только те позиции, которые фактически есть на складе.СГРУППИРОВАТЬ ПО ТоварыНаСкладахОстаткиИОбороты.Номенклатура: Это позволяет нам агрегировать данные по каждой номенклатуре. Если одна и та же номенклатура представлена разными сериями на складе, и для каждой серии есть своя цена, то этот пункт гарантирует, что все эти остатки и их суммарная стоимость будут объединены в одну строку по номенклатуре.СУММА(ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток) КАК КоличествоНаСкладе и СУММА(ТоварыНаСкладахОстаткиИОбороты.ВНаличииКонечныйОстаток * ЦеныНоменклатурыСрезПоследних.Цена) КАК СуммаОценки: Мы суммируем количество и общую стоимость для каждой номенклатуры.Даже самый идеальный запрос не поможет, если в базе данных отсутствуют необходимые сведения. Как выяснилось в нашей ситуации, основная и самая «грубая» ошибка заключалась в процессе перехода на новую конфигурацию 1С:УТ 11.
При миграции данных, когда производился ввод начальных остатков, цены были установлены только для вида цены «Цена приобретения». Для всех остальных видов цен (розничная, оптовая и т.д.) записи в регистре «ЦеныНоменклатуры» просто отсутствовали или были неактуальны. Именно поэтому типовой отчет «Ведомость по товарам в ценах номенклатуры» показывал цены только для «цены приобретения», а для других видов цен поля оставались пустыми.
Дополнительно мы выяснили, что даже если цены были установлены для серий, для номенклатуры без серий цены могли отсутствовать, что также приводило к проблемам.
Важный вывод: некорректная стоимостная оценка склада чаще всего является следствием либо ошибок в данных (отсутствие или неактуальность цен), либо неправильного формирования запросов, не учитывающих все измерения (такие как серии). Комплексный подход, включающий проверку данных, корректировку запросов и понимание механизмов ценообразования, позволит нам добиться точной и надежной стоимостной оценки наших запасов.