Question

In case of virtual products, we do not need a shipping step so customer directly goes for payment step during checkout.

I have a simple product and a custom field delivery_type in quote table. delivery_type field's value is updated on the cart page by selecting what is the delivery type (home/store).

If the value of delivery_type is store shipping step is not required and the customer should see only payment step similar to virtual products at checkout. Can anyone guide me on how I should go about customizing it?

I tried changing the value of field is_virtual to 1 in quote and quote_item table manually but it does not make any difference. I have logged window.checkoutConfig.quoteData.is_virtual which still shows 0.

Was it helpful?

Solution

Please have a look at this class

Magento\Quote\Model\Quote

in this class you have this method isVirtual() [image attached]

if the return result is true, Magento will skip the Shipping Step.

You can override this method or create a "after plugin" (recommended) to change the return value as you want

https://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html

enter image description here

OTHER TIPS

Found generic way to skip shipping, not just for virtual products, in my case I have table driven shipping rate according to zip code (distance), and shipping screen is redundant. The idea is waiting for the shipping screen to load and then approve and continue automatically.

  1. Create requirejs-config.js file in
    app/code/[Vendor]/[Modulename]/view/
    folder and add below code see why.
var config = {
   paths: {
      'Magento_Checkout/js/view/shipping': '[Vendor]_[Modulename]/js/view/shipping'
   }
};
  1. Copy Shipping.js from magento source folder:
    vendor/magento/module-checkout/view/frontend/web/js/view to your module in the following folder:
    app/code/[Vendor]/[Modulename]/view/frontend/web/js/view

  2. Revising the Shipping.js to include the following code:

define([
    'jquery',
    'underscore',
    'Magento_Ui/js/form/form',
    'ko',
    'Magento_Customer/js/model/customer',
    'Magento_Customer/js/model/address-list',
    'Magento_Checkout/js/model/address-converter',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/create-shipping-address',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Checkout/js/model/shipping-rates-validator',
    'Magento_Checkout/js/model/shipping-address/form-popup-state',
    'Magento_Checkout/js/model/shipping-service',
    'Magento_Checkout/js/action/select-shipping-method',
    'Magento_Checkout/js/model/shipping-rate-registry',
    'Magento_Checkout/js/action/set-shipping-information',
    'Magento_Checkout/js/model/step-navigator',
    'Magento_Ui/js/modal/modal',
    'Magento_Checkout/js/model/checkout-data-resolver',
    'Magento_Checkout/js/checkout-data',
    'uiRegistry',
    'mage/translate',
    'Magento_Checkout/js/model/shipping-rate-service'
], function (
    $,
    _,
    Component,
    ko,
    customer,
    addressList,
    addressConverter,
    quote,
    createShippingAddress,
    selectShippingAddress,
    shippingRatesValidator,
    formPopUpState,
    shippingService,
    selectShippingMethodAction,
    rateRegistry,
    setShippingInformationAction,
    stepNavigator,
    modal,
    checkoutDataResolver,
    checkoutData,
    registry,
    $t
) {
    'use strict';

    var popUp = null;

    // ### 1st revision start
    var timer = setInterval(function() {
        // Wait until all page was loaded, using Next button div id
        var nextVar = $( "#shipping-method-buttons-container");
        if (nextVar.length > 0) {
            clearInterval(timer);
            // Make sure 'Next' button is visible
            var nextBtn = $("button", nextVar);
            if (nextBtn.is(":visible")) {
                __self.setShippingInformation();
            }

        }
    }, 100);

    // ### 1st revision end

    return Component.extend({
        defaults: {
            template: 'Magento_Checkout/shipping',
            shippingFormTemplate: 'Magento_Checkout/shipping-address/form',
            shippingMethodListTemplate: 'Magento_Checkout/shipping-address/shipping-method-list',
            shippingMethodItemTemplate: 'Magento_Checkout/shipping-address/shipping-method-item'
        },
        visible: ko.observable(!quote.isVirtual()),
        errorValidationMessage: ko.observable(false),
        isCustomerLoggedIn: customer.isLoggedIn,
        isFormPopUpVisible: formPopUpState.isVisible,
        isFormInline: addressList().length === 0,
        isNewAddressAdded: ko.observable(false),
        saveInAddressBook: 1,
        quoteIsVirtual: quote.isVirtual(),

        /**
         * @return {exports}
         */
        initialize: function () {
            var self = this,
                hasNewAddress,
                fieldsetName = 'checkout.steps.shipping-step.shippingAddress.shipping-address-fieldset';

            // ### last revision start
            __self = self;
            // ### last revision end

            this._super();
            ...

Using setInterval is not best practice, but couldn't find a way to trigger setShippingInformation() after the shipping screen fully loaded. Tried $(document).ready as well as $(window).on("load", function) but the document wasn't fully loaded even then, making the call to setShippingInformation() to be ignored.

Hope this helps anyone.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top