Проблема расхождения итоговой суммы НДС на несколько копеек — это классическая ситуация, с которой сталкивается практически каждый разработчик при создании или редактировании внешних печатных форм (ВПФ). Особенно часто это проявляется в таких документах, как Коммерческое предложение, Заказ клиента или Реализация товаров и услуг в современных конфигурациях (УТ 11, КА 2, ERP).
В этой статье мы подробно разберем, откуда берутся эти «невидимые» копейки, почему стандартные методы расчета могут давать сбой и как правильно написать код в ВПФ, чтобы итоговые цифры всегда сходились с тем, что пользователь видит на экране.
Прежде чем переходить к коду, давайте проанализируем ситуацию с точки зрения логики системы. В 1С существует два принципиально разных подхода к расчету налогов, и их смешивание в одной печатной форме — главная причина ошибок:
Из-за математических правил округления сумма округлений каждой строки почти никогда не совпадает с налогом, рассчитанным от общей суммы. Если в вашей ВПФ вы пытаетесь рассчитать НДС по формуле ИтоговаяСумма * Ставка / (100 + Ставка), вы почти гарантированно получите разницу в 1-2 копейки по сравнению с тем, что записано в табличной части документа.
Самый простой и эффективный способ избежать расхождений — не считать сумму заново, а взять уже готовый результат из табличной части документа. Платформа 1С уже произвела все необходимые расчеты при заполнении документа пользователем.
Посмотрим на пример кода, который помогает получить корректную сумму для вывода в подвал документа:
// Получаем область подвала из макета
Подвал = Макет.ПолучитьОбласть("Подвал");
// Вместо ручного пересчета используем метод Итог по колонке СуммаСНДС
// Это гарантирует, что сумма в печати совпадет с суммой в документе
ПодвалСумма = СсылкаНаДокумент.Товары.Итог("СуммаСНДС");
// Заполняем параметры макета
Подвал.Параметры.Сумма = ПодвалСумма;
Подвал.Параметры.Пропись = ЧислоПрописью(ПодвалСумма, "Л=ru_RU;ДП=Истина");
Важный момент: если ваша печатная форма использует данные из структуры ДанныеОбъекта (которая часто формируется в типовых конфигурациях), убедитесь, что в эту структуру попадают верные поля. Рассмотрим альтернативный вариант заполнения параметров:
Подвал = Макет.ПолучитьОбласть("Подвал");
// Вариант 1: Сумма всего из реквизита объекта (если есть такой реквизит)
ПодвалСумма = ДанныеОбъекта.СуммаВсего;
// Вариант 2: Сложение суммы без НДС и суммы налога из рассчитанных данных
// ПодвалСумма = ДанныеОбъекта.СуммаБезНДС + ДанныеОбъекта.СуммаНДС;
Подвал.Параметры.Сумма = ПодвалСумма;
Подвал.Параметры.Пропись = ЧислоПрописью(ПодвалСумма, "Л=ru_RU;ДП=Истина");
Проанализируем ситуацию, когда в документе используются ручные или автоматические скидки. При назначении скидки на весь документ 1С распределяет её сумму по строкам пропорционально стоимости товаров. В результате этого распределения часто возникают дробные части копеек (например, 0.003 рубля).
Система округляет эти значения в каждой строке. В современных конфигурациях используется механизм «выравнивания», когда накопленная погрешность округления сбрасывается в последнюю строку документа. Если ваша ВПФ делает запрос к табличной части Товары и пытается сама умножать Цена * Количество, она не учитывает эти распределенные копейки скидок, что и приводит к ошибке в итоге.
Если ваша печатная форма строится на основе запроса, критически важно производить суммирование именно на стороне базы данных, используя агрегатные функции. Посмотрим, как должен выглядеть фрагмент запроса:
ВЫБРАТЬ
КоммерческоеПредложениеТовары.Ссылка КАК Ссылка,
СУММА(КоммерческоеПредложениеТовары.Сумма) КАК СуммаБезНДС,
СУММА(КоммерческоеПредложениеТовары.СуммаНДС) КАК СуммаНДС,
СУММА(КоммерческоеПредложениеТовары.СуммаСНДС) КАК ВсегоСНДС
ИЗ
Документ.КоммерческоеПредложениеКлиенту.Товары КАК КоммерческоеПредложениеТовары
ГДЕ
КоммерческоеПредложениеТовары.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
КоммерческоеПредложениеТовары.Ссылка
Использование функции СУММА() в запросе по полям, которые уже округлены в табличной части (СуммаНДС, СуммаСНДС), — это залог того, что итог в печатной форме будет соответствовать итогу в интерфейсе программы.
При написании программного кода в модуле ВПФ часто используются промежуточные переменные. Если вы делите сумму на количество или вычисляете процент, всегда используйте явное округление. В 1С расчеты могут вестись с точностью выше 2 знаков после запятой, и эти микро-доли накапливаются при итоговом суммировании.
Рассмотрим пример правильного вычисления суммы в цикле (если вы по какой-то причине не используете Итог()):
ИтоговаяСумма = 0;
Для Каждого СтрокаТовар Из СсылкаНаДокумент.Товары Цикл
// Округляем каждое промежуточное вычисление
ТекущаяСуммаНДС = Окр(СтрокаТовар.Сумма * (СтавкаНДС / 100), 2);
ИтоговаяСумма = ИтоговаяСумма + ТекущаяСуммаНДС;
КонецЦикла;
Без использования функции Окр(Значение, 2) переменная ИтоговаяСумма может содержать значение вроде 100.020000000004, которое при выводе в ЧислоПрописью внезапно превратится в лишнюю копейку.
Чтобы ваша печатная форма всегда выводила корректные данные без «плавающих» копеек, придерживайтесь следующих правил:
СуммаНДС или СуммаСНДС.СУММА() по соответствующим колонкам табличной части.Объект.Товары.Итог("ИмяКолонки").Окр(Результат, 2).Следуя этим рекомендациям, вы забудете о проблеме расхождения сумм в коммерческих предложениях и других финансовых документах.