gifts2017

Точный расчет пропорционально зависимых значений в спецификации.

Опубликовал Михаил Семенов (Shaman100M) в раздел Программирование - Практика программирования

Больше статья, чем программа. Прилагаемая внешняя обработка - пример расчета на таблице значений.

Точный расчет пропорционально зависимых значений в спецификации.
(Пример на сумме накладной и НДС)

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

Итог по расчетной колонке <> Расчетное значение по итогу "колонки-основания" для расчета (1)

(проще говоря)

Итог("НДС") <> СтавкаНДС * Итог("Сумма") 




Погрешность в 1-2 копейки возникает очень часто, если количество строк в документе большое,
может достигать 10-20 копеек.

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

Исключения всегда есть:

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

Идея точного расчета состоит в том, чтобы условие (1) выполнялось на любой момент пересчета спецификации.
Таким образом, на примере НДС для позиции i спецификации (единая ставка для всей спецификации):

НДС_i = Окр(СтавкаНДС * Сумма_i,2); // по старому
    
НДС_i = Окр(СтавкаНДС * ПромИтог("Сумма",1,i),2) -
                                           ПромИтог("НДС",1,i-1); // по новому

 

ПромИтог(<Колонка>,<ГраницаОтВкл>,<ГраницаДоВкл>) - промежуточный итог по указанной колонке
по диапазону строк с указанными границами.

Или, словами: НДС для позиции это разница между ставкой НДС от накопленной суммы на данную позицию
минус накопленный НДС на предыдущую позицию.

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

Реализация метода - в прилагающейся внешней обработке.

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
PinPointCalc
.1174486780 6,59Kb
25.09.09
67
.1174486780 6,59Kb 67 Бесплатно

См. также

Подписаться Добавить вознаграждение

Комментарии

1. rjhev korum (корум) 25.04.07 11:58
Есть ли пример встраивания в "типовые" процедуры? (глПересчетТабличнойЧасти и т.п.)
перелопачивать весь глобальник+все документы как-то сильно не хочется...
2. Михаил Семенов (Shaman100M) 25.04.07 13:18
Если говорить о ТиС, взять реквизит ТЧ "СуммаНДС" (или "СуммаНП"), то можно поискать обращение к процедуре глРасчетНалога(),
встречается не так часто:

глПересчетТаблЧасти()
глПересчитатьСтрокиДокумента()
глПересчитатьСкидки()

Описанная метода может отработать там, где осуществляется полный перебор строк и полный пересчет, т.е. в
глПересчитатьСтрокиДокумента и глПересчитатьСкидки.

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

Сам использовал данный пересчет в нетиповой конфиге при программном создании документов. В формах документов добавлял кнопку и доп. диалог для "сведения" суммы и НДС. Можно пересчитывать при сохранении.
3. Михаил Семенов (Shaman100M) 25.04.07 13:49
...хотя... "последнее дополняющее до точного итогового" + итоговый пересчет при сохранении потянет
4. Сhe Burashka (CheBurator) 14.08.07 05:39
возьмем 8-ую строку... типа НДС..
пришел я вот такой злостный налоговый инспектор... ткнул пальцем в первичку.. что у нас тут.. ага... НДСик д.б. 0.435045 = 0.44, а у вас что = 0.43.. ОПС! на цугундер!!! утаили копеечку от государства!!!
5. Poppy (poppy) 14.08.07 12:15
Алгоритм правильный, но реализация уж больно мудреная. Предлагаю более простой вариант:

Код
Процедура Сформировать()
   
   ПромИтогСумма = ТЗ1.Итог("СуммаЭталон");
   ПромИтогРасчет = ПримерРасчета(ТЗ1.Итог("СуммаЭталон"));

   ТЗ1.ВыбратьСтроки();
   Пока ТЗ1.ПолучитьСтроку()=1 Цикл
      
      ТЗ1.РасчетПоНовому = Окр(ТЗ1.СуммаЭталон * ПромИтогРасчет / ПромИтогСумма ,2);
      
      ПромИтогСумма = ПромИтогСумма - ТЗ1.СуммаЭталон;
      ПромИтогРасчет = ПромИтогРасчет - ТЗ1.РасчетПоНовому;
      
      ТЗ1.РасчетПоСтарому=ПримерРасчета(ТЗ1.СуммаЭталон); // по старому
   КонецЦикла;
   
КонецПроцедуры //Сформировать()

Показать полностью
6. Poppy (poppy) 14.08.07 12:21
(4)
Если инспектор никогда не читал НК, то это не злостный, но беспредельщик. Такие обычно не тычут в первичку, а сразу предлагают разобраться по-хорошему.
7. Poppy (poppy) 14.08.07 12:25
Применение рассматриваемого алгоритма не ограничивается пересчетом НДС в документах.

Например, при закрытии затратных счетов 44, 26, 25, 23, 20 без такого алгоритма = никуда.
8. Михаил Семенов (Shaman100M) 14.08.07 13:07
(4) А мож он сначала в итоги посмотрит? Ну, можно, конечно, начать разбирать не работающий системник, не убедившись , что просто не включен "пилот". :)

(5) можно бы проверить это алгоритм, т.к. при последнем проходе
[code] ТЗ1.РасчетПоНовому = Окр(ТЗ1.СуммаЭталон * ПромИтогРасчет / ПромИтогСумма ,2); [code]
тоже идет округление результата деления, - не факт, что ТЗ1.Итог("РасчетПоНовому") будет равен первичному ПромИтогРасчет , а это - основная цель разработки.

Реализация сделана сложнее, т.к. предполагает универсальность и минимум дополнительного кода в основной цикл пересчета (одна строка в цикле, одна до него)

Спасибо за комменты.
9. Poppy (poppy) 14.08.07 13:45
(8) >тоже идет округление результата деления, - не факт, что ТЗ1.Итог("РасчетПоНовому") будет равен первичному ПромИтогРасчет , а это - основная цель разработки.

В том то и дело, что на последнем проходе ТЗ1.СуммаЭталон тождественно равно ПромИтогСумма. Это значит, что ТЗ1.РасчетПоНовому = ПромИтогРасчет. Никакого округления не будет, т.к. ПромИтогРасчет всегда округлен.

По окончании цикла, ПромИтогРасчет всегда будет равен нулю. А значит, ТЗ1.Итог("РасчетПоНовому") будет равен первичному ПромИтогРасчет.
10. Михаил Семенов (Shaman100M) 14.08.07 14:44
(9) Да, согласен. От перестановки мест множителей произведение не меняется, но знак деления уже не смущает:

code] ТЗ1.РасчетПоНовому = Окр(ПромИтогРасчет * ТЗ1.СуммаЭталон / ПромИтогСумма ,2);
[/code]
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа