Проблема «лишних копеек» или внезапных разрывов в себестоимости при списании товара — это классическая задача, с которой сталкивается практически каждый начинающий разработчик в 1С. Ситуация, когда один и тот же товар, купленный по разным ценам, при продаже выдает разную себестоимость в соседних строках отчета, может вызвать недоумение у пользователя и ошибки в финансовой отчетности. Разберем подробно, почему это происходит и как правильно реализовать алгоритм списания, чтобы данные были точными.
Давайте проанализируем математическую суть проблемы. Когда мы ведем учет «по средней», система делит общую стоимость остатка на общее количество. Если вы купили 3 единицы товара за 1000 рублей, то математически себестоимость одной единицы составит 333,3333... рубля. Поскольку в ресурсах регистров 1С обычно установлено 2 знака после запятой, система округляет это значение до 333,33 рубля.
Рассмотрим пример:
В итоге в отчете по продажам мы увидим три разные суммы: 333.33, 333.33 и 333.34. Это не ошибка программы, а следствие того, что сумма округлений не всегда равна округлению суммы. Однако, если разница составляет не копейки, а рубли, это уже сигнализирует об ошибках в программном коде или нарушении хронологии документов.
Чтобы в регистрах не зависали «копеечные хвосты» (ситуация, когда количество равно 0, а сумма осталась, например, 0.01 руб.), необходимо использовать проверку на полное списание остатка. Проанализируем правильную логику расчета в цикле обхода выборки:
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
КоличествоСписания = ... // количество из документа
ОстатокКол = ВыборкаДетальныеЗаписи.КоличествоОстаток;
ОстатокСумма = ВыборкаДетальныеЗаписи.СтоимостьОстаток;
Если КоличествоСписания = ОстатокКол Тогда
// Если списываем всё под чистую - забираем всю сумму без деления
СтоимостьСписания = ОстатокСумма;
Иначе
// Если списываем часть - считаем среднюю с округлением
СтоимостьСписания = Окр(ОстатокСумма / ОстатокКол * КоличествоСписания, 2);
КонецЕсли;
// Запись в движения документа
Движение.Стоимость = СтоимостьСписания;
КонецЦикла;
Этот метод гарантирует, что при уходе товара со склада в ноль, денежный остаток также обнулится.
Частой ошибкой является получение остатков на Дату документа. Если в одну секунду (например, 12:00:00) заведено два документа (приход и расход), запрос по дате может не увидеть приход, который формально записан «после» расхода в рамках этой секунды. Рассмотрим, как правильно передавать параметры в запрос:
Вместо использования ТекущаяДата() или ЭтотОбъект.Дата, всегда используйте МоментВремени() или Границу. Это позволяет получить остатки строго до текущего документа, включая или исключая его движения.
Запрос.УстановитьПараметр("Период", Новый Граница(МоментВремени(), ВидГраницы.Исключая));
// Или просто передать МоментВремени() в параметры виртуальной таблицы
Выясним причину, почему это важно: МоментВремени содержит не только дату и время, но и уникальную ссылку на документ. Это позволяет 1С выстроить все документы в строгую цепочку на временной оси.
Если вы обнаружили разницу в несколько рублей (как в сообщении автора темы: 3462,78 и 3467,58), проблема почти наверняка заключается в нарушении последовательности. Это происходит, когда документ прихода был изменен или введен «задним числом» уже после того, как были проведены документы продажи.
Проанализируем ситуацию: продажа рассчитала себестоимость на основе старых остатков. Затем вы ввели поступление товара по новой цене датой, предшествующей продаже. Продажа «не знает» о новом приходе и продолжает хранить старую сумму себестоимости.
Как это исправить:
Последовательности в 1С (если он предусмотрен в конфигурации).Если бизнес-логика требует идеальной точности и прозрачности (чтобы было видно, по какой конкретно закупке списан товар), следует рассмотреть переход на партионный учет. В этом случае себестоимость не усредняется.
Разберем по шагам, как это работает:
В такой модели «копейки» также могут возникать, но они всегда привязаны к конкретной поставке и легко отслеживаются. Однако партионный учет более требователен к ресурсам системы и дисциплине ввода данных.
Подведем итоги нашего анализа. Для минимизации погрешностей соблюдайте следующие правила:
Окр(..., 2) при расчетах списания, если только ваша учетная политика не подразумевает большую точность.Стоимость регистра Продажи.Соблюдение этих технических регламентов позволит вам избежать хаоса в копейках и обеспечит доверие пользователей к формируемым отчетам.