Magento 2 – How to Set a Custom Shipping Address on Checkout Page

checkoutmagento2shipping-address

On checkout page by default my saved addresses are rendered. How I'll set a custom address as shipping address instead of addresses shown from my account?

I've added an event to observe checkout page load

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="controller_action_predispatch_checkout_index_index">
        <observer name="vendorcheckout_before_dispatch" instance="Vendor\Module\Observer\Dispatch" />
    </event>
</config>

and here is my observer code

<?php

namespace Vendor\Module\Observer;
use Magento\Framework\Event\ObserverInterface;

class Dispatch implements ObserverInterface
{

    public function __construct(
        \Magento\Checkout\Model\Session $session,
        \Magento\Quote\Api\Data\AddressInterface $address,
        \Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement,
        \Magento\Checkout\Api\Data\ShippingInformationInterface $shippingInformation
    )
    {
        $this->session = $session;
        $this->address = $address;
        $this->shippingInformationManagement = $shippingInformationManagement;
        $this->shippingInformation = $shippingInformation;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $address = $this->address
                    ->setFirstname('john')
                    ->setLastname('cena')
                    ->setStreet('xxxx')
                    ->setCity('Delhi')
                    ->setCountryId('US')
                    ->setRegionId(26)
                    ->setRegion('Kansas')
                    ->setPostcode('6666')
                    ->setTelephone('444')
                    ->setFax('3333')
                    ->setSaveInAddressBook(0)
                    ->setSameAsBilling(0);
        if ($this->session->getQuote()) {
            $cartId = $this->session->getQuote()->getId();
            if ($cartId) {
                $add = $this->shippingInformation->setShippingAddress($address);
                $this->shippingInformationManagement->saveAddressInformation($cartId, $add);
            }
        }
    }
}

Above code is throwing

Exception #0 (Magento\Framework\Exception\NoSuchEntityException):
Carrier with such method not found: ,

Just to test manually I've added $carrierCode and $methodCode as flatrate in class module-checkout/Model/ShippingInformationManagement

This is adding shipping address properly to quote_address table. Though on checkout still my account addresses are shown instead of this custom shipping address from quote_address table.

Can someone guide me with following:
1. How to fix exception Carrier with such method not found ?

2. Do I need to update this address somewhere else also to render it on checkout page and save as shipping address with order?

Best Answer

This is how I have achieved it through my module:

etc/frontend/events.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="controller_action_predispatch_checkout_index_index">
        <observer name="customcheckout_before_dispatch" instance="Vendor\Module\Observer\Dispatch" />
    </event>
</config>

Observer/Dispatch.php

<?php

namespace Vendor\Module\Observer;
use Magento\Framework\Event\ObserverInterface;

class Dispatch implements ObserverInterface
{

    public function __construct(
        \Magento\Checkout\Model\Session $session,
        \Magento\Quote\Api\Data\AddressInterface $address,
        \Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement,
        \Magento\Checkout\Api\Data\ShippingInformationInterface $shippingInformation,
        \Magento\Quote\Model\QuoteRepository $quoteRepository,
        \Vendor\Module\Helper\Data $helperData,
        \Magento\Framework\Url $url,
        \Magento\Framework\Message\ManagerInterface $messageManager,
        \Magento\Framework\App\ResponseFactory $responseFactory,
        \Magento\Framework\App\Response\Http $http
    )
    {
        $this->session = $session;
        $this->address = $address;
        $this->shippingInformationManagement = $shippingInformationManagement;
        $this->shippingInformation = $shippingInformation;
        $this->quoteRepository = $quoteRepository;
        $this->helperData = $helperData;
        $this->url = $url;
        $this->messageManager = $messageManager;
        $this->http = $http;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {

        if ($this->session->getQuote()) {
            $cartId = $this->session->getQuote()->getId();
            if ($cartId) {
                $quote = $this->quoteRepository->getActive($cartId);
                $deliveryType = $quote->getDeliveryType();
                if ($deliveryType === 'store') {
                    $this->helperData->saveShippingInformation();
                }
            }

        }
    }

}

Helper/Data.php

<?php
namespace Vendor\Module\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Store\Model\ScopeInterface;

class Data extends AbstractHelper
{

    public function __construct(
        \Magento\Checkout\Model\Session $session,
        \Magento\Quote\Api\Data\AddressInterface $address,
        \Magento\Checkout\Api\ShippingInformationManagementInterface $shippingInformationManagement,
        \Magento\Checkout\Api\Data\ShippingInformationInterface $shippingInformation,
        \Magento\Framework\Message\ManagerInterface $messageManager,
        \Magento\Directory\Model\RegionFactory $regionFactory,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    )
    {
        $this->session = $session;
        $this->address = $address;
        $this->shippingInformationManagement = $shippingInformationManagement;
        $this->shippingInformation = $shippingInformation;
        $this->messageManager = $messageManager;
        $this->regionFactory = $regionFactory;
        $this->scopeConfig = $scopeConfig;

    }

    public function saveShippingInformation()
    {
        if ($this->session->getQuote()) {
            $cartId = $this->session->getQuote()->getId();
            $cartSkuArray = $this->getCartItemsSkus();
            if ($cartSkuArray) {
                $shippingAddress = $this->getShippingAddressInformation();
         $this->shippingInformationManagement->saveAddressInformation($cartId, $shippingAddress);
            }
        }
    }
    public function getShippingAddressInformation() {
        $cartSkuArray = $this->getCartItemsSkus();
        $collectionPointResponse = $this->getCollectionPointAddress($cartSkuArray);
        $shippingAddress = $this->prepareShippingAddress($collectionPointResponse);
        $address = $this->shippingInformation->setShippingAddress($shippingAddress)
            ->setShippingCarrierCode('freeshipping')
            ->setShippingMethodCode('freeshipping');
        return $address;
    }

    /* prepare shipping address from your custom shipping address */
    protected function prepareShippingAddress($collectionPointResponse) {
        $collectionMessage = $collectionPointResponse['message'][0];
        $firstName = $collectionMessage['firstname'];
        $lastName = $collectionMessage['lastname'];
        $countryId = $collectionMessage['country_id'];
        $pincode = $collectionMessage['c_pincode'];
        $region = $collectionMessage['region'];;
        $street = $collectionMessage['c_address'];
        $city = $collectionMessage['c_city'];
        $telephone = $collectionMessage['telephone'];
        $regionId = $this->getRegionByName($region, $countryId);
        $address = $this->address
            ->setFirstname($firstName)
            ->setLastname($lastName)
            ->setStreet($street)
            ->setCity($city)
            ->setCountryId($countryId)
            ->setRegionId($regionId)
            ->setRegion($region)
            ->setPostcode($pincode)
            ->setTelephone($telephone)
            //->setFax('3333')
            ->setSaveInAddressBook(0)
            ->setSameAsBilling(0);
        return $address;
    }

    public function getCartItemsSkus() {
        $cartSkuArray = [];
        $cartItems = $this->session->getQuote()->getAllVisibleItems();
        foreach ($cartItems as $product) {
            $cartSkuArray[] = $product->getSku();
        }
        return $cartSkuArray;
    }

    public function getRegionByName($region, $countryId) {
        return $this->regionFactory->create()->loadByName($region, $countryId)->getRegionId();
    }

    protected function getCollectionPointAddress($cartSkuArray) {
      $customShipping = // write your logic here to gets your custom shipping
    return $customShipping;
    }
}

Note: This code saves shipping information every time you load the checkout page. You need to change it and add it to your specific scenario like I have modified it to save shipping information only when customer selects delivery type in delivery option module which is a different discussion.

Related Topic