Design within Inventory
Proposed Design
Objective
Define minimum concepts and API endpoints for handling the inventorying of medical commodity stock. Addresses issues related to products (v2 and Logical Model) and trade items (GS1), base unit within inventory, changing stock on hand, lots and stocking meta-data.
API Design
RAML: product-inventory.yaml
Logistics Locations
A logistics location is one where stock is held in inventory in OpenLMIS. In this way a logistics location "owns" stock that is in its inventory.
Logistics Location terminology in this design is sourced from the Logical Model*. Incorporating this concept of a location, with what we know so far about GS1 locations (GLN) as well as some of the challenges with Facility in OpenLMIS v2, an abstract concept of an independent logistics location appears useful. It's not expected that end users would need to interact with them directly.
Global Products and Trade Items
A Global Product is a USAID model for usage of various produced products. A Trade Item is a GS1 model for describing produced items. A couple examples:
- An 8oz coffee mug holds 8oz of hot liquid and would be a Global Product description. A Starbucks branded 8oz coffee mug is a Trade Item.
- A bottle of pills of Ibuprofen 500mg would be a Global Product. A bottle of 50 pills, 500mg, of Advil is a Trade Item.
Global Product's in the logical model have provisions on how one Global Product may be substituted for another. This complexity is useful to understand, but at the point of Inventory all we need to know is the basic relationship between Global Product's and Trade Items, and that Global Product's have more advanced substitution models.
A critical component of this relationship between a Global Product and a Trade Item (known also as a Supplier Catalog Item in the Logical Model) is that the primary package of each within their association may be different (see orders), however the dispensing units must be fully fungible within the context of inventory. e.g. 1 pill of Ibuprofen 500mg must be fungible with 1 pill of Advil 500mg within the context of Inventory.
Updating stock in Inventory
Updating stock in Inventory has been written about in more depth. Updating the singular Product model in v1 and v2 with Global Product's and Trade Item's introduce some variation in understanding what stock is being updated. While Global Products and Trade Items ideally are associated, the accounting of what's in stock while allowing flexible options for accounting for stock at different levels of detail lead to treating updates to Global Products and Trade Items on hand separately. Stock events that are published should therefore specify if it's a change in stock in inventory of a Global Product or a Trade Item separately.
What stock is in Inventory
To discover what stock is in inventory the calls to the API are again separated by Global Product and Trade Item. However querying for Global Product's in inventory where there are Trade Item's in inventory that also have an association with a Global Product would return inventory details about those Trade Items. Again it's important to understand that any quantities represented are in dispensing units. This gives a consistent atomic unit, and allows processes to build up from this based on a desired inventorying policy (e.g. at the secondary packaging level at regional wharehouses).
An example of query a logistics location (X) about a Global Product (Y) in Inventory
/logisticsLocations/X/globalProducts/Y
200 body:
{ UUID: Y balance: { onHand: 12 available: 10 } tradeItems: [ { ... } ] }
Here, balance refers to the Global Product's that are in inventory and tradeItems is a list of Trade Items in inventory, and these are separate. Balance doesn't give a total balance of the Global Product and all it's associated Trade Items in inventory. This allows at the API level for a client to understand inventory in light of Global Product-Trade Item associations, however it doesn't mandate that one representation of a product/item is used in accounting for stock.
An example of a logistics location (X) with a Trade Item (Z) in inventory
/logisticsLocations/X/tradeItems/Z
200 body:
{ UUID: Z balance: { onHand: 12 available: 10 } lots: [ { UUID: ... ... balance: {...} } ] }
Here we see that the Trade Item Z, like the Global Product Y, has a balance. And like in Global Product, this balance represents Trade Item's that have been placed in inventory sans lot information. If we are updating trade item inventory by lot, then a breakdown of that inventory is in the lots list.
What about Programs?
Programs separate out most if not all stock processes within OpenLMIS. It's therefore suspicious that Programs are absent above. This absence is intentional as we've heard various requests to both inventory stock by program as well as to not inventory by program. The decision of weather inventory is by program or not, seems to be a policy decision at the logistics location in question. This could be addressed in a couple different ways: directly within inventory, or indirectly through processes that adjust stock (e.g. fulfillment, receiving stock, push, etc). The former option seems more alike to stock bins separated by program, whereas the latter seems more alike to an accounting method of tracking stock.
What about other stock tracking metadata?
We've seen in previous projects the desire to track additional meta-data for stock in inventory. Examples include expiration date (free of lot information) and VVM (vaccines). For this additional meta-data desire, there should be a simple litmus test for when the model should be extended to track by <some metadata>. Information such as VVM isn't static, it can change while sitting in a bin. Additionally an expiration date that's collected outside the context of a manufacturer's lot has so far been done more informatively than as a declaration of the contents of a bin. Examples include collecting the earliest-expiration date of items in a bin (requisition screen, epi-inventory screen), or as an un-attched list of expiration dates (CHAI Mozambique dispensing application).
The above models used this implied litmus test during design: is the meta-data declarative of the contents of an entire bin? If not then the meta-data isn't used to account for stock - meaning that you couldn't effect a stock balance of items with VVM status 2, you could only inform the system that a given trade item's stock changed, and attach additional meta-data to the event that indicated the VVM status. The general approach to entity extension therefore is expected to be needed within inventory entities to cover new meta-data requirements and reporting.
Terms
Global Product - a model of Products that is removed from details of manufacturer.
Trade Item - an item that's produced at a certain time
Primary Package - From GS1, an atomic shippable item. this is usually a branded package that has a manufacturer supplied informational card.
Dispensing Unit - the atomic unit that may be given to a patient. Examples might be an injection of a vaccine, a blister pack, a single pill, etc
on hand and available - onHand is the stock physically present. Available is that stock that hasn't yet been ear-marked for some purpose (e.g. to pick or waiting to be shipped)
OpenLMIS: the global initiative for powerful LMIS software