При проведении документа «Поступление товаров и услуг» пользователи нередко сталкиваются с ошибкой: «Суммы по документу расходятся, нажмите пожалуйста кнопку "Распределить" на закладке "Услуги"». При этом даже повторное нажатие кнопки «Распределить» не дает результата, и документ по-прежнему отказывается проводиться. Разберем по шагам, почему возникает эта коллизия и как ее устранить методологически и программно.
Проанализируем ситуацию, которая приводит к сбою. Ошибка чаще всего возникает на стыке двух факторов:
25,15 и цене 277,95 произведение составляет 6990,4425 руб. В регламентированном учете метаданные 1С для денежных показателей строго ограничены форматом Число(15, 2) — учет ведется исключительно в рублях и копейках. Ни один бухгалтерский регистр физически не хранит десятитысячные доли.Рассмотрим подробнее доступные пути решения — от простых пользовательских приемов до технической доработки алгоритма.
Разберем самый простой и надежный способ для пользователя, не требующий внесения изменений в конфигурацию. Если распределение услуги внутри накладной блокирует проведение, разделим операции:
Поступление доп. расходов (или Приобретение услуг и прочих активов в зависимости от используемой конфигурации).Если требуется провести услугу именно в текущем документе поступления, применим ручную корректировку распределенной суммы:
Посмотрим на техническую сторону вопроса. Стандартная ошибка разработчиков при написании процедур распределения заключается в независимом расчете каждой строки в цикле без вычисления накопительного итога. Чтобы сумма распределения всегда гарантированно сходилась с исходной суммой услуги, алгоритм распределения должен относить образовавшуюся копеечную разницу на последнюю строку.
Рассмотрим пример правильного алгоритма распределения с контролем остатка:
// Предположим, у нас есть ОбщаяСуммаУслуги и ТабличнаяЧастьТовары
НакопленнаяСумма = 0;
ВсегоСтрок = ТабличнаяЧастьТовары.Количество();
Для Индекс = 0 По ВсегоСтрок - 1 Цикл
СтрокаТовара = ТабличнаяЧастьТовары[Индекс];
Если Индекс = ВсегоСтрок - 1 Тогда
// На последнюю строку относим весь оставшийся «хвост»
СтрокаТовара.СуммаУслуги = ОбщаяСуммаУслуги - НакопленнаяСумма;
Иначе
// Рассчитываем пропорциональную долю строки с математическим округлением до копеек
Доля = Окр((СтрокаТовара.Сумма / ИтогСуммаТоваров) * ОбщаяСуммаУслуги, 2);
СтрокаТовара.СуммаУслуги = Доля;
НакопленнаяСумма = НакопленнаяСумма + Доля;
КонецЕсли;
КонецЦикла;
Такой подход полностью устраняет ошибку несовпадения итогов, так как последняя строка гарантированно поглощает погрешность округления Разница = СуммаУслуги - СуммаРаспределения, позволяя документу беспрепятственно сформировать проводки.