Magento为什么在计算税额时存储舍入增量


14

在模型中tax/Sales_Total_Quote_Tax,有一种_deltaRound()舍入价格的方法。它增加了一个小的变化量,以在四舍五入时停止不确定的行为。

/**
 * Round price based on previous rounding operation delta
 *
 * @param float $price
 * @param string $rate
 * @param bool $direction price including or excluding tax
 * @param string $type
 * @return float
 */
protected function _deltaRound($price, $rate, $direction, $type = 'regular')
{
    if ($price) {
        $rate = (string)$rate;
        $type = $type . $direction;
        // initialize the delta to a small number to avoid non-deterministic behavior with rounding of 0.5
        $delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0.000001;
        $price += $delta;
        $this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
        $price = $this->_calculator->round($price);
    }
    return $price;
}

但它存储一个增量。如果找不到这样存储的增量,则将其补足。为什么?就像我所知道的tar一样,使用相同的操作会导致不同的结果。

假设我们的$price值为3.595,并且没有cached $delta。通过该方法,我们将获得$ delta = 0.000001。然后$price,我们得到= 3.595001(四舍五入为3.60),因此我们有了新$delta的-0.004999。我们返回3.60。

除了现在,我们有一个增量,所以我们用$price= 3.595 重新做一次。$price= 3.595-0.004999 = 3.590001

如果四舍五入,我们得到3.59。不同的答案。

在我看来,每次使用相同的参数运行时,任何舍入算法都应至少给出相同的答案,但这次不这样做。


顺便说一句,在Magento 2.2.2中遇到了相同的错误
TheKitMurkit,

Answers:


9

我的服务器上装有Magento 1.8,并且已经检查了_deltaRound()方法。现在看起来像这样。

/**
 * Round price based on previous rounding operation delta
 *
 * @param float $price
 * @param string $rate
 * @param bool $direction price including or excluding tax
 * @param string $type
 * @return float
 */
protected function _deltaRound($price, $rate, $direction, $type = 'regular')
{
    if ($price) {
        $rate  = (string) $rate;
        $type  = $type . $direction;
        $delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0;
        $price += $delta;
        $this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
        $price = $this->_calculator->round($price);
    }
    return $price;
}

如您所见,如果_roundingDeltas()未设置,则将其zero作为默认值。它只是为了通知您。Magento团队可能会忽略您的疑问。他们默默地解决了您的问题。:)

编辑

让我们通过将其应用到实时示例中来分析此功能的使用。假设我的购物车中有一种商品应课税。我要购买的数量为5。应用税后,该产品的价格为$ 10.5356。这就是我的情况

CART
-------
   Product A
       - Price (including tax) - 10.5356
       - Quantity              - 5
       - Tax Rule  - Apply tax for each product. Then calculate the total price according to the quantity purchased.

因此,现在让我们计算在这种情况下将要产生的实际价格。这将是

  Total =  10.5356 x 5 = 52.678

现在让我们假设,magento不使用_deltaRound()方法。它只是将产品价格四舍五入到小数点后两位,然后计算总价。在这种情况下,产品价格将四舍五入10.54,因此总价格为

  Total = 10.54 x 5 = 52.7

现在让我们假设magento正在使用_deltaRound()方法,并且此函数实际上将产品价格四舍五入到两位小数。随之,它将保留一个增量值,即实际价格和四舍五入后的价格之间的差额,以后将用于计算四舍五入后的价格。这里在此处输入图片说明

  Total =  10.54+10.53+10.54+10.53+10.54 = 52.68

这意味着_deltaRound()方法实际上使税收价格四舍五入到实际税收价格更为准确。如您所述,此方法返回的取整值取决于增量值。该增量值实际上使税收舍入更准确。

据此可以得出结论,随着数量的增加,如果不采用此方法,则四舍五入后的值与实际值之间会产生很大的差异。但是,如果使用此方法,则将使舍入后的值与实际值尽可能接近。

默认情况下,Magento会四舍五入到小数点后两位。这是负责两位小数舍入的方法

Location :app/code/core/Mage/Core/Model/Store.php
public function roundPrice($price)
{
    return round($price, 2);
}

如果将其设置为4左右,则可以进一步提高舍入的精度。

注意:这是我的介绍和概述。这可能是正确的,也可能不是。但是,对于我来说,这似乎是正确且合乎逻辑的。

谢谢。


我真的很讨厌硬编码2roundPrice
David Manners 2014年

@DavidManners:是的,这是正确的。但是magento用来一定程度_deltaRound()上克服困难。任何如何对其进行硬编码。在某些情况下,它肯定会带来一些困难
Rajeev K Tomy

1
查看github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/…在magento 1.9中,默认值仍为0.0001,这对我们造成了一个错误提示,即运输时的税收计算
ProxiBlue

2

信息

Magento中的舍入价格基于先前的舍入操作增量。

应用程序/代码/核心/法师/税务/型号/销售/总/报价/ Tax.php:1392 应用程序/代码/核心/法师/税务/型号/销售/总/报价/ Subtotal.php:719

protected function _deltaRound($price, $rate, $direction, $type = 'regular')
{
    if ($price) {
        $rate = (string)$rate;
        $type = $type . $direction;
        // initialize the delta to a small number to avoid non-deterministic behavior with rounding of 0.5
        $delta = isset($this->_roundingDeltas[$type][$rate]) ? $this->_roundingDeltas[$type][$rate] : 0.000001;
        $price += $delta;
        $this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);
        $price = $this->_calculator->round($price);
    }
    return $price;
}

有时由于高增量计算错误($this->_calculator->round($price))可能导致错误。例如,由于这个原因,某些价格可能在±1美分的范围内变化。

为避免这种情况,您需要提高增量计算的准确性。

更改

$this->_roundingDeltas[$type][$rate] = $price - $this->_calculator->round($price);

$this->_roundingDeltas[$type][$rate] = $price - round($price, 4);

需要在两个文件中进行更改:

应用程序/代码/核心/法师/税务/型号/销售/总/报价/ Tax.php:1392 应用程序/代码/核心/法师/税务/型号/销售/总/报价/ Subtotal.php:719

不要修改或破解核心文件!重写!

该解决方案已在Magento 1.9.x的不同版本上进行了测试,但也许可以在早期版本中使用。

聚苯乙烯

roundPrice如下所示,Change 函数可以解决舍入错误的问题,但可能引起其他问题(例如,某些平台要求舍入到小数点后2位)。

应用/代码/核心/法师/核心/模型/Store.php:995

public function roundPrice($price)
{
    return round($price, 4);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.