How to Customize the Checkout Process in Magento 2

Dec 18, 20181088Gennadiy Haritonov
How to Customize the Checkout Process in Magento 2

In this article we will examine in great detail the question from Magento 2 Certification – Customizing the Checkout Process. The topic itself is rather complicated, so we got here a very large post, so for you to navigate in it, here’s the three aspects we’re going investigate:

How to use quote, quote item, address, and shopping cart rules in checkout
How to use totals models
How to customize the shopping cart

How to use quote, quote item, address, and shopping cart rules in checkout

What is quote?

Let’s begin with the notion of a quote itself, what is it used for and where is it stored.  When a customer adds a new item to the cart, Magento creates a Quote. It is used for the following purposes:

  • to track the products that a customer wants to buy along with their cost and quantity;
  • to collect customer information, including billing address and shipping address;
  • to assess Shipping Cost;
  • to calculate the subtotal price, to add (shipping cost, taxes, etc.) and use coupons for determining the total amount;
  • to determine the payment method;
  • to place an order so that the seller can fulfill it.

There are the following tables for storing Quote in the database:

  • quote
  • quote_address
  • quote_address_item
  • quote_id_mask
  • quote_item
  • quote_item_option
  • quote_payment
  • quote_shipping_rate

The Magento\Quote\Model\Quote model is responsible for Quote. The Magento\Quote\Model\Quote\Address\Quote model is responsible for Quote Address and usually contains 2 addresses (billing, shipping), but can have more (if the customer specified multiple shipping addresses) or none at all. If there is no address in Quote, then the Price Rules associated with the country will not be taken into account in Totals. If Quote contains virtual products only, then the shipping address is ignored and checked by the isVirtual() method of the Magento\Quote\Model\Quote class. Only the billing address is considered for Quote with virtual products. The Magento\Quote\Model\Quote\Item model is responsible for products in Quote. The Magento\Quote\Model\Quote\Payment model is responsible for payment in Quote.

Useful quote fields or methods

The “quote” table has a field called “ext_shipping_info” where you can add some extra information.
If “quote” has the “trigger_recollect” flag and its elements were changed, they will be reassembled via the Magento\NegotiableQuote\Plugin\Quote\Model\QuotePlugin around CollectTotals() function (Magento Commerce only). After performing the collectTotals() function, the elements marked as deleted will be deleted. This method compares the elements that existed in “quote” before collectTotals() was called. If certain elements are absent after the function has been executed, this method sets the deletion notifications of them.
If the “trigger_recollect” flag is set, then provided the price is changed or the product status is set to “disabled”, quote will be updated after the item is saved. The same happens if we change the rules of the “CatalogRules” directory. We can find these methods in the Magento\Quote\Model\ResourceModel markQuotesRecollectOnCatalogRules() and markQuotesRecollect() classes.
Quote can also be extended via Magento\Framework\Model\AbstractExtensibleModel — it supports “extension_attributes“. You can register the extension via the extension_attributes.xml file:

Use the “Quote Repository Plugin” to fill in your values using the afterLoad(), beforeSave() or whenever() functions. Quote does not use “custom_attributes” as they are not EAV.

Quote address custom attributes

  • “CE” \Magento\Quote\Model\Quote\Address\CustomAttributeList getAttributes() returns empty array. A plugin needs to be written for the implementation.
  • “EE” \Magento\CustomerCustomAttributes\Model\Quote\Address\CustomAttributeList::getAttributes returns “customer address attributes” + “customer attributes”.

Quote item useful methods:

  • Magento\Quote\Model\Quote\Item checkData() is called after adding to cart and updating options;
  • Magento\Quote\Model\Quote\Item setQty() triggers stock validation;
  • Magento\Catalog\Model\Product\Type\AbstractType checkProductBuyState() checks if product can be bought;
  • Magento\Quote\Model\Quote\Item setCustomPrice();
  • Magento\Quote\Model\Quote\Item getCalculationPrice() gets original custom price applied before tax calculation;
  • Magento\Quote\Model\Quote\Item isChildrenCalculated() checks if there children calculated or parent item when we have parent quote item and its children;
  • Magento\Quote\Model\Quote\Item isShipSeparately() checks if we can ship the product separately (each child separately) or each parent product item can be shipped only as a single item;
  • Magento\Quote\Model\Quote\Item\Compare::compare merges items and adds qty instead of a new item;
  • Magento\Quote\Model\Quote\Item representProduct() compares the quote item with some new product, checks product id and custom options;
  • Magento\Quote\Model\Quote\Item compareOptions() check if two option arrays are identical. The first option array is prerogative, the second options array is checked against the first one.

How to modify these models and effectively use them in customizations

Inventory validation

  • Use function Magento\Quote\Model\Quote\Item setQty() to declare quote item quantity.
  • Use event “sales_quote_item_qty_set_after“.
  • Use function Magento\CatalogInventory\Observer\QuantityValidatorObserver::execute.
  • Use function \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator::validate to check product inventory data when declaring quote item quantity.

Add to cart

  • Use function Magento\Checkout\Model\Cart addProduct() to add a product to the shopping cart (quote).
  • Use function Magento\Quote\Model\Quote addProduct() for advanced functionality of adding a product to quote (you can specify the processing mode there). It returns the error message if the product type instance can’t prepare the product.
  • Use function Magento\Catalog\Model\Product\Type\AbstractType prepareForCartAdvanced() to initialize product(s) for the ‘add to cart’ process. The advanced version of the function that prepares a product for cart (processMode) can be specified there.
  • Use function Magento\Quote\Model\Quote\Item\Processor::prepare to set qty and custom price for quote item.
  • Use event “checkout_cart_product_add_after“.
  • Use event “checkout_cart_save_after”, “checkout_cart_save_before“.
  • Use event “checkout_cart_add_product_complete“.

Cart update

  • Use function Magento\Checkout\Model\Cart suggestItemsQty() to return the suggested quantities for items. It can be used to automatically fix the quantities entered by the user before updating cart so that cart contains valid qty values.
  • Use function Magento\Checkout\Model\Cart updateItems() to update the information about cart items.
  • Use function Magento\Checkout\Model\Cart save() to save cart.

How to customize the process of adding a product to the cart

  • Use function Magento\Catalog\Model\Product\Type\AbstractType prepareForCartAdvanced() to prepare the product for adding to cart (i.e the “Quote” object). It is called from the Magento\Quote\Model\Quote addProduct() method.
  • The “catalog_product_type_prepare_full_options” event is launched right before the product is converted into the “Quote” element with its configured options.
  • Using the \Magento\Quote\Model\Quote\Item\Processor::prepare plugin we can change the product quantity and its custom price.
    Using the “checkout_cart_product_add_after” event we can change attribute values or product price.
  • In the catalog_attributes.xml file of the <group name=”quote_item”> group we can describe the product attributes that will fall into “quote”. For example, <attribute name=”sku”/>.

Different scenarios you should take into account

  • adding to the cart from the catalog;
  • adding to the cart from wishlist;
  • adding all the items from wishlist to the cart;
  • placing the order from the administrative / user part of the site;
  • “Reorder” from the administrative / user part of the site;
  • configuration of the added product — changing custom options;
  • combining “Quotes” when authorizing a client if he added products as a guest and already has a “Quote”.

 

How to use totals models

How can you add a custom totals model or modify existing totals models?

First of all you need to create in our module the following file app/code/Vendor/Module/etc/sales.xml. This file is used to register all available ones in Magento totals.

Here we specified the \Vendor\Module\Model\Totals\Custom class as a model of our custom total. This class must inherit \Magento\Quote\Model\Quote\Address\Total\AbstractTotal and realize collect и fetch methods. The collect method is used to calculate our total and fetch method recovers this sum as well as total’s code and its name.
Moreover, the parameter \Magento\Quote\Model\Quote\Address\Total $total allows you to affect the result of the other total classes. But depending on the task it can make more sense to use plugins to modify its values.

How to use totals models

Cart and checkout pages
To demonstrate totals we use knockout.js, so in order for our total to appear at the cart and checkout pages, we need to add new js component to checkout_cart_index.xml and checkout_index_index.xml layouts.

app/code/Vendor/Module/view/frontend/layout/checkout_index_index.xml

We also need to add the components themselves and HTML templates: app/code/Vendor/Module/view/frontend/web/js/view/checkout/cart/totals/custom_total.js

app/code/Vendor/Module/view/frontend/web/template/checkout/cart/totals/custom_total.html

app/code/Vendor/Module/view/frontend/web/js/view/checkout/summary/custom_total.js

Partner With Us Let's discuss how to grow your business. Get a Free Quote.
Talk to Igor

getValue and getPureValue methods retrieve the value of our custom total, but the getValue method formats this value adding two decimal digits and the preset currency symbol to it.

app/code/Vendor_Module/view/frontend/web/template/checkout/summary/custom_total.html

Order Emails
In order to add the reflection of a new total to the order email, you need to add a new block to the sales_email_order_items layout.

app/code/Vendor/Module/view/frontend/layout/sales_email_order_items.xml

app/code/Vendor/Module/Block/Order/CustomTotal.php

How to customize the shopping cart

How to create shopping cart rules in Magento 2

Cart rules in Magento 2 is a system used for discounts and promotion. Unlike catalog rules, cart rules are applied not to a certain product in a shopping cart, but to the whole cart itself; another difference is that a customer might need to enter a coupon code to trigger a shopping cart rule. Such discounts that are not visible to the customer and are activated if there are certain factors for obtaining them, like the number of products in the customer’s basket, their total price, product category, and many others.

Create cart rules from admin panel

Such rules are created mainly from the admin panel, but you can also create it programmatically. To create a new cart rule from the admin panel, go to Marketing -> Cart Price Rules and click “Add New Rule”.

Magento 2 cart rules creation

There you can choose the name of the rule, its correlation to store and customer groups, and set the coupon necessary for getting the discount.

Create new cart rule programmatically

To create shipping cart rule programmatically, you have to inject \Magento\SalesRule\Model\RuleFactory class:

And then use it like this:

Create conditions and actions for the rule

As an example, we will create a condition which grants the discount for a certain product if a customer added more than five of them in his cart.

Cart rule limitations and performance impact

  • One coupon per customer.
  • Rules cannot add other products to the cart.
  • Rules only apply to the item they were designated to work with.
    Cart rules can slow down the process of adding products to the cart as well as work of the shopping cart and checkout.
  • The more cart rules with a wide range of actions without reference to the website or customer group and the need to use a coupon you will add, the better the performance impact of cart rules will be.

How to add-to-cart logic in different scenarios

  • Adding from product pages:
    Controllers: \Magento\Checkout\Controller\Cart\Add
    Available events: checkout_cart_add_product_complete, checkout_cart_product_add_after, sales_quote_product_add_After, sales_quote_add_item
    Based on the added product and the amount needed cart model will generate correspoding quote item.
  • Adding from wishlist:
    Controllers: \Magento\Wishlist\Controller\Index\Cart
    Available events: checkout_cart_product_add_after, sales_quote_product_add_after, sales_quote_add_item
  • Reorder:
    Controllers: \Magento\Sales\Controller\AbstractController\Reorder
    Available events: checkout_cart_product_add_after, sales_quote_product_add_after, sales_quote_add_item
  • Quote merge:
    Method: \Magento\Quote\Model\Quote::merge
    Available events: sales_quote_add_item

Difference in behavior of different product types in the shopping cart

Magento 2 implements renderers to show products in the shopping cart. Each product type (e.g. simple, configurable, bundle) has its own renderer. They are registered in a renderer list with the help of layout instructions as child blocks of the \Magento\Framework\View\Element\RendererList block with the name “checkout.cart.item.renderers”.

Let’s take a renderer for configurable products as an example:
vendor/magento/module-configurable-product/view/frontend/layout/checkout_cart_item_renderers.xml

Where the \Magento\ConfigurableProduct\Block\Cart\Item\Renderer\Configurable class is used as a renderer and contains methods for reflecting the child product picture instead of the image of the parent product.

Custom shopping cart renderer

You will need to create block, \Vendor\Module\Block\Cart\CustomRenderer for example, which will be responsible for the html content of the product. Specify the product you need to reflect in the \Magento\Checkout\Block\Cart\AbstractCart::getItemHtml block.

Therefore, the product we need will be available in the template of our block through the $product = $block->getItem(); call.
Also, you need to register renderer in the list: app/code/Vendor/Module/view/frontend/layout/checkout_cart_item_renderers.xml

Afterwards, all the “custom-type” product types will be reflected in our class.

Available shopping cart operations

Which operations are available to the customer on the cart page?

  • Change product quantity
  • Update shopping cart (necessary after changing quantities)
  • Change product configurable/bundle options
  • Delete product
  • Transfer product to the wishlist (in enabled)
  • Add/delete coupon
  • Proceed to checkout
  • Go to multi-shipping settings (if enabled)

How would you create an extension that deletes one item if another was deleted?

You can use an observer for sales_quote_remove_item event. app/code/Vendor/Module/etc/events.xml

app/code/Vendor/Module/Observer/RemoveCartItem.php

How do you add a field to the shipping address?

To add a new field to the shipping address, you need to:
1. Add a field to the layout.
Since the shipping and billing address forms are dynamically generated, you need to do this with the help of a plugin for the \ Magento \ Checkout \ Block \ Checkout \ LayoutProcessor :: process method
2. Create a JS mixin to send additional info.
It is necessary to modify the component Magento_Checkout / js / action / set-shipping-information
3. Add new field to the address model with the help of extension attributes.

/app/code/Vendor/Module/etc/extension_attributes.xml

4. Get server-side value using the Magento \ Checkout \ Api \ Data \ ShippingInformationInterface interface’s getExtensionAttributes method.

Types of payment methods

Payment methods are divided into offline (check / money order, bank transfer) and online (paypal, braintree, authorize.net) methods.

Unlike offline methods, online methods when performing operations such as authorize, capture, refund, etc. send requests to other external payment services.

This is all to the topic of checkout process customization in Magento 2. Feel free to leave your questions and comments down below.


Partner With Us Looking for a partner that will help you to grow your business? We are the right company to develop your webstore. Feel free to get in touch with us. We will be happy to discuss your business opportunities and provide you with a Free Quote. Talk to Igor

4 Comments

  1. That was probably the best article related to checkout on the internet! Good luck for the next posts.

  2. Hi, Umar!
    It’s very pleasant to learn you have such high opinion of my article. Stay tuned for my next posts!

  3. Hi, Umar!
    Thanks for your comment and kind words, they are very motivating. Stay tuned for my next posts!

Post a new comment

top
BelVG Newsletter
Subscribe to our mailing list and get interesting stuff and updates to your email inbox.
Email *