Advertisement

Facebook

Fixing the PayPal NVP Gateway Error in Magento 2.4: 'The Totals of the Cart Item Amounts Do Not Match Order Amounts'

When integrating PayPal's NVP (Name-Value Pair) gateway with Magento 2.4, many merchants encounter a frustrating error that blocks transactions from being processed. The error message is:
[XXXX-XX-20T13:28:28.179037+00:00] main.CRITICAL: PayPal NVP gateway errors: The totals of the cart item amounts do not match order amounts (#10413: Transaction refused because of an invalid argument. See additional error messages for details). Correlation ID: 6803ed78cc7c0. Version: 72.0. [] []
[XXXX-XX-20T13:28:28.180779+00:00] main.ERROR: Magento2 v3.5.1: PayPal gateway has rejected request. The totals of the cart item amounts do not match order amounts (#10413: Transaction refused because of an invalid argument. See additional error messages for details). [] []
xxxxxxxxxxxxxxxxxxxx
'L_SHORTMESSAGE0' => 'Transaction refused because of an invalid argument. See additional error messages for details.', 'L_LONGMESSAGE0' => 'The totals of the cart item amounts do not match order amounts.',
xxxxxxxxxxxxxxxxxxxx

This issue often arises when the total amount passed to PayPal does not match the totals calculated by Magento. The mismatch typically happens due to issues with tax or shipping amounts. Fortunately, there's a straightforward solution that ensures the totals are calculated correctly, eliminating the error. In this blog post, we will walk you through the process of fixing this issue. 

Understanding the Error

The error occurs when the PayPal NVP gateway receives inconsistent information about the total order amount, including item amounts, tax, and shipping. PayPal expects these amounts to match exactly, and if they do not, it throws the 10413 error.

This discrepancy often arises from the ITEMAMT (item amount), TAXAMT (tax amount), and SHIPPINGAMT (shipping amount) fields being improperly calculated or passed to PayPal during checkout.

Steps to Fix the PayPal NVP Gateway Error

To address the issue, we will create a custom module that overrides Magento's default PayPal functionality. This allows us to adjust how the totals are calculated before sending the request to PayPal.

Step-1: Create the registration.php file at app/code/VendorName/ModuleName and add the following code:


<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'VendorName_ModuleName',
    __DIR__
);

Step-2: Create the module.xml file at app/code/VendorName/ModuleName/etc and add the following code:


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="VendorName_ModuleName" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Paypal"/>
        </sequence>
    </module>
</config>
	

Step-3: Create the di.xml file at app/code/VendorName/ModuleName/etc and add the following code:


<?xml version="1.0" ?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Paypal\Model\Api\Nvp" type="VendorName\ModuleName\Model\Api\Nvp" />
</config>
	

Step-4: Create the Nvp.php file at app/code/VendorName/ModuleName/Model/Api and add the following code:

Now, we will override the Nvp class in the PayPal module and modify two critical functions: callSetExpressCheckout() and callDoExpressCheckoutPayment().


<?php

namespace VendorName\ModuleName\Model\Api;

use Magento\Paypal\Model\Api\Nvp as PayPalNvp;

class Nvp extends PayPalNvp
{
    /**
     * SetExpressCheckout call
     *
     * TODO: put together style and giropay settings
     *
     * @return void
     *
     * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetExpressCheckout
     */
    public function callSetExpressCheckout()
    {
        $this->_prepareExpressCheckoutCallRequest($this->_setExpressCheckoutRequest);
        $request = $this->_exportToRequest($this->_setExpressCheckoutRequest);
        $this->_exportLineItems($request);

        // import/suppress shipping address, if any
        $options = $this->getShippingOptions();
        if ($this->getAddress()) {
            $request = $this->_importAddresses($request);
            $request['ADDROVERRIDE'] = 1;
        } elseif ($options && count($options) <= 10) {
            // doesn't support more than 10 shipping options
            $request['CALLBACK'] = $this->getShippingOptionsCallbackUrl();
            $request['CALLBACKTIMEOUT'] = 6;
            // max value
            $request['MAXAMT'] = $request['AMT'] + 999.00;
            // it is impossible to calculate max amount
            $this->_exportShippingOptions($request);
        }

        // custom code start
        $taxAmt = isset($request['TAXAMT']) ? $request['TAXAMT'] : 0;
        $shippingAmt = isset($request['SHIPPINGAMT']) ? $request['SHIPPINGAMT'] : 0;
        $request['ITEMAMT'] = $request['AMT'] - $taxAmt - $shippingAmt;
        // custom code end

        $response = $this->call(self::SET_EXPRESS_CHECKOUT, $request);
        $this->_importFromResponse($this->_setExpressCheckoutResponse, $response);
    }

    /**
     * DoExpressCheckout call
     *
     * @return void
     *
     * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoExpressCheckoutPayment
     */
    public function callDoExpressCheckoutPayment()
    {
        $this->_prepareExpressCheckoutCallRequest($this->_doExpressCheckoutPaymentRequest);
        $request = $this->_exportToRequest($this->_doExpressCheckoutPaymentRequest);
        $this->_exportLineItems($request);

        if ($this->getAddress()) {
            $request = $this->_importAddresses($request);
            $request['ADDROVERRIDE'] = 1;
        }

        // custom code start
        $taxAmt = isset($request['TAXAMT']) ? $request['TAXAMT'] : 0;
        $shippingAmt = isset($request['SHIPPINGAMT']) ? $request['SHIPPINGAMT'] : 0;
        $request['AMT'] = $request['ITEMAMT'] + $taxAmt + $shippingAmt;
        // custom code end

        $response = $this->call(self::DO_EXPRESS_CHECKOUT_PAYMENT, $request);
        $this->_importFromResponse($this->_paymentInformationResponse, $response);
        $this->_importFromResponse($this->_doExpressCheckoutPaymentResponse, $response);
        $this->_importFromResponse($this->_createBillingAgreementResponse, $response);
    }
}
	

The callSetExpressCheckout() function prepares the request sent to PayPal when a customer initiates the checkout process. Here, we need to adjust how the totals are calculated, subtracting the tax and shipping amounts from the total to determine the ITEMAMT.

The callDoExpressCheckoutPayment() function processes the final payment after the customer confirms it. Here, we again need to ensure the amounts are correctly calculated, adjusting the AMT field to include ITEMAMT, TAXAMT, and SHIPPINGAMT.

Step-5: Run the Commands to Enable the Module and Test

Now that all the code is in the correct locations, Run the following commands to enable the module and test the changes:


php bin/magento module:enable VendorName_ModuleName
php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy -f
php bin/magento setup:di:compile
php bin/magento cache:clean
	

Test the checkout process once the module is enable to ensure the PayPal integration works as expected. Verify that the 10413 error is resolved and transactions are processed successfully.

Conclusion

By following these steps, you can successfully resolve the "totals of the cart item amounts do not match order amounts" error in Magento 2.4 when using PayPal’s NVP gateway. The root cause of the error is the mismatch between the totals calculated by Magento and those sent to PayPal, and our custom module ensures that the totals are accurately calculated and passed to PayPal for a smooth transaction process.

This solution provides an easy fix for this common issue, ensuring that your customers can complete their purchases without any disruptions. For more tips on Magento or other payment integration solutions, stay tuned to our blog!

Post a Comment

0 Comments

Buy Me A Coffee