Magento vergileri hesaplarken neden yuvarlama bir delta saklıyor?


14

Modelde tax/Sales_Total_Quote_Tax, _deltaRound()fiyatı yuvarlayan bir yöntem var. 0.5 yuvarlarken belirsiz olmayan davranışı durdurmak için küçük bir delta ekler.

/**
 * 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;
}

Ama bir delta depolar. Eğer depolanmış bir deltayı bulamazsa, bir tane oluşturur. Neden? Anlayabildiğim gibi katran olarak, bu aynı işlemlerle farklı sonuçlara yol açar.

Diyelim ki $price3.595'imiz var ve önbelleğe sahip değiliz $delta. Bu yöntemden geçerken $ delta = 0.000001 elde edeceğiz. Daha sonra $price= 3.595001 $deltaalırız. Ve 3.60'a geri dönüyoruz.

Şimdi bir $pricedeltamız var , hadi tekrar = 3.595 ile yapalım. $price= 3.595 - 0.004999 = 3.590001

Hangi yuvarlak yaparsak, 3.59 alırız. Farklı cevaplar.

Bana öyle geliyor ki, kullanılan herhangi bir yuvarlama algoritması en azından aynı argümanlarla her çalıştırıldığında aynı cevabı vermeli, ama bu sefer değil.


BTW, Magento 2.2.2'de aynı hatayla karşılaştı
TheKitMurkit

Yanıtlar:


9

Sunucumda Magento 1.8 var ve _deltaRound()yöntemi kontrol ettim . Şimdi böyle gözüküyor.

/**
 * 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;
}

Gördüğünüz gibi, _roundingDeltas()ayarlanmadıysa, zerovarsayılan değeri olarak alır . Sadece seni fark ettiđin için. Magento Takımı şüphelerinizi dinleyebilir. Sorununuzu sessizce çözdüler. :)

DÜZENLE

Bu işlevi gerçek zamanlı bir örneğe uygulayarak kullanımını analiz edelim. Sepette vergiye tabi bir ürünüm olduğunu varsayalım. Satın alacağım miktar 5 olacak. Vergi uyguladıktan sonra, ürün 10.5356 $ bir fiyat var. Bu benim durumum

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.

Şimdi bu durumda üretecek olan gerçek fiyatı hesaplayalım. Olacak

  Total =  10.5356 x 5 = 52.678

Şimdi varsayalım, magento _deltaRound()yöntem kullanmıyor . Sadece ürün fiyatını iki ondalık basamağa yuvarlar ve sonra toplam fiyatı hesaplar. Bu durumda, ürün fiyatı yuvarlanır 10.54ve dolayısıyla toplam fiyat

  Total = 10.54 x 5 = 52.7

Şimdi magento'nun _deltaRound()yöntemi kullandığını varsayalım ve bu fonksiyon aslında ürün fiyatını iki ondalığa yuvarlar. Bununla birlikte, gerçek fiyat ve yuvarlak fiyat arasındaki fark olan bir delta değerini tutacak, daha sonra yuvarlak fiyatı hesaplamak için kullanacaktır. Burayaresim açıklamasını buraya girin

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

Bu, _deltaRound()yöntemin aslında vergi fiyatı yuvarlamasını gerçek vergi fiyatlandırmasına göre daha doğru hale getirdiği anlamına gelir . Belirttiğiniz gibi, bu yöntem farklı yuvarlak değer döndürür, delta değerine bağlıdır. Bu delta değeri aslında vergi yuvarlamayı daha doğru hale getirir.

Buna göre, miktar arttıkça, bu yöntemi benimsemezsek, yuvarlatılmış değer ile gerçek değer arasında büyük bir fark yaratacağı sonucuna varabiliriz. Ancak bu yöntemi kullanırsak, yuvarlanmış değerimizi gerçek değerle mümkün olduğunca yakın hale getirir.

Magento varsayılan olarak iki ondalık basamağa yuvarlar. İki ondalık basamak yuvarlamadan sorumlu olan yöntem budur.

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

4 veya daha fazla bir değere ayarlarsak, yuvarlamanın doğruluğunu daha da artırabiliriz.

Not: Bu benim açılışım ve genel bakışım. Doğru olabilir de olmayabilir de. Ancak benim için doğru ve mantıklı görünüyor.

Teşekkürler.


Gerçekten zor kodlu 2 nefret ediyorumroundPrice
David Manners

@DavidManners: evet doğru. Ancak magento _deltaRound()zorluğun üstesinden gelmek için kullanır . Herhangi bir sabit kodlanmış. Bazı durumlarda kesinlikle bazı zorluklar çıkaracaktır
Rajeev K Tomy

1
Github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/… 'a bakıldığında, magento 1.9'da varsayılan değer hala 0.0001'dir, bu da bizim için nakliye konusunda vergi hesaplamalarında bir hataya neden oldu
ProxiBlue

2

Bilgi

Magento'da önceki yuvarlama işlemi deltasına göre yuvarlak fiyat.

app / code / core / Mage / Vergi / Model / Satış / Toplam / Alıntı / Tax.php: 1392 app / code / core / Mage / Vergi / Model / Satış / Toplam / Alıntı / 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;
}

Bazen bu, yüksek delta hesaplama hatası ( $this->_calculator->round($price)) nedeniyle hataya neden olabilir . Örneğin, bu nedenle, bazı fiyatlar ± 1 cent aralığında değişebilir .

Çözüm

Bundan kaçınmak için delta hesaplamasının doğruluğunu artırmanız gerekir.

Değişiklik

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

için

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

Değişikliklerin her iki dosyada da yapılması gerekir:

app / code / core / Mage / Vergi / Model / Satış / Toplam / Alıntı / Tax.php: 1392 app / code / core / Mage / Vergi / Model / Satış / Toplam / Alıntı / Subtotal.php: 719

Çekirdek dosyaları değiştirmeyin veya hacklemeyin! Yeniden yaz!

Çözüm, Magento 1.9.x'in farklı sürümlerinde test edildi, ancak belki de önceki sürümlerde çalışacaktır.

PS

Değiştirme roundPriceişlevi, aşağıda gösterildiği gibi, yuvarlama hata sorununu çözebilir, ancak başkalarına neden olabilir (örneğin, bazı platformlar 2 ondalık basamağa kadar yuvarlama gerektirir).

Uygulama / kod / çekirdek / Mage / çekirdek / Modeli / Store.php: 995

public function roundPrice($price)
{
    return round($price, 4);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.