5

When using Paypal express, the shipping options shown in Paypal are not the clean the versions that the customer should see. Instead they see options like -

matrixrate_matrixrate_3378 Select Sh: £5.00 GBP

matrixrate_matrixrate_3374 Select Sh: £5.00 GBP

matrixrate_matrixrate_3373 Select Sh: £9.99 GBP

freeshipping_freeshipping Free - Sto: £0.00 GBP

I'm aware that this is a known problem, but I haven't found answers on how to correct it, or even choose not to display the shipping options in Paypal.

Anyone have any ideas?

Thanks

  • Are you using WebShopApps MatrixRate? If so, then check your spreadsheet to ensure that your columns are in the right spots. It looks like you may have a problem with your uploaded sheet. – seanbreeden Sep 2 '13 at 13:53
  • Hi Sean. Thanks for your comment. Yes, in this situation I was using matrix rates, but also free shipping. In fact, it doesn't matter if I use WSA matrix rates, Amasty table rates, DHL, Fedex, whatever. It always has the same problem. I've tested in a vanilla install and confirm the bug. I've also talked to WSA about it, and they confirm they know of the bug too, and accredit it to the Paypal integration. SO any thoughts on how to correct this would be super useful. Cheers – JamesAllwood Sep 2 '13 at 13:59
  • James, I've worked with WSA's extensions a lot and haven't heard of this bug. When you have time I wouldn't mind having a chat about it on here. Maybe we could help eliminate this for someone else. – seanbreeden Sep 5 '13 at 2:00
5

We're running Magento EE 1.12 and there is at least an option to prevent the shipping options from showing up in Paypal under the Express Checkout basic settings in the Magento Admin:

Magento Admin Screenshot

When Transfer Shipping Options is set to Yes they show up, when it's set to No, they don't. We chose not to display them since they are formatted so strangely. We're not using a shipping extension either. Just the built in shipping options. Would definitely love to hear from anyone who's found a way to display these shipping options in a customer friendly way on the Paypal side.

1

The problem is that Paypal doesn't display the shipping names that are sent across to it, it's displaying the shipping codes that are passed.

File: app/code/core/Mage/Paypal/Model/Express/Checkout.php

The method _prepareShippingOptions() is passing across the parameters to Paypal;

    $options[$i] = new Varien_Object(array(
        'is_default' => $isDefault,
        'name'       => trim("{$rate->getCarrierTitle()} - {$rate->getMethodTitle()}", ' -'),
        'code'       => $rate->getCode(),
        'amount'     => $amountExclTax,
    ));

So to get the shipping options looking pretty in Paypal you just switch around the name and code values;

    $options[$i] = new Varien_Object(array(
        'is_default' => $isDefault,
        'name'       => $rate->getCode(),
        'code'       => trim("{$rate->getCarrierTitle()} - {$rate->getMethodTitle()}", ' -'),
        'amount'     => $amountExclTax,
    ));

Then the method _matchShippingMethodCode() retrieves what's sent back from Paypal when the user continues (or pays, but that's another story) and attempts to match it to the Magento shipping code so the correct shipping method is saved against the order. Slightly comically (as you can see from the original Magento comments) Paypal sometimes sends back the shipping code....and sometimes sends back the shipping name....and sometimes a concatenated mixture. This code is still in CE 1.9, whether that is still the case or not at the Paypal end I don't know but it certainly makes this solution a little less hacky and a little more acceptable.

Paypal has passed back the same $option['code'] and $option['name'] we sent over to it, as we switched them round before we passed them we therefore just return the name rather than the code from this method. ie;

    protected function _matchShippingMethodCode(Mage_Sales_Model_Quote_Address $address, $selectedCode)
    {
        $options = $this->_prepareShippingOptions($address, false);
        foreach ($options as $option) {
            if ($selectedCode === $option['code'] // the proper case as outlined in documentation
                || $selectedCode === $option['name'] // workaround: PayPal may return name instead of the code
                // workaround: PayPal may concatenate code and name, and return it instead of the code:
                || $selectedCode === "{$option['code']} {$option['name']}"
            ) {
                // return $option['code'];
                return $option['name'];
            }
        }
        return '';
    }

So a simple module (to save you having to write it) overloads those two methods and sorts it all out;

app/etc/modules/McNab_PaypalExpressShippingMethod.xml

    <?xml version="1.0"?>
    <config>
        <modules>
            <McNab_PaypalExpressShippingMethod>
                <active>true</active>
                <codePool>local</codePool>
                <depends>
                    <Mage_Paypal />
                </depends>
            </McNab_PaypalExpressShippingMethod>
        </modules>
    </config>

app/code/local/McNab/PaypalExpressShippingMethod/etc/config.xml

    <?xml version="1.0"?>
    <config>
        <modules>
            <McNab_PaypalExpressShippingMethod>
                <version>0.1.0</version>
            </McNab_PaypalExpressShippingMethod>
        </modules>
        <global>
            <models>
                <paypal>
                    <rewrite>
                        <express_checkout>McNab_PaypalExpressShippingMethod_Model_Express_Checkout</express_checkout>
                    </rewrite>
                </paypal>
            </models>
        </global>
    </config> 

app/code/local/McNab/PaypalExpressShippingMethod/Model/Express/Checkout.php

    <?php

    class McNab_PaypalExpressShippingMethod_Model_Express_Checkout extends Mage_Paypal_Model_Express_Checkout {

        // The problem is that Paypal doesn't display the Shipping name that's sent across to it, it's displaying the shipping code.  So to get the shipping options looking pretty in Paypal you just switch around the name and code values

        protected function _prepareShippingOptions(
            Mage_Sales_Model_Quote_Address $address,
            $mayReturnEmpty = false, $calculateTax = false
        ) {
            $options = array(); $i = 0; $iMin = false; $min = false;
            $userSelectedOption = null;

            foreach ($address->getGroupedAllShippingRates() as $group) {
                foreach ($group as $rate) {
                    $amount = (float)$rate->getPrice();
                    if ($rate->getErrorMessage()) {
                        continue;
                    }
                    $isDefault = $address->getShippingMethod() === $rate->getCode();
                    $amountExclTax = Mage::helper('tax')->getShippingPrice($amount, false, $address);
                    $amountInclTax = Mage::helper('tax')->getShippingPrice($amount, true, $address);

                    $options[$i] = new Varien_Object(array(
                        'is_default' => $isDefault,
                        'name'       => $rate->getCode(),
                        'code'       => trim("{$rate->getCarrierTitle()} - {$rate->getMethodTitle()}", ' -'),
                        'amount'     => $amountExclTax,
                    ));
                    if ($calculateTax) {
                        $options[$i]->setTaxAmount(
                            $amountInclTax - $amountExclTax
                                + $address->getTaxAmount() - $address->getShippingTaxAmount()
                        );
                    }
                    if ($isDefault) {
                        $userSelectedOption = $options[$i];
                    }
                    if (false === $min || $amountInclTax < $min) {
                        $min = $amountInclTax;
                        $iMin = $i;
                    }
                    $i++;
                }
            }

            if ($mayReturnEmpty && is_null($userSelectedOption)) {
                $options[] = new Varien_Object(array(
                    'is_default' => true,
                    'name'       => Mage::helper('paypal')->__('N/A'),
                    'code'       => 'no_rate',
                    'amount'     => 0.00,
                ));
                if ($calculateTax) {
                    $options[$i]->setTaxAmount($address->getTaxAmount());
                }
            } elseif (is_null($userSelectedOption) && isset($options[$iMin])) {
                $options[$iMin]->setIsDefault(true);
            }

            // Magento will transfer only first 10 cheapest shipping options if there are more than 10 available.
            if (count($options) > 10) {
                usort($options, array(get_class($this),'cmpShippingOptions'));
                array_splice($options, 10);
                // User selected option will be always included in options list
                if (!is_null($userSelectedOption) && !in_array($userSelectedOption, $options)) {
                    $options[9] = $userSelectedOption;
                }
            }

            return $options;
        }

        // Paypal has passed back the same `$option['code']` and `$option['name']` we sent over to it, as we switched them round before we passed them we therefore just return the name rather than the code from this method.  ie;

        protected function _matchShippingMethodCode(Mage_Sales_Model_Quote_Address $address, $selectedCode)
        {
            $options = $this->_prepareShippingOptions($address, false);
            foreach ($options as $option) {
                if ($selectedCode === $option['code'] // the proper case as outlined in documentation
                    || $selectedCode === $option['name'] // workaround: PayPal may return name instead of the code
                    // workaround: PayPal may concatenate code and name, and return it instead of the code:
                    || $selectedCode === "{$option['code']} {$option['name']}"
                ) {
                    return $option['name'];
                }
            }
            return '';
        }


    }    
  • This is really useful, thanks! However, the shipping option still appears as follows: DHL tablerate_bestway x,xx € while it should just be DHL x,xx € – loeffel Aug 10 '15 at 12:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.