Magento – Extension attributes to add product attribute to the order summary on checkout

extension-attributesmagento2

I am trying to display a custom product attribute under the order summary list of items on checkout. I think it is fed by the TotalsItemExtensionInterface. I have the following trying to add the custom attribute to the collection exposed on the front end.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
<extension_attributes for="Magento\Quote\Api\Data\TotalsItemExtensionInterface">
    <attribute code="product" type="string">
        <join reference_table="catalog_product" reference_field="product_id" join_on_field="entity_id">
            <field>custom_attribute</field>
        </join>
    </attribute>
</extension_attributes>
</config>

Any ideas on how this is done to attach a product attribute to a quote item in Magento 2?

EDIT: Attached is the screenshot of where I would like to get the attribute to show:
enter image description here

Also I am taking a different route, but have the same problem. I brought the attribute to the quote item through a migration so is now part of the quote_item table. But not part of the collection coming through. Any idea on how I get that attribute as part of the quoteItem object?

Best Answer

1) The flow of cart summary in checkout page

We can get the totalsData from:

vendor/magento/module-checkout/view/frontend/web/js/model/quote.js

var totalsData = window.checkoutConfig.totalsData;

return {
    totals: totals,
    ......
}

If we try to format the Json from window.checkoutConfig, we can see the totalsData. And, we can get the items from it.

enter image description here

Now, at look the checkout xml layout:

vendor/magento/module-checkout/view/frontend/layout/checkout_index_index.xml

<item name="cart_items" xsi:type="array">
    <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/cart-items</item>
    <item name="children" xsi:type="array">
        <item name="details" xsi:type="array">
            <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details</item>
            <item name="children" xsi:type="array">
                <item name="thumbnail" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/thumbnail</item>
                    <item name="displayArea" xsi:type="string">before_details</item>
                </item>
                <item name="subtotal" xsi:type="array">
                    <item name="component" xsi:type="string">Magento_Checkout/js/view/summary/item/details/subtotal</item>
                    <item name="displayArea" xsi:type="string">after_details</item>
                </item>
            </item>
        </item>

    </item>
</item>

In the front page:

enter image description here

2) Add custom attribute

Where is the totalsData from the PHP side?

vendor/magento/module-checkout/Model/DefaultConfigProvider.php

public function getConfig()
{ 
    ......
    $output['postCodes'] = $this->postCodesConfig->getPostCodes();
    $output['imageData'] = $this->imageProvider->getImages($quoteId);
    $output['totalsData'] = $this->getTotalsData();
    ......
}

So, we need to override this method, I think we should use Plugin to override this method.

Vendor\Module\etc\di.xml

<type name="Magento\Checkout\Model\DefaultConfigProvider">
        <plugin name="add_custom_product_attribute" type="Vendor\Module\Model\Checkout\ConfigProviderPlugin" />
</type>

Vendor\Module\Model\Checkout\ConfigProviderPlugin.php

public function afterGetConfig(\Magento\Checkout\Model\DefaultConfigProvider $subject, array $result)
{
    $items = $result['totalsData']['items'];
    foreach($items as $item) {
        //Your code here
    }

    return $result;
}

And then, we need to create your own js and html template files or override the exist files.

[EDIT]

We should try with:

The proper way is to use TotalsItemExtensionInterface and add all these via it

Create extension attributes:

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

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\TotalsItemExtensionInterface">
        <attribute code="reward_points" type="int" />
    </extension_attributes>
</config>

app/code/Vendor/Module/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">
    <type name="Magento\Quote\Model\Cart\Totals\ItemConverter">
        <plugin name="show-points-item" type="Vendor\Module\Plugin\Cart\Totals\ItemConverterPlugin" sortOrder="10"/>
    </type>
</config>

app/code/Vendor/Module/Plugin/Cart/Totals/ItemConverterPlugin.php

<?php

namespace Vendor\Module\Plugin\Cart\Totals;

use Magento\Quote\Model\Cart\Totals\ItemConverter;
use Magento\Quote\Api\Data\TotalsItemExtensionFactory;

class ItemConverterPlugin
{
    /**
     * @var TotalsItemExtensionFactory
     */
    protected $totalsItemExtensionFactory;

    /**
     * ItemConverterPlugin constructor.
     *
     * @param TotalsItemExtensionFactory $totalsItemExtensionFactory
     */
    public function __construct(
        TotalsItemExtensionFactory $totalsItemExtensionFactory
    ) {
        $this->totalsItemExtensionFactory = $totalsItemExtensionFactory;
    }

    /**
     * @param ItemConverter $subject
     *
     * @param $result
     * @return mixed
     */
    public function afterModelToDataObject(
        ItemConverter $subject,
        $result
    ) {
        $extensionAttributes = $result->getExtensionAttributes();
        if ($extensionAttributes === null) {
            $extensionAttributes = $this->totalsItemExtensionFactory->create();
        }
        $pointsDelta = 24;
        $extensionAttributes->setRewardPoints($pointsDelta);
        $result->setExtensionAttributes($extensionAttributes);
        return $result;
    }
}

On the checkout page, we can check on Browser console: window.checkoutConfig.totalsData.items

enter image description here