LeeYoonMyeong created FINERACT-2988:
---------------------------------------

             Summary: Tax split uses double arithmetic and can be off by one 
minor unit at rounding boundaries
                 Key: FINERACT-2988
                 URL: https://issues.apache.org/jira/browse/FINERACT-2988
             Project: Apache Fineract
          Issue Type: Bug
          Components: Savings
            Reporter: LeeYoonMyeong


{\{TaxUtils.splitTax}} and \{{TaxUtils.splitTaxData}} compute each tax 
component as

{code:java}
double tax = amount.doubleValue() * percentage.doubleValue() / 100.0;
BigDecimal.valueOf(tax).setScale(scale, MoneyHelper.getRoundingMode());
{code}

When the exact product lies on a rounding boundary, the binary double is 
slightly below it, so the configured rounding mode is applied to the wrong 
side. These methods are used for withholding tax on savings interest posting 
(\{{SavingsAccount}}, \{{SavingsAccountInterestPostingServiceImpl}}) and for 
charge tax (\{{ChargeTaxApplicationServiceImpl}}).

Examples (exact value -> expected -> current):
* 4.10 at 15 %, scale 2, HALF_EVEN: 0.615 -> 0.62 -> *0.61*
* 5250 at 1.4 %, scale 0, HALF_EVEN: 73.5 -> 74 -> *73*
* 5500 at 1.4 %, scale 0, DOWN: 77 -> 77 -> *76*

I scanned whole amounts 1..1,000,000 at 1.4 % (scale 0) and found 187 differing 
amounts under HALF_EVEN and 374 under HALF_UP. Amounts 0.01..10,000.00 at 15 % 
(scale 2) gave 658 differing amounts under HALF_EVEN. Rates such as 10 %, 14 % 
and 16 % gave no differences in these ranges. That is why the existing tests 
(e.g. 1000 at 16 %) pass.

*Proposed fix:* compute the product exactly with BigDecimal and round once: 
\{{amount.multiply(percentage).movePointLeft(2).setScale(scale, 
MoneyHelper.getRoundingMode())}}. Results change only where the exact value is 
on a rounding boundary. I have a patch with unit tests ready and would like to 
work on this issue.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to