Magento 2 Certified Professional Developer Guide
Section 8: Customizing the Checkout Process
8.1 Demonstrate ability to use quote, quote item, address, and shopping cart rules in checkout
Quote contains data for creating an order. This data is temporary and can be modified by the user. When the order is created, the user can no longer change this data in it.Magento uses Quote for the following purposes:- Store products in the cart along with their cost, quantity and options
- Store selected billing address and shipping address
- Store shipping costs
- Store subtotals of prices, additional prices (shipping costs, taxes, etc.) and coupons application to determine the total price
- Store selected payment method
- quote
- quote_address
- quote_address_item
- quote_id_mask
- quote_item
- quote_item_option
- quote_payment
- quote_shipping_rate
Rules in checkout
With Cart Price Rules, we can modify the final price at the checkout and the shipping costs. It is also possible to configure rules via the admin panel. There is a flexible set of conditions, under which the rules apply. We can add a coupon for applying the discount and indicate its percentage. Also, we can apply a discount or include free shipping to the cart that meets certain conditions. We can see all the settings in the Marketing-> Cart Price Rules-> Add New Rule section. As conditions, we can apply:- Product attribute combination
- Products subselection
- Conditions combination
- Subtotal
- Total Items Quantity
- Total Weight
- Payment Method
- Shipping Method
- Shipping Postcode
- Shipping Region
- Shipping State/Province
- Shipping Country
Interesting quote fields or methods:
If the “trigger_recollect” flag is set, the “quote” will also be updated when the price changes or the product is set to “disabled” status. The same happens if we change the rules of the CatalogRules catalog, for we can find these methods in the class Magento \ Quote \ Model \ ResourceModel markQuotesRecollectOnCatalogRules () and markQuotesRecollect ().Quote is also extendable through Magento \ Framework \ Model \ AbstractExtensibleModel, for it supports “extension_attributes”. You can register the extension through the extension_attributes.xml file:1 2 3 | <extension_attributes for="Magento\Quote\Api\Data\CartInterface"> <attribute code="shipping_assignments" type="Magento\Quote\Api\Data\ShippingAssignmentInterface[]" /> </extension_attributes> |
Quote address custom attributes:
- “CE” \Magento\Quote\Model\Quote\Address\CustomAttributeList getAttributes() return empty array. To implement it, we need to write a plugin.
- “EE” \Magento\CustomerCustomAttributes\Model\Quote\Address\CustomAttributeList::getAttributes return “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() – check if the 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 are children calculated or parent item when we have parent quote item and its children
- Magento\Quote\Model\Quote\Item isShipSeparately() – Checking if we can ship products separately (each child separately) or each parent product item can be shipped only like one item
- Magento\Quote\Model\Quote\Item\Compare::compare merges items and adds quantity instead of a new item
- Magento\Quote\Model\Quote\Item representProduct() – compares quote item with some new product, checks product id and custom options
- Magento\Quote\Model\Quote\Item compareOptions() – check if two options array are identical. First options array is prerogative, and second options array checked compared to the first one.
Describe how to modify these models and effectively use them in customizations
Inventory validation
- Use Magento\Quote\Model\Quote\Item setQty() function to declare quote item quantity
- Use event “sales_quote_item_qty_set_after”
- Use function \Magento\CatalogInventory\Model\Quote\Item\QuantityValidator::validate to check product inventory data when quote item quantity declaring.
Add to cart
- Use function Magento\Quote\Model\Quote addProduct() to add a product to the shopping cart Returns error message if product type instance can’t prepare product.
- Use function Magento\Catalog\Model\Product\Type\AbstractType prepareForCartAdvanced() to initialize product(s) to add to cart process. The advanced version of function that prepares product for cart (processMode) can be specified there.
- Use function Magento\Quote\Model\Quote\Item\Processor::prepare to set quantity and custom price for quote item
- Use event “sales_quote_product_add_after”
- Use event “sales_quote_save_after”, “sales_quote_save_before”
- Use event “checkout_cart_add_product_complete”
Cart update
- Use function \Magento\Quote\Model\Quote updateItemUpdate() quote item information
- Use event “sales_quote_save_after”, “sales_quote_save_before”
Describe how to customize the process of adding a product to the cart
- Applying a plugin to the Magento\Catalog\Model\Product\Type\AbstractType prepareForCartAdvanced() method. This function is used to prepare the product for adding to the cart (that is, the “Quote” object) and is called from the Magento \ Quote \ Model \ Quote addProduct () method.
- Applying a plugin to the Magento\Quote\Model\Quote::addProduct method
- Applying a plugin to the Magento\Quote\Model\Quote::addItem method
- With the help of “catalog_product_type_prepare_full_options” event at the condition of full validation, or “catalog_product_type_prepare_lite_options” at the condition of partial validation, the event is launched right before the product with configurable options is configured into “Quote” element.
- Applying a plugin to the \Magento\Quote\Model\Quote\Item\Processor::prepare method, we can modify the number of products and their custom prices.
- With the help of “sales_quote_product_add_after” event, we can modify attribute values or product price.
- Using the “sales_quote_add_item” event.
- In the catalog_attributes.xml file in
group, we describe the product attributes that get into “quote”; for example, .
Which different scenarios should you take into account?
- Adding into the shopping cart from the catalog
- Adding into the shopping cart from the wishlist
- Adding all items from the wishlist into the shopping cart
- Create an order from the admin / user part of the website
- “Reorder” from the admin / user part of the website
- Configuration of the added product is modification of custom options
- “Quotes” merge at the client authorization in case he or she added products as a guest and already have a “Quote”
8.2 Demonstrate ability to use totals models
Describe how to modify the price calculation process in the shopping cart. How can you add a custom totals model or modify existing totals models?
Custom totals can be used to add an additional tax or discount in Magento Checkout or modify the existing ones.First, we need to create the1 2 3 4 5 6 7 8 | xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd"> <section name="quote"> <group name="totals"> <item name="custom_total" instance="Vendor\Module\Model\Totals\Custom" sort_order="500"/> </group> </section> </config> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | <?php Namespace Vendor\Module\Model\Total; class Custom extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal { /** * Custom constructor. */ public function __construct() { $this->setCode('custom_total'); } /** * @param \Magento\Quote\Model\Quote $quote * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment * @param \Magento\Quote\Model\Quote\Address\Total $total * @return $this */ public function collect( \Magento\Quote\Model\Quote $quote, \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment, \Magento\Quote\Model\Quote\Address\Total $total ) { parent::collect($quote, $shippingAssignment, $total); $items = $shippingAssignment->getItems(); if (!count($items)) { return $this; } //we will add an additional amount of 150 to the order as an example $amount = 150; $total->setTotalAmount('custom_total', $amount); $total->setBaseTotalAmount('custom_total', $amount); $total->setCustomAmount($amount); $total->setBaseCustomAmount($amount); $total->setGrandTotal($total->getGrandTotal() + $amount); $total->setBaseGrandTotal($total->getBaseGrandTotal() + $amount); return $this; } /** * @param \Magento\Quote\Model\Quote\Address\Total $total */ protected function clearValues(\Magento\Quote\Model\Quote\Address\Total $total) { $total->setTotalAmount('subtotal', 0); $total->setBaseTotalAmount('subtotal', 0); $total->setTotalAmount('tax', 0); $total->setBaseTotalAmount('tax', 0); $total->setTotalAmount('discount_tax_compensation', 0); $total->setBaseTotalAmount('discount_tax_compensation', 0); $total->setTotalAmount('shipping_discount_tax_compensation', 0); $total->setBaseTotalAmount('shipping_discount_tax_compensation', 0); $total->setSubtotalInclTax(0); $total->setBaseSubtotalInclTax(0); } /** * @param \Magento\Quote\Model\Quote $quote * @param \Magento\Quote\Model\Quote\Address\Total $total * @return array */ public function fetch( \Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total ) { return [ 'code' => $this->getCode(), 'title' => 'Custom Total’, 'value' => 150 ]; } /** * @return \Magento\Framework\Phrase */ public function getLabel() { return __('Custom Total’); } } |
Displaying Custom Total
Cart and checkout pages
We use knockout.js to display our totals. Therefore, to make our total appear at the cart and checkout pages, we need to add a new JS component into checkout_cart_index.xml and checkout_index_index.xml layouts.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="checkout.cart.totals"> <arguments> <argument name="jsLayout" xsi:type="array"> <item name="components" xsi:type="array"> <item name="block-totals" xsi:type="array"> <item name="children" xsi:type="array"> <item name="custom_total" xsi:type="array"> <item name="component" xsi:type="string">Vendor_Module/js/view/checkout/cart/totals/custom_total</item> <item name="sortOrder" xsi:type="string">20</item> <item name="config" xsi:type="array"> <item name="template" xsi:type="string">Vendor_Module/checkout/cart/totals/custom_total</item> <item name="title" xsi:type="string">Custom Total</item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceBlock name="checkout.root"> <arguments> <argument name="jsLayout" xsi:type="array"> <item name="components" xsi:type="array"> <item name="checkout" xsi:type="array"> <item name="children" xsi:type="array"> <item name="sidebar" xsi:type="array"> <item name="children" xsi:type="array"> <item name="summary" xsi:type="array"> <item name="children" xsi:type="array"> <item name="totals" xsi:type="array"> <item name="children" xsi:type="array"> <item name="custom_total" xsi:type="array"> <item name="component" xsi:type="string">Vendor_Module/js/view/checkout/cart/totals/custom_total</item> <item name="sortOrder" xsi:type="string">20</item> <item name="config" xsi:type="array"> <item name="template" xsi:type="string">Vendor_Module/checkout/cart/totals/custom_total</item> <item name="title" xsi:type="string">Custom Total</item> </item> </item> </item> </item> <item name="cart_items" xsi:type="array"> <item name="children" xsi:type="array"> <item name="details" xsi:type="array"> <item name="children" xsi:type="array"> <item name="subtotal" xsi:type="array"> <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/item/details/subtotal</item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | define( [ 'Vendor_Module/js/view/checkout/summary/custom_total' ], function (Component) { 'use strict'; return Component.extend({ /** * @override */ isDisplayed: function () { return this.getPureValue() !== 0; } }); } ); |
Copyright BelVG