Nachbesserung der Rundungsfehlerkorrektur in Magento und PayPal

Rounding Error Fix for Magento and PayPal 1.0.4 auf Magento ConnectRounding Error Fix for Magento and PayPal

Nach der Veröffentlichung unserer Erweiterung, die den Rundungsfehler ausschließlich durch bedingte Erhöhung der Rundungsgenauigkeit korrigieren sollte, wurden uns Konstellationen berichtet, in den der Fehler weiterhin auftritt.

In unserer bisherigen Lösung haben wir die Manipulation der Beträge durch Addition oder Subtraktion des Rundungsfehlers vermieden.

Um sicherzustellen, dass die Warenkorbdaten nach PayPal so übertragen werden, dass die Schlüsselbeträge mit den der Bestellung in Magento übereinstimmen, haben wir uns entschieden nun doch die Formulardaten des PayPal-Moduls zu manipulieren!

Wir erweitern die Methode Mage_Paypal_Model_Api_Standard::getStandardCheckoutRequest, die die Formulardaten für PayPal-Zahlungen bereitstellt. Die Schlüsselbeträge sind die Mehrwertsteuer und der Gesamtbetrag. Da die Nettopreise einzelner Artikel und der Versandkosten nicht direkt in der Magento-Bestelung zu sehen sind, wird die Anpassung dieser Werte nicht auffallen.

Für die Anpassung der Formulardaten gehen wir wie folgt vor:

  • Vergleiche den für PayPal vorbereiteten Gesamtwert mit dem Gesamtwert der Bestellung: Beträgt die Differenz der beiden Werte nicht Null, wird der Rundungsfehler korrigiert. Aufgrund der in Magento bereits vorhandener Logik für die Korrektur des Rundungsfehlers, nehmen wir an, dass der gerundete Rundungsfehler +0.01 oder -0.01 betragen kann.
  • Rekonstruiere die Schlüsselwerte des PayPal-Formulars aus den Bestelldaten: Netto-Gesamtwert der Bestellung, Mehrwertsteuerbetrag, Netto-Versandkosten. Zusätzlich werden noch die Brutto-Versandkosten berechnet, um festzustellen, ob hier ein Rundungsfehler vorliegt.
  • Korrigiere den Rundungsfehler durch Anpassung von: Netto-Versandkosten oder des Netto-Preises des letzten Warenkorbartikels oder des Mehrwertsteuerbetrags. Die Anpassung wird im ersten dieser Schlüsselwerte vorgenommen, bei dem ein Rundungsfehler, berechnet im vorigen Schritt, vorliegt. Aus der Magento-eigenen Rundungsfehlerkorrektur ist uns nicht bekannt, wie der Rundungsfehler des letzten Warenkorbartikels verwendet wird. Deshalb erscheint es uns sinnvoll für die Rundungsfehlerkorrektur den Netto-Preis des letzten Warenkorbartikels anzupassen.

Es folgt die Methode, die die Rundungsfehlerkorrektur implementiert:

public function getStandardCheckoutRequest()
{
    // calculate the rounded request total
    $request = parent::getStandardCheckoutRequest();
    $requestBaseGrandTotal = round($request['amount'] + $request['tax'] - $request['discount_amount'], 2);

    // get the rounded order total
    $orderObj = Mage::getSingleton('sales/order')
                ->loadByIncrementId(Mage::getSingleton('checkout/session')->getLastRealOrderId());
    $orderBaseGrandTotal = round($orderObj->getBaseGrandTotal(), 2);

    // get the rounded rounding error
    $roundingError = round($orderBaseGrandTotal - $requestBaseGrandTotal, 2); // -0.01 or +0.01

    // fix the rounding error
    if($roundingError) {
        $order = array(); // create an array from order data resembling the structure or the request array
        $roundingDeltas = array(); // save the rounding error

        $order['amount'] = round($orderObj->getBaseSubtotal() + $orderObj->getBaseShippingAmount(), 2);
        $roundingDeltas['amount'] = ($orderObj->getBaseSubtotal() + $orderObj->getBaseShippingAmount()) - $order['amount'];

        $order['tax'] = round($orderObj->getBaseTaxAmount(), 2);
        $roundingDeltas['tax'] = $orderObj->getBaseTaxAmount() - $order['tax'];

        $order['shipping'] = round($orderObj->getBaseShippingAmount(), 2);
        $roundingDeltas['shipping'] = $orderObj->getBaseShippingAmount() - $order['shipping'];

        // not contained in the request but useful to determine if there is a rounding error in shipping
        $order['shipping_incl_tax'] = round($orderObj->getBaseShippingAmount() + $orderObj->getBaseShippingTaxAmount(), 2);
        $roundingDeltas['shipping_incl_tax'] = ($orderObj->getBaseShippingAmount() + $orderObj->getBaseShippingTaxAmount()) - $order['shipping_incl_tax'];

        $orderTotalItemCount = $orderObj->getTotalItemCount();

        // hide rounding error in shipping
        if($roundingDeltas['shipping_incl_tax'] && $order['shipping'] > 0) {
            if(isset($request['amount_'.($orderTotalItemCount+1)])) { // ensure that the shipping item is there
                $request['amount_'.($orderTotalItemCount+1)] += $roundingError;
            }
            $request['shipping'] += $roundingError;
            $request['amount'] += $roundingError;

        // hide rounding error in the last cart item
        } elseif($roundingDeltas['amount'] && $order['amount'] > 0) {
            if(isset($request['amount_'.($orderTotalItemCount+1)])) {
                $request['amount_'.($orderTotalItemCount+1)] += $roundingError;
            }
            $request['amount'] += $roundingError;
        } else {
            // hide rounding error in tax
            if($order['tax'] > 0) {
                $request['tax'] += $roundingError;
                $request['tax_cart'] += $roundingError;
            } else {
                // do not correct rounding error in this unexpected situation
            }
        }

    }
    return $request;
}

Rounding Error Fix for Magento and PayPal 1.0.4 auf Magento ConnectRounding Error Fix for Magento and PayPal

3 Gedanken zu „Nachbesserung der Rundungsfehlerkorrektur in Magento und PayPal“

  1. Kann es sein, dass bei $requestBaseGrandTotal ein „+ $request[’shipping‘]“ fehlt?
    In einem Test von mir war der RoundingError gleich dem Shipping Betrag. Was dann wiederum zu fehlerhaften Berechnungen führte.

  2. Hallo,

    vielen vielen Dank für diese Arbeit! Ich habe eine Frage
    – Alle anderen „Rundungsproblematiken“ (der Klassiker 33,99 EUR Artikel mit 19% MwSt. wird im Cataloge zu 40,00 EUR usw.) habt ihr damit auch im Griff?
    Sprich – „Better Rounding“ Extensions können rausfliegen? Oder sollten die drinbleiben?

    Ich hab mal vorsichtig damit getestet, bislang geht alles soweit… Habe aber noch nicht sämtliche Konstellationen durch (Rabatte, MwSt. usw.)

    Und was ist mit dem Hinweis von AndiD ? Ist da was dran?
    Danke für ein kurzes Feedback!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.