Почему цена в остатках регистра накопления становится нулевой и как это исправить

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

При разработке собственных механизмов учета в 1С:Предприятие 8.3, особенно в таких сложных конфигурациях, как Комплексная автоматизация 2.4, начинающие разработчики часто сталкиваются с проблемой: приход товара в регистр отображается корректно, но после оформления расхода остаток по ресурсу Цена обнуляется или принимает неверное значение, хотя количество товара на складе еще есть. Давайте разберем по шагам, почему это происходит, и как правильно спроектировать архитектуру хранения данных.

Анализ ошибки: почему Цена не может быть ресурсом

Рассмотрим ситуацию, описанную в теме. Автор создал регистр накопления остатков СВХ_ТоварыНаКонсолидационномСкладе и добавил в него ресурс Цена. При поступлении 3 единиц товара по цене 26,48 в регистр записывается «Приход». При продаже 1 единицы по той же цене записывается «Расход».

Математика регистра накопления (тип «Остатки») работает по принципу простого сумматора. Когда мы запрашиваем остатки, платформа складывает все приходы и вычитает все расходы по каждому ресурсу в разрезе измерений. Проанализируем, что происходит с ресурсом Цена:

  1. Приход: +26,48
  2. Расход: -26,48
  3. Итог: 0

С точки зрения системы, это абсолютно логичное поведение. Регистр накопления предназначен для хранения аддитивных (суммируемых) величин. Количество и сумма — это экстенсивные показатели: если у нас есть 2 яблока и мы добавим еще 3, у нас станет 5 яблок. Цена — это интенсивная величина. Если цена одного яблока 10 рублей и цена другого 10 рублей, это не значит, что цена двух яблок — 20 рублей.

Важный вывод: Ресурсы регистра накопления остатков должны иметь физический или экономический смысл при сложении. Цена таким свойством не обладает.

Правильная структура регистра накопления

Чтобы учет работал корректно, нам необходимо изменить состав ресурсов регистра. Вместо хранения цены напрямую, мы должны хранить Количество и Сумма. Разберем правильную структуру:

В этом случае при расходе 1 единицы товара мы будем списывать не «цену», а «часть общей стоимости». Если пришло 3 шт. на сумму 79,44 (3 * 26,48), а ушло 1 шт. на сумму 26,48, то в остатке останется 2 шт. на сумму 52,96. Цена в любой момент может быть получена делением Сумма / Количество.

Реализация движений в коде

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


// Регистр СВХ_ТоварыНаКонсолидационномСкладе: ПРИХОД
Движения.СВХ_ТоварыНаКонсолидационномСкладе.Записывать = Истина;

Для Каждого ТекСтрока Из Товары Цикл
    Движение = Движения.СВХ_ТоварыНаКонсолидационномСкладе.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
    Движение.Период = Дата;
    
    // Заполняем измерения
    Движение.Номенклатура = ТекСтрока.Номенклатура;
    Движение.Склад        = Склад;
    Движение.Валюта       = ТекСтрока.Валюта;
    
    // Заполняем аддитивные ресурсы
    Движение.Количество   = ТекСтрока.Количество;
    Движение.Сумма        = ТекСтрока.Количество * ТекСтрока.Цена; // Или ТекСтрока.Сумма
    Движение.ВесБрутто    = ТекСтрока.ВесБрутто;
КонецЦикла;

Теперь рассмотрим формирование движений расхода. Здесь критически важно списывать сумму пропорционально количеству, чтобы в итоге (при нулевом остатке товара) сумма также закрылась в ноль. В сложных системах (как КА 2.4) для этого используется расчет себестоимости, но в простом варианте мы можем брать цену из документа:


// Регистр СВХ_ТоварыНаКонсолидационномСкладе: РАСХОД
Движения.СВХ_ТоварыНаКонсолидационномСкладе.Записывать = Истина;

Для Каждого ТекСтрока Из Товары Цикл
    Движение = Движения.СВХ_ТоварыНаКонсолидационномСкладе.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Дата;
    
    Движение.Номенклатура = ТекСтрока.Номенклатура;
    Движение.Склад        = Склад;
    Движение.Валюта       = ТекСтрока.Валюта;
    
    Движение.Количество   = ТекСтрока.Количество;
    // Списываем сумму, соответствующую расходу
    Движение.Сумма        = ТекСтрока.Количество * ТекСтрока.Цена; 
    Движение.ВесБрутто    = ТекСтрока.ВесБрутто;
КонецЦикла;

Как получить цену в отчетах или запросах

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


ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.Склад,
    Остатки.КоличествоОстаток,
    Остатки.СуммаОстаток,
    ВЫБОР
        КОГДА Остатки.КоличествоОстаток <> 0
            ТОГДА Остатки.СуммаОстаток / Остатки.КоличествоОстаток
        ИНАЧЕ 0
    КОНЕЦ КАК ЦенаСредняя
ИЗ
    РегистрНакопления.СВХ_ТоварыНаКонсолидационномСкладе.Остатки(&Период, ) КАК Остатки

Такой подход обеспечивает корректное вычисление средней цены (средневзвешенной), даже если товар поступал партиями по разным ценам. Это стандарт индустрии 1С-разработки.

Альтернативный вариант: Регистр сведений для цен

Выясним причину, если вам все же необходимо хранить именно "цену" как таковую (например, прайс-лист или последнюю цену закупки), а не остаток стоимости. В этом случае использование регистра накопления — ошибка архитектуры.

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

  1. Регистр накопления: Отвечает на вопрос «Сколько сейчас товара на сумму...?» (изменяется документами).
  2. Регистр сведений: Отвечает на вопрос «Какая цена установлена для этого товара на дату...?».

Если ваша задача — знать, по какой цене товар должен списываться, создайте регистр сведений ЦеныНоменклатуры с измерениями Номенклатура и ВидЦены. При проведении документа расхода программа будет обращаться к этому регистру методом СрезПоследних(), получать актуальную цену и умножать её на количество для записи в регистр накопления.

Резюме и рекомендации

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

Применяя эти принципы, вы создадите архитектуру, которая не будет «разваливаться» при сложных операциях перемещения, корректировках цен или возвратах товаров.

← На главную