使用 moneyphp 计算税收
Calculating tax using moneyphp
我正在使用 moneyphp/money class 来存储货币值。但是,在计算所欠税款时,我遇到了一个问题,即计算出的税款是小数,而图书馆正在寻找一个整数值。
示例:
$invoiceTotal = new Money("155" new Currency("USD")); //.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 [=10=].10
从上面的例子中,一些分数价值正在丢失。单独来看不算多,但是如果我们在一个纳税周期内处理几千张发票,最终征收的总税款将超过1分钱。
- 有没有办法用 Money 包来处理这些情况?
- 如果没有,是否有其他包可以处理这个问题?
无耻的插件:我不知道是否有办法用 moneyphp/money
库来做到这一点,但这里是你如何用 brick/money 库处理这种情况(免责声明:我创作它)。
您选择的选项将取决于您要实现的目标。
选项 1:使用具有默认比例的货币,向上或向下取整
如果您需要货币默认比例的结果(USD
的小数点后两位),并知道要应用哪种舍入,请使用此方法:
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
A 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 包,可对任何比例的数字执行计算。试一试!
我正在使用 moneyphp/money class 来存储货币值。但是,在计算所欠税款时,我遇到了一个问题,即计算出的税款是小数,而图书馆正在寻找一个整数值。
示例:
$invoiceTotal = new Money("155" new Currency("USD")); //.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 [=10=].10
从上面的例子中,一些分数价值正在丢失。单独来看不算多,但是如果我们在一个纳税周期内处理几千张发票,最终征收的总税款将超过1分钱。
- 有没有办法用 Money 包来处理这些情况?
- 如果没有,是否有其他包可以处理这个问题?
无耻的插件:我不知道是否有办法用 moneyphp/money
库来做到这一点,但这里是你如何用 brick/money 库处理这种情况(免责声明:我创作它)。
您选择的选项将取决于您要实现的目标。
选项 1:使用具有默认比例的货币,向上或向下取整
如果您需要货币默认比例的结果(USD
的小数点后两位),并知道要应用哪种舍入,请使用此方法:
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
A 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 包,可对任何比例的数字执行计算。试一试!