Как реализовать расчет стоимости по методу Средневзвешенная-скользящая?

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

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

Понятие метода средневзвешенной скользящей

Для начала проанализируем саму суть метода. Средневзвешенная скользящая стоимость (Moving Average) рассчитывается непосредственно в момент совершения операции выбытия товара (продажи, списания). В отличие от периодической средней, которая считается один раз в конце отчетного периода, скользящая средняя учитывает только те поступления, которые физически произошли до текущей продажи.

Рассмотрим формулу, по которой определяется сумма списания:

СуммаСписания = (СуммаОстаткаВРегистре / КоличествоОстаткаВРегистре) * КоличествоКсписанию

Разграничение цены продажи и себестоимости

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

Себестоимость же, рассчитанная по методу средней, — это внутренняя учетная величина. Она не должна подставляться в колонку «Цена» табличной части документа. Покупатель не должен видеть нашу закупочную стоимость. Расчет средней стоимости выполняется «невидимо» для пользователя в момент нажатия кнопки Провести. Результат этого расчета записывается только в движения регистра накопления ОстаткиТоваров (или Продажи), уменьшая суммовой остаток склада.

Где реализовывать алгоритм: Модуль формы или Модуль объекта?

Разберем, почему расчет нельзя делать в модуле формы при событии ПриИзменении количества. Программисты должны понимать следующие риски:

  1. Актуальность данных: Пока пользователь заполняет накладную, другой сотрудник может провести документ поступления или списания. Данные об остатках в базе изменятся, и цена, рассчитанная в форме, станет неверной к моменту нажатия кнопки «ОК».
  2. Транзакционность: Проведение документа — это неделимая операция. Только в модуле объекта в процедуре ОбработкаПроведения мы можем гарантировать, что данные регистра не изменятся в процессе расчета.
  3. Производительность: Лишние запросы к базе при каждом изменении строки в форме избыточно нагружают систему.

Таким образом, правильное место для кода — процедура ОбработкаПроведения в модуле объекта документа.

Пошаговый алгоритм технической реализации

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

Шаг 1. Установка управляемых блокировок.
Прежде чем читать остатки из регистра, необходимо заблокировать данные по тем позициям номенклатуры, которые указаны в документе. Это предотвратит ситуацию, когда два одновременно проводимых документа уводят остаток в минус.


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрНакопления.ОстаткиТоваров");
ЭлементБлокировки.УстановитьЗначение("Номенклатура", СписокНоменклатурыДокумента);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();

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

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

Проблема «копеек» и корректное округление

Проанализируем типичную ошибку: расчет цены единицы с последующим округлением. Если вы разделите 100 рублей на 3 штуки, получите 33.333... Округление до 33.33 даст ошибку при умножении обратно на количество.

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

Посмотрим на пример кода логики расчета:


Для Каждого СтрокаТЧ Из СписокНоменклатуры Цикл
    // Предположим, ИзРегистра мы получили КолОстаток и СумОстаток
    Если СтрокаТЧ.Количество < КолОстаток Тогда
        СуммаСписания = (СумОстаток / КолОстаток) * СтрокаТЧ.Количество;
    ИначеЕсли СтрокаТЧ.Количество = КолОстаток Тогда
        СуммаСписания = СумОстаток; // Списываем всё в ноль
    Иначе
        // Обработка нехватки товара
    КонецЕсли;
КонецЦикла;

Особенности работы с отрицательными остатками

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

Резюме для реализации на экзамене или в проекте

Подведем итоги нашего исследования:

  1. Расчет ведем строго в ОбработкаПроведения.
  2. Цена в табличной части — для покупателя, расчетная стоимость — для регистра.
  3. Используем объект БлокировкаДанных для обеспечения целостности.
  4. При списании последней единицы товара (или всего остатка) — списываем всю сумму остатка полностью, чтобы избежать копеечных «хвостов».
  5. Для получения данных используем Запрос к виртуальной таблице Остатки с фильтром по массиву номенклатуры из документа.

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

← На главную