-
Notifications
You must be signed in to change notification settings - Fork 248
SourceItem Entity Extension
- Overview
- Request for SourceItem Extension
- SourceItem entity representation
- Recommendation how to extend SourceItem entity
- Adding new Data interface representing Allocated Space
- Existing usages of Extension Attributes
This document describes general recommendations on how entities introduced in the scope of Magento MSI (Source, Stock, SourceItem, StockSourceLink etc.) could be extended with additional attributes via an example of the SourceItem entity representing a particular amount of Products in dedicated Source (warehouse).
Hi Igor. We had a meeting with your regarding MSI not long time ago. I have one general question In case we need to add some additional attributes to source items i.e. expected_date, item_location(aisle/shelve), etc What is preferable approach from your point of view:
- Add this columns to inventory_source_item table and extend existing interfaces
- Create new table inventory_source_item_attributes and create new interfaces that will work with that newly created entity
and also what will be preferable approach of import/export:
- separate CSV
- add new attributes into existing CSV for source items
First of all, let's look at the declaration of SourceItemInterface:
namespace Magento\InventoryApi\Api\Data;
use Magento\Framework\Api\ExtensibleDataInterface;
/**
* Represents amount of product on physical storage
* Entity id getter is missed because entity identifies by compound identifier (sku and source_code)
*
* Used fully qualified namespaces in annotations for proper work of WebApi request parser
*
* @api
*/
interface SourceItemInterface extends ExtensibleDataInterface
{
/**#@+
* Constants for keys of data array. Identical to the name of the getter in snake case
*/
const SKU = 'sku';
const SOURCE_CODE = 'source_code';
const QUANTITY = 'quantity';
const STATUS = 'status';
/**#@-*/
/**#@+
* Source items status values
*/
const STATUS_OUT_OF_STOCK = 0;
const STATUS_IN_STOCK = 1;
/**#@-*/
/**
* Get source item sku
*
* @return string|null
*/
public function getSku();
/**
* Set source item sku
*
* @param string|null $sku
* @return void
*/
public function setSku($sku);
/**
* Get source code
*
* @return string|null
*/
public function getSourceCode();
/**
* Set source code
*
* @param string|null $sourceCode
* @return void
*/
public function setSourceCode($sourceCode);
/**
* Get source item quantity
*
* @return float|null
*/
public function getQuantity();
/**
* Set source item quantity
*
* @param float|null $quantity
* @return void
*/
public function setQuantity($quantity);
/**
* Get source item status (One of self::STATUS_*)
*
* @return int|null
*/
public function getStatus();
/**
* Set source item status (One of self::STATUS_*)
*
* @param int|null $status
* @return int
*/
public function setStatus($status);
/**
* Retrieve existing extension attributes object
*
* Null for return is specified for proper work SOAP requests parser
*
* @return \Magento\InventoryApi\Api\Data\SourceItemExtensionInterface|null
*/
public function getExtensionAttributes();
/**
* Set an extension attributes object
*
* @param \Magento\InventoryApi\Api\Data\SourceItemExtensionInterface $extensionAttributes
* @return void
*/
public function setExtensionAttributes(SourceItemExtensionInterface $extensionAttributes);
}
Here are attributes description:
- SKU - represents product SKU
- SourceCode - the reference to Source where the product located
- Quantify - the number of products located on particular Source
- Status - status per Source (In Stock / Out of Stock) describing whether we can fulfill orders from this Source.
- getExtensionAttributes/setExtensionAttributes - methods preserved for extension Data Interface with custom attributes
Here is I recommend you to keep a general recommendation for extending Magento entities:
- From the code standpoint - to use Extension attributes, as \Magento\InventoryApi\Api\Data\SourceItemInterface provides two methods for these purposes
/**
* Retrieve existing extension attributes object
*
* Null for return is specified for proper work SOAP requests parser
*
* @return \Magento\InventoryApi\Api\Data\SourceItemExtensionInterface|null
*/
public function getExtensionAttributes();
/**
* Set an extension attributes object
*
* @param \Magento\InventoryApi\Api\Data\SourceItemExtensionInterface $extensionAttributes
* @return void
*/
public function setExtensionAttributes(SourceItemExtensionInterface $extensionAttributes);
- From DB standpoint - to introduce own table to store these fields. Usage of own table would help you to prevent possible backward incompatibilities in future. As in Magento 2.3 we are introducing Declarative schema for Magento entities. Thus, a way how DB table structure declared could be changed soon. Also, in general, Magento considers DB table structure as a private implementation which potentially could be changed in future. That's why Magento introduces additional abstraction layer on top of Data Schema creation.
Not sure whether you need to introduce a dedicated Data Interface for your needs.
You may need it if you are really introducing the Interface which represents an entity from your business domain.
Like The Space
in your warehouse and you would like to provide an ability of space management (which is currently absent in MSI and may be added in future releases).
Thus, you would like to specify particular place(-s) where products are located within the warehouse.
And either you would like to introduce date of arrival and date of shipment as you know that some products will arrive soon and need some space to be allocated, but have not been delivered yet.
On the other hand - some product already sold, but not yet shipped from the warehouse.
For these purposes - you can introduce own Data Interface and some services which will provide you manipulation over these data.
But if you just want to add an attribute which makes sense only in the scope of SourceItem entity - it’s better to inject one into the SourceItemInterface via ExtensionAttributes.
and also what will be preferable approach of import/export:
The same recommendation is applicable for import/export: if you consider that you are introducing new Entity - it’s better to introduce the independent Import/Export process for it. If it’s part of SourceItem - just extend existing Import/Export of SourceItems
For example, according to business requirements merchant wants to manage the allocated space on each Source. What he can do is to introduce dedicated Entity responsible for this - SourceItemPlaceAllocation
interface SourceItemPlaceAllocation
{
/**
* Get Source Code
*
* @return string
*/
public function getSourceCode();
/**
* Set Source Code
*
* @param string $sourceCode
* @return void
*/
public function setSourceCode(string $sourceCode);
/**
* Get SKU
*
* @return string
*/
public function getSku();
/**
* Set Sku
*
* @param string $sku
* @return void
*/
public function setSku(string $sku);
/**
* Get date of arrival
*
* @return string
*/
public function getDateOfArrival();
/**
* Get date of arrival
*
* @param string $date
* @return void
*/
public function setDateOfArrival(string $date);
/**
* Get date of shipment
*
* @return string
*/
public function getDateOfShipment();
/**
* Get date of shipment
*
* @param string $date
* @return void
*/
public function setDateOfShipment(string $date);
/**
* Get Source Item location within Source
*
* @return string
*/
public function getLocationWithinSource();
/**
* Set Source Item location within Source
*
* @param string $location
* @return void
*/
public function setLocationWithinSource(string $location);
/**
* Amount of Place Occupied by these SourceItems
*
* @return float
*/
public function getOccupiedSpace();
/**
* Set Amount of Place Occupied by these SourceItems
*
* @param string $occupiedSpace
* @return void
*/
public function setOccupiedSpace(float $occupiedSpace);
}
And Service which will retrieve current entity.
interface GetAllocatedPlaceBySourceItem
{
public function execute(string $sku, string $sourceCode) : SourceItemPlaceAllocation;
}
There, of course, could be other services introduced. For example, to calculate all occupied space per Source for specified Date, but the main idea is that extension developer is introducing own entities (stored in a dedicated table or even Data Storage) and manage linkage to existing SourceItem.
Existing examples of Extension Attributes usages could be either found in Magento MSI codebase.
For example, InventorySales module introduces Extension Attribute sales_channels
injecting it to Stock entity. Doing this injection we introduce a linkage between Sales Channel (Magento Website) and Particulat Stock.
This is how the declaration looks like: Magento/InventorySales/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\InventoryApi\Api\Data\StockInterface">
<attribute code="sales_channels" type="Magento\InventorySalesApi\Api\Data\SalesChannelInterface[]" />
</extension_attributes>
</config>
Retrieval and persistence of this attribute implemented via 2 plugins:
Multi-Source Inventory developed by Magento 2 Community
- Technical Vision. Catalog Inventory
- Installation Guide
- List of Inventory APIs and their legacy analogs
- MSI Roadmap
- Known Issues in Order Lifecycle
- MSI User Guide
- 2.3 LIVE User Guide
- MSI Release Notes and Installation
- Overview
- Get Started with MSI
- MSI features and processes
- Global and Product Settings
- Configure Source Selection Algorithm
- Create Sources
- Create Stock
- Assign Inventory and Product Notifications
- Configure MSI backorders
- MSI Import and Export Product Data
- Mass Action Tool
- Shipment and Order Management
- CLI reference
- Reports and MSI
- MSI FAQs
- DevDocs Documentation
- Manage Inventory Management Modules (install/upgrade info)
- Inventory Management
- Reservations
- Inventory CLI reference
- Inventory API reference
- Inventory In-Store Pickup API reference
- Order Processing with Inventory Management
- Managing sources
- Managing stocks
- Link and unlink stocks and sources
- Manage source items
- Perform bulk actions
- Manage Low-Quantity Notifications
- Check salable quantities
- Manage source selection algorithms
- User Stories
- Support of Store Pickup for MSI
- Product list assignment per Source
- Source assignment per Product
- Stocks to Sales Channel Mapping
- Adapt Product Import/Export to support multi Sourcing
- Introduce SourceCode attribute for Source and SourceItem entities
- Assign Source Selector for Processing of Returns Credit Memo
- User Scenarios:
- Technical Designs:
- Module Structure in MSI
- When should an interface go into the Model directory and when should it go in the Api directory?
- Source and Stock Item configuration Design and DB structure
- Stock and Source Configuration design
- Open Technical Questions
- Inconsistent saving of Stock Data
- Source API
- Source WebAPI
- Sources to Sales Channels mapping
- Service Contracts MSI
- Salable Quantity Calculation and Mechanism of Reservations
- StockItem indexation
- Web API and How To cover them with Functional Testing
- Source Selection Algorithms
- Validation of Domain Entities
- PHP 7 Syntax usage for Magento contribution
- The first step towards pre generated IDs. And how this will improve your Integration tests
- The Concept of Default Source and Domain Driven Design
- Extension Point of Product Import/Export
- Source Selection Algorithm
- SourceItem Entity Extension
- Design Document for changing SerializerInterface
- Stock Management for Order Cancelation
- Admin UI
- MFTF Extension Tests
- Weekly MSI Demos
- Tutorials