При работе с конфигурацией 1С:Розница программисты и аналитики часто сталкиваются с ситуацией, когда отчеты по остаткам в стоимостном выражении начинают «врать». Вроде бы количественный учет ведется верно, приходы и расходы совпадают с первичными документами, но итоговая сумма в отчете не бьется с реальностью. Рассмотрим эту проблему подробно, разберем архитектурные особенности программы и выясним, как правильно строить запросы для получения корректных данных.
Первое и самое важное, что мы должны понимать при работе с 1С:Розница: в этой конфигурации по умолчанию отсутствует полноценный партионный учет. В отличие от более тяжелых решений, таких как «1С:Управление торговлей» или «1С:ERP», здесь нет регистров, которые бы жестко связывали каждую проданную единицу товара с конкретной поставкой (партией) по методу FIFO или LIFO.
Проанализируем ситуацию: как программа понимает, сколько стоит товар на складе? Она использует регистр сведений СебестоимостьНоменклатуры. В этот регистр записывается цена при каждом поступлении товара. Проблема заключается в том, что когда мы формируем отчет на ретроспективную дату (например, смотрим остатки на начало года), отчет зачастую обращается к последней известной цене из этого регистра. Если в феврале товар подорожал, то отчет за январь может пересчитать все остатки по новой цене, что и создает иллюзию «пропажи» или «появления» денег.
Рассмотрим пример кода, который часто используется в доработанных отчетах для получения «себестоимости на дату». Проанализируем, где здесь кроется ловушка. В типовых или кастомных решениях можно встретить конструкцию, выбирающую первый регистратор с конца:
ВЫБРАТЬ ПЕРВЫЕ 1
Себестоимость.Регистратор
ИЗ
РегистрСведений.СебестоимостьНоменклатуры КАК Себестоимость
ГДЕ
(Себестоимость.Магазин = &Магазин ИЛИ Себестоимость.Магазин = ЗНАЧЕНИЕ(Справочник.Магазины.ПустаяСсылка))
И Себестоимость.Номенклатура = &Номенклатура
И Себестоимость.Период <= &Период
УПОРОДОЧИТЬ ПО
Себестоимость.Период УБЫВ,
Себестоимость.Регистратор УБЫВ
Разберем этот алгоритм. Программа ищет последнюю запись в регистре сведений до указанной даты. Если мы купили краску в январе по 100 рублей, а в феврале — по 200 рублей, то при формировании отчета за март по такой логике система умножит весь остаток (включая январский) на 200 рублей. Это главная причина, по которой возникают расхождения с «фактом» в таблицах Excel, которые ведут бухгалтеры или товароведы вручную.
Прежде чем переписывать код, необходимо убедиться, что база данных находится в целостном состоянии. Иногда расхождения вызваны не логикой запроса, а «кривыми» итогами в регистрах накопления. Выполним следующие действия:
ТоварыНаСкладах.Как показывает практика, фраза «все приходуется правильно» от товароведа часто не соответствует действительности. Проанализируем типичные ошибки пользователей:
Установка цен номенклатуры или запись в регистр себестоимости сделаны позже, чем отчет пытается их прочитать, мы получим нулевую стоимость.Для выявления таких проблем рекомендуется сформировать типовой отчет Ведомость по товарам на складах и сравнить его количественные показатели с вашим отчетом. Если количество сходится, значит, проблема исключительно в механизме определения цены (себестоимости).
Чтобы отчет стал более точным, нам нужно соединить таблицу остатков с таблицей цен таким образом, чтобы цена бралась именно на тот момент времени, который нас интересует. Посмотрим на пример более сложного запроса, который учитывает характеристики и магазины:
ВЫБРАТЬ РАЗРЕШЕННЫЕ
Остатки.Номенклатура,
Остатки.КоличествоОстаток,
ЕСТЬNULL(СебестоимостьНоменклатуры.Цена, 0) * Остатки.КоличествоОстаток КАК Себестоимость
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, ) КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СебестоимостьНоменклатуры КАК СебестоимостьНоменклатуры
ПО Остатки.Номенклатура = СебестоимостьНоменклатуры.Номенклатура
И Остатки.Характеристика = СебестоимостьНоменклатуры.Характеристика
И СебестоимостьНоменклатуры.Регистратор В (
ВЫБРАТЬ ПЕРВЫЕ 1 Т.Регистратор
ИЗ РегистрСведений.СебестоимостьНоменклатуры КАК Т
ГДЕ Т.Номенклатура = Остатки.Номенклатура
И Т.Период <= &Период
УПОРЯДОЧИТЬ ПО Т.Период УБЫВ
)
Важный нюанс: Даже такой запрос в условиях 1С:Розница не является «партионным». Он лишь берет последнюю цену до указанной даты. Если вы хотите видеть реальную картину движения денег с учетом каждой закупки, единственным верным решением будет внедрение полноценного партионного учета (что требует серьезной переработки конфигурации) или переход на «1С:Управление торговлей».
Подводя итог, можно сделать следующие выводы. Если ваши остатки «разъезжаются» с фактом в 1С:Розница:
Поступление товаров и Оприходование.РегистрСведений.СебестоимостьНоменклатуры — это не регистр накопления, он не хранит «сумму остатка», он хранит лишь «цену записи».Тестирование и исправление для профилактики логических ошибок в итогах.Таким образом, «аномалии» в 1С:Розница чаще всего оказываются либо следствием упрощенной архитектуры программы, либо результатом человеческих ошибок при вводе данных. Понимание работы механизма ВЫБРАТЬ ПЕРВЫЕ 1 в связке с периодом поможет вам создавать более предсказуемые и точные отчеты.