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)