Tại sao Magento lưu trữ một đồng bằng tròn khi tính thuế


14

Trong mô hình tax/Sales_Total_Quote_Tax, có một phương pháp _deltaRound()làm tròn giá. Nó thêm một delta nhỏ, để ngăn chặn hành vi không xác định khi làm tròn 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;
}

Nhưng nó lưu trữ một đồng bằng. Nếu nó không thể tìm thấy một delta được lưu trữ như vậy, nó tạo nên một delta. Tại sao? Như tar như tôi có thể nói, điều này dẫn đến kết quả khác nhau với các hoạt động giống hệt nhau.

Giả sử chúng ta có $price3.595 và chúng ta không có bộ nhớ cache $delta. Khi chúng ta thực hiện phương thức này, chúng ta sẽ thu được $ delta = 0,000001. Sau đó, chúng tôi nhận được $price= 3.595001, làm tròn đến 3,60, vì vậy chúng tôi có số mới $deltalà -0,004999. Và chúng tôi trả lại 3,60.

Ngoại trừ bây giờ chúng ta có một đồng bằng, vì vậy hãy làm lại, với $price= 3.595. $price= 3.595 - 0,004999 = 3.590001

Mà nếu chúng ta làm tròn, chúng ta nhận được 3,59. Câu trả lời khác nhau.

Dường như với tôi, bất kỳ thuật toán làm tròn nào được sử dụng ít nhất nên đưa ra cùng một câu trả lời mỗi khi nó được chạy với cùng một đối số, nhưng không phải lúc này.


BTW, đã gặp lỗi tương tự trong Magento 2.2.2
TheKitMurkit

Câu trả lời:


9

Tôi có Magento 1.8 trên máy chủ của mình và tôi đã kiểm tra _deltaRound()phương pháp. Nó trông như thế này bây giờ.

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

Như bạn có thể thấy, nếu _roundingDeltas()không được đặt, nó sẽ lấy zerogiá trị mặc định của nó. Nó chỉ để thông báo cho bạn. Đội Magento có thể nghe lỏm nghi ngờ của bạn. Họ âm thầm giải quyết vấn đề của bạn. :)

BIÊN TẬP

Hãy để chúng tôi phân tích việc sử dụng chức năng này bằng cách áp dụng nó vào một ví dụ thời gian thực. Giả sử tôi có một sản phẩm trong giỏ hàng chịu thuế. Số lượng mà tôi sẽ mua là 5. Sau khi áp dụng thuế, prdouct có giá $ 10,5356. Vì vậy, đây là tình huống của tôi

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.

Vì vậy, bây giờ chúng ta hãy tính giá thực sẽ sản xuất trong tình huống này. Nó sẽ là

  Total =  10.5356 x 5 = 52.678

Bây giờ chúng ta hãy giả sử, magento không sử dụng _deltaRound()phương pháp. Nó chỉ làm tròn giá sản phẩm lên đến hai chữ số thập phân và sau đó tính tổng giá. Trong trường hợp này, giá sản phẩm sẽ được làm tròn đến 10.54và do đó tổng giá sẽ là

  Total = 10.54 x 5 = 52.7

Bây giờ chúng ta hãy giả sử magento đang sử dụng _deltaRound()phương thức và chức năng này thực sự làm tròn giá sản phẩm thành hai phần thập phân. Cùng với đó, nó sẽ giữ một giá trị delta, trên thực tế là chênh lệch giữa giá thực tế và giá làm tròn, sẽ được sử dụng để tính giá làm tròn sau này. Đâynhập mô tả hình ảnh ở đây

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

Điều đó có nghĩa là _deltaRound()phương pháp thực sự làm cho giá thuế làm tròn chính xác hơn với giá thuế thực tế. Như bạn đã nói phương pháp này trả về giá trị vòng khác nhau phụ thuộc vào giá trị delta. Giá trị delta này thực sự làm cho việc làm tròn thuế chính xác hơn.

Theo đó, chúng ta có thể kết luận rằng, khi số lượng tăng, nếu chúng ta không áp dụng phương pháp này, nó sẽ tạo ra sự khác biệt lớn giữa giá trị làm tròn và giá trị thực. Nhưng nếu chúng ta sử dụng phương pháp này, nó sẽ làm cho giá trị làm tròn của chúng ta càng gần với giá trị thực.

Magento theo mặc định làm tròn đến hai chữ số thập phân. Đây là phương pháp chịu trách nhiệm làm tròn hai chữ số thập phân

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

Nếu chúng ta đặt nó thành 4 hoặc một cái gì đó, chúng ta có thể tăng thêm độ chính xác của làm tròn.

Lưu ý: Đây là ý kiến ​​và tổng quan của tôi. Nó có thể đúng hoặc không đúng. Tuy nhiên nó có vẻ chính xác và hợp lý đối với tôi.

Cảm ơn.


Tôi thực sự ghét 2 người khó tínhroundPrice
David Manners

@DavidManners: đúng vậy. Nhưng magento sử dụng _deltaRound()để vượt qua khó khăn bằng cách mở rộng. Bất kỳ mã hóa cứng của nó. Nó chắc chắn sẽ gây ra một số khó khăn trong một số trường hợp
Rajeev K Tomy

1
Nhìn vào github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/ , giá trị mặc định vẫn là 0,0001 trong magento 1.9, điều này đối với chúng tôi đã dẫn đến một lỗi nghiêm trọng khi giao hàng
ProxiBlue

2

Thông tin

Giá tròn trong Magento dựa trên delta hoạt động làm tròn trước.

ứng dụng / mã / lõi / Pháp sư / Thuế / Mô hình / Bán hàng / Tổng số / Trích dẫn / Thuế.php: 1392 ứng dụng / mã / lõi / Pháp sư / Thuế / Mô hình / Bán hàng / Tổng số / Trích dẫn / 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;
}

Đôi khi điều này có thể gây ra lỗi do lỗi tính toán delta cao ( $this->_calculator->round($price)). Ví dụ, vì lý do này, một số giá có thể thay đổi trong phạm vi ± 1 cent .

Giải pháp

Để tránh điều này, bạn cần cải thiện tính chính xác của phép tính delta.

Thay đổi

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

đến

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

Thay đổi cần phải được thực hiện trong cả hai tệp:

ứng dụng / mã / lõi / Pháp sư / Thuế / Mô hình / Bán hàng / Tổng số / Trích dẫn / Thuế.php: 1392 ứng dụng / mã / lõi / Pháp sư / Thuế / Mô hình / Bán hàng / Tổng số / Trích dẫn / Subtotal.php: 719

Đừng sửa đổi hoặc hack các tập tin cốt lõi! Làm lại!

Giải pháp đã được thử nghiệm trên các phiên bản khác nhau của Magento 1.9.x, nhưng có lẽ điều này sẽ hoạt động trong các phiên bản trước.

PS

Thay đổi roundPricechức năng, như được hiển thị bên dưới, có thể giải quyết vấn đề lỗi làm tròn, nhưng nó có thể gây ra các vấn đề khác (ví dụ: một số nền tảng yêu cầu làm tròn đến 2 chữ số thập phân).

ứng dụng / mã / lõi / Pháp sư / Lõi / Mô hình / Cửa hàng.php: 995

public function roundPrice($price)
{
    return round($price, 4);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.