Как исправить ошибку списания стоимости товаров и зависание суммовых остатков в 1С?

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

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

Проанализируем причины возникновения этой проблемы и разберем практические способы ее решения в коде проведения расходных документов.

Почему возникают отрицательные или копеечные остатки стоимости?

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


Движение = Движения.Остатки.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Товар = Выборка.Товар;
Движение.Склад = Склад;
Движение.Количество = Выборка.Количество;
Движение.Стоимость = Выборка.Сумма; // Ошибка: списание суммы по текущей цене документа

Если товар поступал на склад по одной цене (например, 24 руб. за 20 шт. — по 1,2 руб./шт.), а в момент продажи цена изменилась (например, до 1,3 руб./шт.), то при списании 10 шт. спишется 13 руб. На складе останется 10 шт. на сумму 11 руб. При продаже оставшихся 10 шт. по новой цене система попытается списать еще 13 руб., в результате чего остаток по количеству станет 0 шт., а по сумме — -2 руб.

Вторая распространенная причина — погрешность округления при делении. Если рассчитывать среднюю себестоимость простым делением суммового остатка на количественный, при делении неделимых сумм (например, 100 руб. на 3 шт. = 33.33 руб.) после списания всех трех единиц на остатке останется 1 копейка.

Способ 1. Расчет себестоимости по средней с контролем полного списания остатка

Рассмотрим классический алгоритм списания стоимости по средней. Сумма списания не должна браться из цен продажи — она рассчитывается исходя из фактического остатка стоимости в регистре накопления Остатки на момент проведения документа.

Разберем формулу расчета списания:

СтоимостьСписания = (СтоимостьОстаток / КоличествоОстаток) * КоличествоСписания;

Чтобы избежать зависания копеек из-за округления, необходимо обязательно проверять: если списывается весь оставшийся товар, то должна быть списана вся оставшаяся сумма целиком.

Разберем по шагам реализацию в процедуре ОбработкаПроведения расходного документа:

  1. Устанавливаем исключительную управляемую блокировку на данные регистра остатков, чтобы избежать коллизий при параллельной работе.
  2. Формируем временную таблицу товаров документа со сверткой по номенклатуре.
  3. Получаем актуальные остатки по регистру накопления на момент времени документа.
  4. Рассчитываем сумму списания с проверкой на полное списание партии.

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


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

// 2. Получение остатков и расчет сумм
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ДокТовары.Товар КАК Товар,
    |    СУММА(ДокТовары.Количество) КАК Количество
    |ПОМЕСТИТЬ ВТ_ТоварыДокумента
    |ИЗ
    |    Документ.РасходнаяНакладная.Товары КАК ДокТовары
    |ГДЕ
    |    ДокТовары.Ссылка = &Ссылка
    |СГРУППИРОВАТЬ ПО
    |    ДокТовары.Товар
    |;
    |
    |ВЫБРАТЬ
    |    ВТ.Товар КАК Товар,
    |    ВТ.Количество КАК КоличествоК_Списанию,
    |    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
    |    ЕСТЬNULL(Остатки.СтоимостьОстаток, 0) КАК СтоимостьОстаток
    |ИЗ
    |    ВТ_ТоварыДокумента КАК ВТ
    |    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Остатки.Остатки(
    |        &МоментВремени,
    |        Склад = &Склад И Товар В (ВЫБРАТЬ Товар ИЗ ВТ_ТоварыДокумента)) КАК Остатки
    |    ПО ВТ.Товар = Остатки.Товар";

Запрос.УстановитьПараметр("Ссылка", Ссылка);
Запрос.УстановитьПараметр("Склад", Склад);
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Движения.Остатки.Записывать = Истина;

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

Способ 2. Введение документа переоценки товаров на складах

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

Рассмотрим, как работает эта схема:

  1. При изменении розничных цен формируется документ переоценки (например, ПереоценкаТоваровВРознице).
  2. Документ получает текущие количественные остатки товара на складе.
  3. Рассчитывается разница в стоимости: (НоваяЦена - СтараяЦена) * КоличествоОстаток.
  4. В регистр накопления Остатки делается суммовое движение (без изменения количества) на сумму переоценки (положительное при дооценке или отрицательное при уценке).

В этом случае учетная стоимость складского остатка всегда будет соответствовать произведению текущего количества на действующую цену.

Способ 3. Добавление цены в измерения регистра остатков

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

В таком случае остаток разделяется:

Списание при этом ведется с указанием конкретной цены, либо методом партионного учета (ФИФО/ЛИФО), что полностью исключает перекосы между суммами и количествами.

← На главную