税金を計算するときにMagentoが丸めデルタを保存する理由


14

モデルtax/Sales_Total_Quote_Taxには_deltaRound()、価格を四捨五入する方法があります。0.5を丸めるときに非決定的な動作を停止するために、小さなデルタを追加します。

/**
 * 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 $deltaを取得します。これは3.60に丸められるため、新しい-0.004999があります。そして、3.60を返します。

今以外はデルタがあるので、$price= 3.595 でもう一度やりましょう。$price= 3.595-0.004999 = 3.590001

丸めると3.59になります。さまざまな答え。

使用される丸めアルゴリズムは、少なくとも同じ引数で実行されるたびに同じ答えを返す必要がありますが、今回はそうではないようです。


ところで、Magento 2.2.2で同じエラーが発生しました
TheKitMurkit

回答:


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です。税を適用した後、prdouctの価格は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()メソッドを使用しないと仮定します。製品価格を小数点以下2桁まで切り上げてから、合計価格を計算します。この場合、製品価格は四捨五入される10.54ため、合計価格は

  Total = 10.54 x 5 = 52.7

ここで、magentoが_deltaRound()メソッドを使用しており、この関数が実際に製品価格を小数点以下2桁に丸めると仮定します。それに加えて、実際の価格と丸められた価格の差であるデルタ値を保持し、後で丸められた価格を計算するために使用します。ここにここに画像の説明を入力してください

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

つまり、_deltaRound()メソッドは実際に税額の四捨五入を実際の税の価格設定により正確にします。述べたように、このメソッドはデルタ値に応じて異なるラウンド値を返します。このデルタ値により、実際には税の丸めがより正確になります。

これによれば、量が増えると、この方法を採用しない場合、丸められた値と実際の値の間に大きな差が生じると結論付けることができます。しかし、このメソッドを使用すると、丸められた値が実際の値にできるだけ近くなります。

Magentoはデフォルトで小数点以下2桁に丸めます。これは、小数点以下2桁を丸める方法です。

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

4などに設定すると、丸めの精度をさらに高めることができます。

注:これは私のオープニングと概要です。それは本当かもしれないし、そうでないかもしれない。しかし、それは私にとって正確かつ論理的なようです。

ありがとう。


私はハードコードされた2を本当に嫌っていますroundPrice
David Manners 14年

@DavidManners:はい、正しいです。しかし、magentoは_deltaRound()、ある程度拡張することで困難を克服するために使用します。そのハードコーディングされた方法。場合によっては、いくつかの問題を確実に解決するでしょう
Kトミー14年

1
github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code / ...を見ると、magento 1.9のデフォルト値はまだ0.0001であり、これが出荷時の税計算でのルーティングエラーを引き起こしています
ProxiBlue

2

情報

以前の丸め操作デルタに基づくMagentoのラウンド価格。

app / code / core / Mage / Tax / Model / Sales / Total / Quote / Tax.php:1392 app / code / core / Mage / Tax / Model / Sales / Total / Quote / 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);

両方のファイルに変更を加える必要があります。

app / code / core / Mage / Tax / Model / Sales / Total / Quote / Tax.php:1392 app / code / core / Mage / Tax / Model / Sales / Total / Quote / Subtotal.php:719

コアファイルを変更またはハッキングしないでください!書き直してください!

このソリューションは、Magento 1.9.xのさまざまなバージョンでテストされましたが、以前のバージョンでも機能する可能性があります。

PS

roundPrice以下に示すように、関数を変更すると、丸め誤差の問題を解決できますが、他の原因になる場合があります(たとえば、一部のプラットフォームでは小数点以下2桁に切り上げる必要があります)。

app / code / core / Mage / Core / Model / Store.php:995

public function roundPrice($price)
{
    return round($price, 4);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.