使用moneyphp计算税款

时间:2018-10-07 19:18:07

标签: php currency tax money-php

我正在使用moneyphp/money类来存储货币值。但是,在计算所欠税款时,我遇到了一个问题,即所计算的税款是小数,图书馆正在寻找整数值。

示例:

$invoiceTotal = new Money("155" new Currency("USD")); //$1.55
$taxRate= 0.065;
$invoiceTotalWithTax = $invoiceTotal->multiply($taxRate);
echo $invoiceTotalWithTax; //0.10 whereas actual value is 1.55*0.065 = 0.10075
$formatter = new DecimalMoneyFormatter();
$formatter->format($invoiceTotalWithTax); //will return $0.10

在上面的示例中,某些分数值丢失了。个别情况并不多,但是,如果我们在一个纳税期内处理了数千张发票,那么所收取的总税收最终将超过1美分。

  • Money软件包是否可以处理这些情况?
  • 如果没有,那么还有另一个软件包可以处理吗?

1 个答案:

答案 0 :(得分:2)

无耻的插件:我不知道是否可以使用moneyphp/money软件包来完成此操作,但是这是使用brick/money软件包来处理这种情况的方法(免责声明:我编写的)

您选择的选项取决于您要实现的目标。

选项1:使用默认比例的货币,向上或向下取整

如果您需要使用默认比例的货币结果(USD保留2个小数位),并且知道要应用哪种舍入方法,请使用此方法:

use Brick\Money\Money;
use Brick\Math\RoundingMode;

$invoiceTotal = Money::ofMinor('155', 'USD'); // USD 1.55
// or
$invoiceTotal = Money::of('1.55', 'USD');

$taxRate = '0.065'; // prefer strings over floats!

$totalWithTax = $invoiceTotal->multipliedBy($taxRate, RoundingMode::DOWN); // USD 0.10
$totalWithTax = $invoiceTotal->multipliedBy($taxRate, RoundingMode::UP); // USD 0.11

您还有更多rounding modes可供选择。如果您不提供舍入模式,并且结果不适合小数点后2位,则会出现异常。

选项2:使用具有自定义比例的Money

如果您需要使用给定的精度(例如5个小数位),则可以在创建Money时指定此精度:

use Brick\Money\Money;
use Brick\Money\Context\CustomContext;
use Brick\Math\RoundingMode;

$invoiceTotal = Money::of('1.55', 'USD', new CustomContext(5)); // USD 1.55000
$taxRate = '0.065';

$totalWithTax = $invoiceTotal->multipliedBy($taxRate); // USD 0.10075

如果结果不适合小数点后5位,则需要提供RoundingMode,否则会出现异常。

选项3:使用具有自动缩放比例的Money

使用此方法将结果的小数位数自动调整为正确的小数位数:

use Brick\Money\Money;
use Brick\Money\Context\AutoContext;
use Brick\Math\RoundingMode;

$invoiceTotal = Money::of('1.55', 'USD', new AutoContext()); // USD 1.55
$taxRate = '0.065';

$totalWithTax = $invoiceTotal->multipliedBy($taxRate); // USD 0.10075

不涉及四舍五入模式,但是如果除法运算得出的十进制数字具有无限个数字,则会出现异常。

选项4:使用RationalMoney

RationalMoney是一个货币对象,将其金额表示为有理数(分数)。当您需要不进行舍入的任何操作时,这特别有用:

use Brick\Money\Money;
use Brick\Math\RoundingMode;

$amount = Money::of('1.55', 'USD'); // USD 1.55
$amount = $amount->toRational(); // USD 155/100

$amount = $amount->dividedBy(3); // USD 155/300
$amount = $amount->dividedBy(7); // USD 155/2100

完成所有操作后,可以根据需要使用舍入模式将最终数字转换为十进制Money:

use Brick\Money\Context\DefaultContext;
use Brick\Money\Context\CustomContext;

$amount->to(new DefaultContext(), RoundingMode::DOWN); // USD 0.07
$amount->to(new CustomContext(6), RoundingMode::DOWN); // USD 0.073809

最终注意事项

brick/money软件包提供了格式设置,现金取整,货币分配,货币换算等功能。它基于brick/math包,可对任意比例的数字执行计算。随时尝试!