Почему в печатной форме 1С появляются лишние копейки в сумме НДС и как это исправить

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

Проблема расхождения итоговой суммы НДС на несколько копеек — это классическая ситуация, с которой сталкивается практически каждый разработчик при создании или редактировании внешних печатных форм (ВПФ). Особенно часто это проявляется в таких документах, как Коммерческое предложение, Заказ клиента или Реализация товаров и услуг в современных конфигурациях (УТ 11, КА 2, ERP).

В этой статье мы подробно разберем, откуда берутся эти «невидимые» копейки, почему стандартные методы расчета могут давать сбой и как правильно написать код в ВПФ, чтобы итоговые цифры всегда сходились с тем, что пользователь видит на экране.

Разберем причину: Математика округлений

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

  1. Построчный расчет: НДС вычисляется для каждой строки отдельно, округляется до двух знаков, а затем эти округленные значения суммируются.
  2. Расчет от итога: Сначала суммируется общая база (сумма без НДС) по всему документу, и уже от этой суммы вычисляется налог.

Из-за математических правил округления сумма округлений каждой строки почти никогда не совпадает с налогом, рассчитанным от общей суммы. Если в вашей ВПФ вы пытаетесь рассчитать НДС по формуле ИтоговаяСумма * Ставка / (100 + Ставка), вы почти гарантированно получите разницу в 1-2 копейки по сравнению с тем, что записано в табличной части документа.

Рассмотрим способ исправления №1: Использование метода Итог()

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

Посмотрим на пример кода, который помогает получить корректную сумму для вывода в подвал документа:


// Получаем область подвала из макета
Подвал = Макет.ПолучитьОбласть("Подвал");

// Вместо ручного пересчета используем метод Итог по колонке СуммаСНДС
// Это гарантирует, что сумма в печати совпадет с суммой в документе
ПодвалСумма = СсылкаНаДокумент.Товары.Итог("СуммаСНДС");

// Заполняем параметры макета
Подвал.Параметры.Сумма = ПодвалСумма;
Подвал.Параметры.Пропись = ЧислоПрописью(ПодвалСумма, "Л=ru_RU;ДП=Истина");

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


Подвал = Макет.ПолучитьОбласть("Подвал");

// Вариант 1: Сумма всего из реквизита объекта (если есть такой реквизит)
ПодвалСумма = ДанныеОбъекта.СуммаВсего; 

// Вариант 2: Сложение суммы без НДС и суммы налога из рассчитанных данных
// ПодвалСумма = ДанныеОбъекта.СуммаБезНДС + ДанныеОбъекта.СуммаНДС;

Подвал.Параметры.Сумма = ПодвалСумма;
Подвал.Параметры.Пропись = ЧислоПрописью(ПодвалСумма, "Л=ru_RU;ДП=Истина");

Выясним причину влияния ручных скидок

Проанализируем ситуацию, когда в документе используются ручные или автоматические скидки. При назначении скидки на весь документ 1С распределяет её сумму по строкам пропорционально стоимости товаров. В результате этого распределения часто возникают дробные части копеек (например, 0.003 рубля).

Система округляет эти значения в каждой строке. В современных конфигурациях используется механизм «выравнивания», когда накопленная погрешность округления сбрасывается в последнюю строку документа. Если ваша ВПФ делает запрос к табличной части Товары и пытается сама умножать Цена * Количество, она не учитывает эти распределенные копейки скидок, что и приводит к ошибке в итоге.

Проанализируем работу с запросами в ВПФ

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


ВЫБРАТЬ
    КоммерческоеПредложениеТовары.Ссылка КАК Ссылка,
    СУММА(КоммерческоеПредложениеТовары.Сумма) КАК СуммаБезНДС,
    СУММА(КоммерческоеПредложениеТовары.СуммаНДС) КАК СуммаНДС,
    СУММА(КоммерческоеПредложениеТовары.СуммаСНДС) КАК ВсегоСНДС
ИЗ
    Документ.КоммерческоеПредложениеКлиенту.Товары КАК КоммерческоеПредложениеТовары
ГДЕ
    КоммерческоеПредложениеТовары.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    КоммерческоеПредложениеТовары.Ссылка

Использование функции СУММА() в запросе по полям, которые уже округлены в табличной части (СуммаНДС, СуммаСНДС), — это залог того, что итог в печатной форме будет соответствовать итогу в интерфейсе программы.

Обратим внимание на типы данных и функцию Окр()

При написании программного кода в модуле ВПФ часто используются промежуточные переменные. Если вы делите сумму на количество или вычисляете процент, всегда используйте явное округление. В 1С расчеты могут вестись с точностью выше 2 знаков после запятой, и эти микро-доли накапливаются при итоговом суммировании.

Рассмотрим пример правильного вычисления суммы в цикле (если вы по какой-то причине не используете Итог()):


ИтоговаяСумма = 0;
Для Каждого СтрокаТовар Из СсылкаНаДокумент.Товары Цикл
    // Округляем каждое промежуточное вычисление
    ТекущаяСуммаНДС = Окр(СтрокаТовар.Сумма * (СтавкаНДС / 100), 2);
    ИтоговаяСумма = ИтоговаяСумма + ТекущаяСуммаНДС;
КонецЦикла;

Без использования функции Окр(Значение, 2) переменная ИтоговаяСумма может содержать значение вроде 100.020000000004, которое при выводе в ЧислоПрописью внезапно превратится в лишнюю копейку.

Подведем итоги и сформируем чек-лист для разработчика

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

  1. Никогда не рассчитывайте НДС в коде ВПФ «на лету» по общей сумме. Всегда суммируйте уже имеющиеся данные из колонок СуммаНДС или СуммаСНДС.
  2. Если используете Запрос, извлекайте итоги с помощью функции СУММА() по соответствующим колонкам табличной части.
  3. Если работаете с Объектом напрямую, используйте метод Объект.Товары.Итог("ИмяКолонки").
  4. При любых арифметических операциях в коде (умножение, деление) используйте функцию Окр(Результат, 2).
  5. Помните про валютный учет: если документ в валюте, а печать в рублях, копейки могут расходиться из-за курсовых разниц в каждой строке. В этом случае нужно брать рублевые эквиваленты, которые система рассчитала при проведении документа.

Следуя этим рекомендациям, вы забудете о проблеме расхождения сумм в коммерческих предложениях и других финансовых документах.

← На главную