0

For my Paypal Payment issue,

I just want to update the following function,

app/code/Magento/Paypal/Model/Api/Nvp.php

protected function _applyStreetAndRegionWorkarounds(DataObject $address)
{
// merge street addresses into 1
if ($address->getData('street2') !== null) {
$address->setStreet(implode("\n", [$address->getData('street'), $address->getData('street2')]));
$address->unsetData('street2');
}
// attempt to fetch region_id from directory
if ($address->getCountryId() && $address->getRegion()) {
$regions = $this->_countryFactory->create()
->loadByCode($address->getCountryId())
->getRegionCollection()
->addRegionCodeOrNameFilter($address->getRegion())
->setPageSize(1);
if ($regions->count()) {
$regionItems = $regions->getItems();
$region = array_shift($regionItems);
$address->setRegionId($region->getId());
$address->setExportedKeys(array_merge($address->getExportedKeys(), ['region_id']));
}
}
}

Instead of

  protected function _applyStreetAndRegionWorkarounds(DataObject $address)
    {
        // merge street addresses into 1
        if ($address->getData('street2') !== null) {
            $address->setStreet(implode("\n", [$address->getData('street'), $address->getData('street2')]));
            $address->unsetData('street2');
        }
        // attempt to fetch region_id from directory
        if ($address->getCountryId() && $address->getRegion()) {
            $regions = $this->_countryFactory->create()->loadByCode(
                $address->getCountryId()
            )->getRegionCollection()->addRegionCodeOrNameFilter(
                $address->getRegion()
            )->setPageSize(
                1
            );
            $regionItems = $regions->getItems();
            $region = array_shift($regionItems);
            $address->setRegionId($region->getId());
            $address->setExportedKeys(array_merge($address->getExportedKeys(), ['region_id']));
        }
    }

Source: https://github.com/magento/magento2/issues/26698

What is the best way to edit core files? Module or Preference or anything else?

My Error:

Fatal error: Uncaught Error: Call to a member function getId() on null in /var/www/html/test/app/code/Magento/Paypal/Model/Api/Nvp.php:1524 Stack trace: 
#0 /var/www/html/test/app/code/Magento/Paypal/Model/Api/Nvp.php(1493): Magento\Paypal\Model\Api\Nvp->_applyStreetAndRegionWorkarounds(Object(Magento\Framework\DataObject)) 
#1 /var/www/html/test/app/code/Magento/Paypal/Model/Api/Nvp.php(849): Magento\Paypal\Model\Api\Nvp->_exportAddresses(Array) 
#2 /var/www/html/test/app/code/Magento/Paypal/Model/Express/Checkout.php(621): Magento\Paypal\Model\Api\Nvp->callGetExpressCheckoutDetails() 
#3/var/www/html/test/app/code/Magento/Paypal/Controller/Express/AbstractExpress/ReturnAction.php(32): Magento\Paypal\Model\Express\Checkout->returnFromPaypal('*********') 
#4/var/www/html/test/generated/code/Magento/Paypal/Controller/Express/ReturnAction/Interceptor.php(24): Magento\Paypal\Controller\Express\AbstractExpress\ReturnAction->execute() 
#5 /var/www/html/test/lib/internal/Magento/Framework/App/Action/Ac in /var/www/html/test/app/code/Magento/Paypal/Model/Api/Nvp.php on line 15

Note: Is the following patch suitable for my error,

https://magento.com/tech-resources/download#tab-36 (PayPal Express Checkout issue with region patch for Magento 2.3.4)

3

1 Answer 1

1

In your di.xml create a preference to your own implementation

app/code/StackExchange/PayPalPreference/etc/di.xml

<?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="StackExchange\PayPalPreference\Model\Api\Nvp"
 />
</config>

In your own implementation, extend the class you want to change and override only the method in question. You will have to create a constructor matching the parent constructor, it will look something like this:

app/code/StackExchange/PayPalPreference/Model/Api/Nvp.php

<?php
declare(strict_types=1);

namespace StackExchange\PayPalPreference\Model\Api;

use Magento\Payment\Model\Method\Logger;

class Nvp extends \Magento\Paypal\Model\Api\Nvp
{
    public function __construct(
        \Magento\Customer\Helper\Address $customerAddress,
        \Psr\Log\LoggerInterface $logger,
        \Magento\Payment\Model\Method\Logger $customLogger,
        \Magento\Framework\Locale\ResolverInterface $localeResolver,
        \Magento\Directory\Model\RegionFactory $regionFactory,
        \Magento\Directory\Model\CountryFactory $countryFactory,
        \Magento\Paypal\Model\Api\ProcessableExceptionFactory $processableExceptionFactory,
        \Magento\Framework\Exception\LocalizedExceptionFactory $frameworkExceptionFactory,
        \Magento\Framework\HTTP\Adapter\CurlFactory $curlFactory,
        array $data = []
    ) {
        parent::__construct($customerAddress, $logger, $customLogger, $localeResolver, $regionFactory, $countryFactory, $processableExceptionFactory, $frameworkExceptionFactory, $curlFactory, $data);
    }

    protected function _applyStreetAndRegionWorkarounds(DataObject $address)
    {
        if ($address->getData('street2') !== null) {
            $address->setStreet(implode("\n", [$address->getData('street'), $address->getData('street2')]));
            $address->unsetData('street2');
        }
        if ($address->getCountryId() && $address->getRegion()) {
            $regions = $this->_countryFactory->create()
                ->loadByCode($address->getCountryId())
                ->getRegionCollection()
                ->addRegionCodeOrNameFilter($address->getRegion())
                ->setPageSize(1);
            if ($regions->count()) {
                $regionItems = $regions->getItems();
                $region = array_shift($regionItems);
                $address->setRegionId($region->getId());
                $address->setExportedKeys(array_merge($address->getExportedKeys(), ['region_id']));
            }
        }
    }
}

You can change the app/code/StackExchange/PayPalPreference/Model/Api/Nvp.php like this and use storeManager to fetch website id to decide whether to run the code or not for particular websites:

<?php
declare(strict_types=1);

namespace StackExchange\PayPalPreference\Model\Api;

use Magento\Store\Model\StoreManagerInterface;

class Nvp extends \Magento\Paypal\Model\Api\Nvp
{
    /**
     * @var StoreManagerInterface
     */
    private StoreManagerInterface $storeManager;

    public function __construct(
        \Magento\Customer\Helper\Address $customerAddress,
        \Psr\Log\LoggerInterface $logger,
        \Magento\Payment\Model\Method\Logger $customLogger,
        \Magento\Framework\Locale\ResolverInterface $localeResolver,
        \Magento\Directory\Model\RegionFactory $regionFactory,
        \Magento\Directory\Model\CountryFactory $countryFactory,
        \Magento\Paypal\Model\Api\ProcessableExceptionFactory $processableExceptionFactory,
        \Magento\Framework\Exception\LocalizedExceptionFactory $frameworkExceptionFactory,
        \Magento\Framework\HTTP\Adapter\CurlFactory $curlFactory,
        StoreManagerInterface $storeManager,
        array $data = []
    ) {
        parent::__construct($customerAddress, $logger, $customLogger, $localeResolver, $regionFactory, $countryFactory, $processableExceptionFactory, $frameworkExceptionFactory, $curlFactory, $data);

        $this->storeManager = $storeManager;
    }

    protected function _applyStreetAndRegionWorkarounds(DataObject $address)
    {
        // e.g. if you do not want to run the code on website id = 2
        if ($this->storeManager->getWebsite()->getId() == 2) {
            parent::_applyStreetAndRegionWorkarounds($address);
            return;
        }

        if ($address->getData('street2') !== null) {
            $address->setStreet(implode("\n", [$address->getData('street'), $address->getData('street2')]));
            $address->unsetData('street2');
        }
        if ($address->getCountryId() && $address->getRegion()) {
            $regions = $this->_countryFactory->create()
                ->loadByCode($address->getCountryId())
                ->getRegionCollection()
                ->addRegionCodeOrNameFilter($address->getRegion())
                ->setPageSize(1);
            if ($regions->count()) {
                $regionItems = $regions->getItems();
                $region = array_shift($regionItems);
                $address->setRegionId($region->getId());
                $address->setExportedKeys(array_merge($address->getExportedKeys(), ['region_id']));
            }
        }
    }
}
9
  • For my clarity, we can overwrite the function only instead of overwriting the whole code right? My Path: app/code/Magento/Paypal/Model/Api/Nvp.php My code: paste.ofcode.org/3bS9xNEMCPgj8NbFhTuEKC9 search function _applyStreetAndRegionWorkarounds
    – zus
    Commented Nov 3, 2020 at 10:25
  • 1
    Yes, if you want to override one function you only have to extend the class as I did above and only implement the function you want to change
    – Kristoffer
    Commented Nov 3, 2020 at 10:27
  • Thank you, for my clarity shall we extend two functions in the above condition?
    – zus
    Commented Nov 3, 2020 at 10:28
  • 1
    sure, no problems. In my code above I implemented only one function. The other __construct is a constructor which Magento will need to make the extending work when the classes are initiated by the object manager
    – Kristoffer
    Commented Nov 3, 2020 at 10:31
  • Last one, thanks for your patience. Here i am using Multi-Website, both website i am using PayPal. Website 1 for USA Paypal working good, website 2 for Australia here only i am facing the PayPal issue, What should i do here, shall i add website filter in this condition, pls guide me. thank you.
    – zus
    Commented Nov 3, 2020 at 10:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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