【问题标题】:Calculating tax using moneyphp使用moneyphp计算税款
【发布时间】:2018-10-07 19:18:06
【问题描述】:

我正在使用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 包处理这些情况?
  • 如果没有,那么是否有其他软件包可以处理这个问题?

【问题讨论】:

    标签: php currency tax money-php


    【解决方案1】:

    无耻插件:我不知道是否有办法使用 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:使用自定义比例的货币

    如果您需要使用给定的精度,比如小数点后 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
    

    完成所有操作后,您可以将最终数字转换为十进制货币,必要时使用舍入模式:

    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 包,可对任意比例的数字执行计算。试试看!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      • 2022-06-17
      • 2013-08-01
      • 2016-12-06
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      相关资源
      最近更新 更多