6

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?

Khoa TruongDinh
  • 32,054
  • 11
  • 88
  • 155
sudopratt
  • 331
  • 1
  • 4
  • 11

1 Answers1

12

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

Khoa TruongDinh
  • 32,054
  • 11
  • 88
  • 155
  • 2
    How could one add the specific product url to the item-array? This would clarify your already great question even more! – Max Oct 19 '16 at 10:34
  • Hello Khoa, as per your answer i have added short description into window.checkoutConfig.totalsdata and window.checkoutConfig.quoteItemData as well. when we reach checkout page the short description is coming, but when we move to payment or come back to shipping tab it dissapears. any idea ? – Sunil Verma Nov 21 '16 at 12:27
  • 1
    it will work until totals are recalculated on shipping method change etc. The proper way is to use TotalsItemExtensionInterface and add all these via it – c0rewell Jan 24 '17 at 09:21
  • @c0rewell I see, I need to test more. – Khoa TruongDinh Jan 24 '17 at 09:44
  • @Sunil Verma Can you please help me? I need to get the product attribute. – Sejal Shah Jun 09 '17 at 12:23
  • I have just updated my answer with using extension attributes. – Khoa TruongDinh Jul 24 '17 at 01:39
  • good explaination : – Amit Bera Jan 24 '18 at 08:26
  • why is it not auto populated from quote_item custom attribute? – Yohanes Pradono Oct 01 '18 at 18:08
  • I tried to use your example and get an error PHP Fatal error: Uncaught Error: Call to undefined method Magento\Quote\Api\Data\TotalsItemExtension::setRewardPoints()

    Magento CLI version 2.2.7

    – Nikolai Silin Mar 14 '19 at 14:24
  • @NikolaiSilin I had same error and solved it by using $extensionAttributes->setData('reward_points', $pointsDelta); instead. – grll Sep 26 '19 at 10:08