0

I have added a custom product attribute via code, using InstallData.php

public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        $eavSetup->addAttribute(
            \Magento\Catalog\Model\Product::ENTITY,
            'hts_code',
            [
                'type' => 'text',
                'backend' => '',
                'frontend' => '',
                'label' => 'HTS Code',
                'input' => 'text',
                'class' => '',
                'source' => '',
                'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
                'visible' => true,
                'required' => false,
                'user_defined' => false,
                'default' => '',
                'searchable' => false,
                'filterable' => false,
                'comparable' => false,
                'visible_on_front' => false,
                'used_in_product_listing' => true,
                'unique' => false,
                'apply_to' => ''
            ]
        );
    }

This attribute shows in the product details page and can be set no issue. It appears in the API when fetching the product.

However, I need to add this attribute to the Order API response (http://store.test/index.php/rest/V1/orders/) but cannot figure this out at all.

I have looked up multiple examples but none of the implementations work.

So how do I go about adding this custom attribute to the Order API response, and ideally, I need to add it to the shipping_assignments.items section of the Order extension attributes

1

1 Answer 1

0

A good example in Magento core code of setting extension attributes can be found in the Magento_GiftMessage module. The file vendor/magento/module-gift-message/Model/Plugin/OrderGet.php details how to add an extension attribute to the order level and the order item level.

We can modify this to add your attribute to the shipment item level.

Add your new plugin to your custom module Vendor/Module/etc/di.xml

<type name="Magento\Sales\Api\OrderRepositoryInterface">
    <plugin name="vendor_module_order_extension_text_attribute"
            type="Vendor\Module\Plugin\AddTextAttributeToShipmentItem" />
</type>

Your custom module 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\Sales\Api\Data\OrderItemInterface">
    <attribute code="text_attribute" type="string" />
</extension_attributes>
<extension_attributes for="Magento\Sales\Api\Data\ShipmentItemInterface">
    <attribute code="text_attribute" type="string" />
</extension_attributes>

Your new plugin code Vendor/Module/Plugin/AddTextAttributeToShipmentItem.php

<?php

declare(strict_types=1);

namespace Vendor\Module\Plugin;

use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Api\Data\ShipmentExtensionFactory;
use Magento\Sales\Api\Data\ShipmentItemExtensionFactory;
use Magento\Framework\Exception\NoSuchEntityException;

class AddTextAttributeToShipmentItem
{
  /**
   * @var ShipmentExtensionFactory
   */
   protected $shipmentExtensionFactory;

  /**
   * @var ShipmentItemExtensionFactory
   */
   private $shipmentItemExtensionFactory;

  /**
   * @param \Magento\Sales\Api\Data\ShipmentExtensionFactory $shipmentExtensionFactory
   * @param \Magento\Sales\Api\Data\ShipmentItemExtensionFactory $shipmentItemExtensionFactory
   */
   public function __construct(
        ShipmentExtensionFactory $shipmentExtensionFactory,
        ShipmentItemExtensionFactory $shipmentItemExtensionFactory
    ) {
        $this->shipmentExtensionFactory = $shipmentExtensionFactory;
        $this->shipmentItemExtensionFactory = $shipmentItemExtensionFactory;
    }

   /**
    * @param \Magento\Sales\Api\OrderRepositoryInterface $subject
    * @param \Magento\Sales\Api\Data\OrderInterface $resultOrder
    * @return \Magento\Sales\Api\Data\OrderInterface
    */
    public function afterGet(
        \Magento\Sales\Api\OrderRepositoryInterface $subject,
        \Magento\Sales\Api\Data\OrderInterface $resultOrder  
    ) {
        $resultOrder = $this->getShipmentItemTextAttribute($resultOrder);

        return $resultOrder;
    }

    /**
     * Add Shipment item level text attribute data
     * @param \Magento\Sales\Api\Data\OrderInterface $order
     * @return \Magento\Sales\Api\Data\OrderInterface
     */
    protected function getShipmentItemTextAttribute(\Magento\Sales\Api\Data\OrderInterface $order)
    {
        $shippingAssignments = $order->getExtensionAttributes()->getShippingAssignments();
        /** Since it is possible for more than one shipment to be created per order
         * we need to check for all possible shipments that may exist */
        foreach ($shippingAssignments as $shippingAssignment) {
            $orderShipmentItems = $shippingAssignment->getItems();

            foreach ($orderShipmentItems as $orderShipmentItem) {
                  $extensionAttributes = $orderShipmentItem->getExtensionAttributes();
                /** getTextAttribute here is checking if your extension_attributes text_attribute exists */
                if ($extensionAttributes && $extensionAttributes->getTextAttribute()) {
                    continue;
                }

                try {
                  /** @var \Magento\Catalog\Model\Product $product */
                    $product = $orderShipmentItem->getProduct();
                    /** Since product could have been deleted by admin since
                     * order has been placed we need to check it still exists */
                    if ($product) {
                        $textAttribute = $product->getData('hts_code')
                        ? (string) $product->getData('hts_code')
                        : 'N/A';
                    } else {
                        $textAttribute = (string) 'N/A';
                    }
                } catch (NoSuchEntityException $e) {
                    continue;
                }

          /** @var \Magento\Sales\Api\Data\ShipmentItemExtension $shipmentItemExtension */
                $shipmentItemExtension = $extensionAttributes
                ? $extensionAttributes
                : $this->shipmentItemExtensionFactory->create();
                $shipmentItemExtension->setTextAttribute($textAttribute);
                $orderShipmentItem->setExtensionAttributes($shipmentItemExtension);
            }
        }
        return $order;
    }

    /**
     * @param \Magento\Sales\Api\OrderRepositoryInterface $subject
     * @param \Magento\Sales\Model\ResourceModel\Order\Collection $resultOrder
     * @return \Magento\Sales\Model\ResourceModel\Order\Collection
     */
    public function afterGetList(
        \Magento\Sales\Api\OrderRepositoryInterface $subject,
        \Magento\Sales\Model\ResourceModel\Order\Collection $resultOrder
    ) {
        /** @var  $order */
        foreach ($resultOrder->getItems() as $order) {
            $this->afterGet($subject, $order);
        }
        return $resultOrder;
    }
}

After recompiling you should now see your custom attribute in the shipment items level of your orders API response.

  "items": [
                {
                    "amount_refunded": 0,
                    "applied_rule_ids": "5",
                    "base_amount_refunded": 0,
                    "base_discount_amount": 2.4,
                    "base_discount_invoiced": 0,
                    "base_discount_tax_compensation_amount": 0.22,
                    "base_original_price": 12,
                    "base_price": 10.91,
                    "base_price_incl_tax": 12,
                    "base_row_invoiced": 0,
                    "base_row_total": 10.91,
                    "base_row_total_incl_tax": 12,
                    "base_tax_amount": 0.87,
                    "base_tax_invoiced": 0,
                    "created_at": "2021-03-28 02:24:31",
                    "discount_amount": 2.4,
                    "discount_invoiced": 0,
                    "discount_percent": 20,
                    "free_shipping": 0,
                    "discount_tax_compensation_amount": 0.22,
                    "is_qty_decimal": 0,
                    "is_virtual": 0,
                    "item_id": 322,
                    "name": "2die4 Holy Cacao Granola Clusters 200g",
                    "no_discount": 0,
                    "order_id": 99,
                    "original_price": 12,
                    "price": 10.91,
                    "price_incl_tax": 12,
                    "product_id": 172,
                    "product_type": "simple",
                    "qty_canceled": 0,
                    "qty_invoiced": 0,
                    "qty_ordered": 1,
                    "qty_refunded": 0,
                    "qty_shipped": 0,
                    "quote_item_id": 1418,
                    "row_invoiced": 0,
                    "row_total": 10.91,
                    "row_total_incl_tax": 12,
                    "row_weight": 0.2,
                    "sku": "611-1101",
                    "store_id": 1,
                    "tax_amount": 0.87,
                    "tax_invoiced": 0,
                    "tax_percent": 10,
                    "updated_at": "2021-03-28 02:24:31",
                    "weight": 0.2,
                    "extension_attributes": {
                        "text_attribute": "93100015453663"
                    }
                },
                {
                    "amount_refunded": 0,
                    "applied_rule_ids": "5",
                    "base_amount_refunded": 0,
                    "base_discount_amount": 3.3,
                    "base_discount_invoiced": 0,
                    "base_discount_tax_compensation_amount": 0.3,
                    "base_original_price": 16.5,
                    "base_price": 15,
                    "base_price_incl_tax": 16.5,
                    "base_row_invoiced": 0,
                    "base_row_total": 15,
                    "base_row_total_incl_tax": 16.5,
                    "base_tax_amount": 1.2,
                    "base_tax_invoiced": 0,
                    "created_at": "2021-03-28 02:24:31",
                    "discount_amount": 3.3,
                    "discount_invoiced": 0,
                    "discount_percent": 20,
                    "free_shipping": 0,
                    "discount_tax_compensation_amount": 0.3,
                    "is_qty_decimal": 0,
                    "is_virtual": 0,
                    "item_id": 323,
                    "name": "2die4 Organic Activated Muesli Traditional 300g",
                    "no_discount": 0,
                    "order_id": 99,
                    "original_price": 16.5,
                    "price": 15,
                    "price_incl_tax": 16.5,
                    "product_id": 173,
                    "product_type": "simple",
                    "qty_canceled": 0,
                    "qty_invoiced": 0,
                    "qty_ordered": 1,
                    "qty_refunded": 0,
                    "qty_shipped": 0,
                    "quote_item_id": 1419,
                    "row_invoiced": 0,
                    "row_total": 15,
                    "row_total_incl_tax": 16.5,
                    "row_weight": 0.3,
                    "sku": "611-1102",
                    "store_id": 1,
                    "tax_amount": 1.2,
                    "tax_invoiced": 0,
                    "tax_percent": 10,
                    "updated_at": "2021-03-28 02:24:31",
                    "weight": 0.3,
                    "extension_attributes": {
                        "text_attribute": "N/A"
                    }
                }
            ]
        }
    ]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.