92
ATG C om mer ce P ro g ramm in g Gui d e
44 5
19 - I n ven t o ry Fra mewo rk
RepositoryInventoryManager
implements all the methods defined by the
InventoryManager
API. It
is a thin wrapper around a repository that contains the inventory information. This allows a maximum
amount of flexibility for potential third party integrators. Integrators can simply implement a repository
containing the required properties for cooperation with the
RepositoryInventoryManager
. The
Repository
InventoryManager
can then be configured to extract inventory manager information from
the third party repository.
The initial implementation of the
RepositoryInventoryManager
uses the a SQL Repository to store
inventory information. In the future, another repository can easily be swapped with the SQL Repository.
The
RepositoryInventoryManager
requires that the inventory items stored in the repository have
certain attributes. All items must contain the following properties and types to represent information the
RepositoryInventoryManager
needs to store in the repository.
Note: The names of the properties are configurable in the
RepositoryInventoryManager
. This allows
them to be internationalized, custom configured, etc.
java.lang.Long <stock level property>
Represents the number of items currently available for purchase. Every inventory item
in the repository must have a Long property attached to it that represents the item’s
inventory level. The default value is
stockLevel
. The name of this property in the
repository is configurable through the
stocklevelPropertyName
property in the
RepositoryInventoryManager
.
java.lang.Long <backorder level property>
Represents the number of items that can be backordered currently. Every inventory
item in the repository must have a Long property attached to it that represents the
item’s backorder level. The default value is
backorderLevel
. The name of this
property in the repository is configurable through the
backorderLevelPropertyName
property in the
RepositoryInventoryManager
.
java.lang.Long <preorder level property>
Represents the number of items that can be preordered currently. Every inventory
item in the repository must have a Long property attached to it that represents the
item’s preorder level. The default value is
preorderLevel
. The name of this property
in the repository is configurable through the
preorderLevelPropertyName
property
in the
RepositoryInventoryManager
.
java.lang.Long <stock threshold property>
Every inventory item in the repository must have a Long property attached to it that
represents the item’s stock level threshold. If the
stocklevel
falls below this value, an
event is triggered. The default value is
stockThreshold
. The name of this property in
the repository is configurable through the
stockThresholdPropertyName
property
in the
RepositoryInventoryManager
.
java.lang.Long <backorder threshold property>
Every inventory item in the repository must have a Long property attached to it that
represents the item’s backorder level threshold. If the
backorderLevel
falls below
this value, an event is triggered. The default value is
backorderThreshold
. The name
of this property in the repository is configurable through the
84
ATG C om merce P ro gra mm in g G ui d e
44 6
19 - I n ven t or y Fram ewo rk
backorderThresholdPropertyName
property in the
RepositoryInventoryManager
.
java.lang.Long <preorder threshold property>
Every inventory item in the repository must have a Long property attached to it that
represents the item’s preorder level threshold. If the
preorderLevel
falls below this
value, an event is triggered. The default value is
preorderThreshold
. The name of
this property in the repository is configurable through the
preorderThresholdPropertyName
property in the
RepositoryInventoryManager
.
java.lang.Integer < availability status property>
Every inventory item in the repository must have an Integer property attached to it
that represents the item’s availability status. The name of this property in the
repository is configurable through the
availabilityStatusPropertyName
property. The default value of the property name is
availabilityStatus
.
The possible values are:
AVAILABILITY_STATUS_IN_STOCK = 1000
AVAILABILITY_STATUS_OUT_OF_STOCK = 1001
AVAILABILITY_STATUS_PREORDERABLE = 1002
AVAILABILITY_STATUS_BACKORDERABLE = 1003
AVAILABILITY_STATUS_DERIVED = 1004
AVAILABILITY_STATUS_DISCONTINUED = 1005
Note: If the status in the repository is AVAILABILITY_STATUS_DERIVED, then a call to
queryAvailabilityStatus
calculates the actual status based on the values of the
item’s
stocklevel
,
backorderLevel
, and
preorderLevel
.
If the status is “hardcoded” to something other than DERIVED, then the status might
not reflect the actual state of the item. For example, if an item’s availability status is
AVAILABILITY_STATUS_IN_STOCK and the
stockLevel
is reduced to 0, then any call
to
queryAvailabilityStatus
will return AVAILABILITY_STATUS_IN_STOCK even
though there is no stock available. In most cases this would be an error, therefore
AVAILABILITY_STATUS_DERIVED should be used for almost all inventory items.
java.util.Date <inventory availability date property>
The date and time at which more of the item will be available for purchase. If
availability is AVAILABILITY_STATUS_IN_STOCK then this property is not used. If
availability is AVAILABILITY_STATUS_OUT_OF_STOCK,
AVAILABILITY_STATUS_PREORDERABLE, or AVAILABILITY_STATUS_BACKORDERABLE
then this property is the date on which more of the product will be available for
purchase. The default value is
availabilityDate
.
java.lang.String <catalog reference id property>
The ID of the item in the product catalog to which this inventory item refers. All the
calls in the
InventoryManager
that take a SKU ID use this property to find the correct
inventory item. The default value is
catalogRefId
and is configurable through the
catalogRefIdPropertyName
property.
124
ATG C om mer ce P ro g ramm in g Gui d e
44 7
19 - I n ven t o ry Fra mewo rk
The
RepositoryInventoryManager
implements the
InventoryManager
interface by using the
configured properties listed above to extract data from a configured repository. For example, the
queryStocklevel
method is implemented by getting the item with the requested ID from the
repository and reading the <stock level property> property.
Using the RepositoryInventoryManager to Implement the InventoryManager
The following section describes how the
RepositoryInventoryManager
implements the
InventoryManager
interface.
Every item in the inventory has an associated SKU (Stock Keeping Unit). Each SKU has three levels
associated with it:
stocklevel
,
backorderLevel
, and
preorderLevel
. The behavior of each of these
levels is similar. If someone makes a successful purchase call,
stocklevel
is decreased. If someone makes
a successful backorder call,
backorderLevel
is decreased. If someone makes a successful preorder call,
preorderLevel
is decreased.
Every SKU also has an
availabilityStatus
. In most cases, the SKU will have an
availabilityStatus
of AVAILABILITY_STATUS_DERIVED. In some cases, it is strictly defined as
AVAILABILITY_STATUS_IN_STOCK, AVAILABILITY_STATUS_OUT_OF_STOCK,
AVAILABILIITY_STATUS_BACKORDERABLE, AVAILABILITY_STATUS_PREORDERABLE, or
AVAILABILITY_STATUS_DISCONTINUED.
If it is derived,
queryAvailabilityStatus
calculates the value based on the three levels:
stocklevel
,
backorderLevel
, and
preorderLevel
.
If
stocklevel
is not 0, then the SKU is IN_STOCK.
If
stocklevel
is 0 but
backorderLevel
is not 0, then the SKU is BACKORDERABLE.
If
stocklevel
and
backorderLevel
are both 0, but
preorderLevel
is not 0, then
the SKU is PREORDERABLE.
If all three levels are 0, then the SKU is OUT_OF_STOCK.
If a purchase call fails for a particular SKU and
queryAvailabilityStatus
says the item is
backorderable, then backorder should be called. Calling backorder decreases the
backorderLevel
. To
ensure the level remains consistent after the SKU is available again,
purchaseOffBackorder
should be
called in place of purchase. This not only decreases
stocklevel
, but it also increases the
backorderLevel
.
If a purchase call fails for a particular SKU and
queryAvailabilityStatus
says the item is preorderable,
then preorder should be called. Calling preorder decreases the
preorderLevel
. To ensure the level
remains consistent after the SKU is available again,
purchaseOffPreorder
should be called in place of
purchase. This not only decreases
stocklevel
, but it also increases the
preorderLevel
.
If your system does not need backorder levels and preorder levels, then you do not need to call
backorder
,
preorder
,
purchaseOffBackorder
, or
purchaseOffPreorder
. The purchase call is
enough.
The default value for an item’s
stockLevel
is –1. This value indicates that there is an infinite amount of
stock. The default value for all other levels. (
backorderLevel
,
preorderLevel
,
stockThreshold
,
backorderThreshold
, and
preorderThreshold
) is 0.
88
ATG C om merce P ro gra mm in g G ui d e
44 8
19 - I n ven t or y Fram ewo rk
If the fulfillment system attempts to purchase an item for a customer and the item is out of stock but
BACKORDERABLE, then the fulfillment system can backorder the item. If the fulfillment system attempts
to purchase an item for a customer and item is out of stock but PREORDERABLE, then the fulfillment
system can preorder the item. Both these statuses mean that the whole order could be waiting for the
item to be in stock. Therefore, it is important that the fulfillment system is notified when an item is in
stock after being backordered, preordered, or even out of stock.
The
UpdateInventory
message indicates that new inventory is available for previously unavailable
items. When the fulfillment system receives an
UpdateInventory
message, the fulfillment system knows
that the items included in the message can be successfully purchased now. It is the responsibility of
InventoryManager
to send this message. The
RepositoryInventoryManager
sends the message
when the
inventoryWasUpdated
method is called.
If a call is made to
inventoryWasUpdated
then an
UpdateInventory
message is constructed and sent
out over the port specified in the
updateInventoryPort
property.
The
UpdateInventory
message has one property:
String[] itemIds
– A list of SKUs that were BACKORDERABLE, PREORDERABLE, or
OUT_OF_STOCK, but are now IN_STOCK. This list is the same as the list of IDs passed
into the
inventoryWasUpdated
method.
Refer to the Inventory JMS Messages chapter for more information on the JMS Messages
CachingInventoryManager
The
CachingInventoryManager
is also included in the ATG Commerce out-of-the-box implementation.
The
CachingInventoryManager
caches any read-only data for quick display to the site user. It is
configured with a
Cache
and an
UncachedInventoryManager
.
The
uncachedInventoryManager
property of the
CachingInventoryManager
refers to any
implementation of the
InventoryManager
API. It is recommended that the
uncachedInventoryManager
property refer to an instance of the
RepositoryInventoryManager
.
All methods are passed to the
UncachedInventoryManager
, except for
queryStocklevel
queryBackorderLevel
queryPreorderLevel
queryAvailabilityStatus
queryAvailabilityDate
queryStockThreshold
queryBackorderThreshold
queryPreorderThreshold
.
These methods work by asking the cache for the item with the requested ID. The needed property value is
then read from the cached item.
82
ATG C om mer ce P ro g ramm in g Gui d e
44 9
19 - I n ven t o ry Fra mewo rk
If a method is called that changes a property of an inventory item, then that item’s cached value is
invalidated and will be reloaded the next time it is needed. If the
CachingInventoryManager
is used, it
should be used for all inventory operations or it could return invalid results. Invalid results could occur if
some updates are made directly to the
InventoryManager
referred to by the
uncachedInventoryManager
property (as opposed to through the
CachingInventoryManager
). This
is because the changes made outside of the
CachingInventoryManager
will not have invalidated the
cache.
The
flushCache
method flushes the existing cache data. The
flushCache
method flushes the entire
cache.
flushCache(List)
flushes the entry for each ID in list.
The
CachingInventoryManager
does not actually perform inventory management. It relies on another
implementation of the
InventoryManager
interface. Therefore, if you provide your own implementation
of the
InventoryManager
interface, instant caching can be configured using the
CachingInventoryManager
and setting its
uncachedInventoryManager
property to your
implementation.
InventoryCache
InventoryCache
is the cache used by the
CachingInventoryManager
. It can be found at
/atg/commerce/inventory/InventoryCache
in the component browser of the ACC. It is an instance
of
atg.service.cache.Cache
. If the inventory data changes, resulting in stale data in the cache, it is
possible to flush the cache. This class includes a public void method
flush
that can be accessed through
the component browser. It flushes all the entries from the caching. For more information, see the Caching
the Inventory section.
The following table describes the properties of the
InventoryCache
component that you can use to
define your cache policies:
maximumCacheEntries
The maximum number of elements in the cache. If set to 0,
nothing will be cached. If set to –1, there is no limit on how
many elements can be in the cache.
maximumCacheSize
The maximum memory size of the cache.
maximumEntrySize
The maximum memory size of a single entry in the cache.
maximumEntryLifetime
The maximum number of milliseconds that an entry will
live in the cache. *
* By default, the
maximumEntryLifetime
property is set to 7,200,000 (2 hours) in the live configuration.
The Motorprise reference application overrides this value and changes it to 60,000 (1 minute). This
frequent update time is recommended during development, so that information will be updated rapidly.
LocalizingInventoryManager
LocalizingInventoryManager
is an implementation of the
InventoryManager
interface that is used
when you want to have more than one set of inventory data (and therefore more than one
107
ATG C om merce P ro gra mm in g G ui d e
45 0
19 - I n ven t or y Fram ewo rk
InventoryManager
).
LocalizingInventoryManager
determines which data/manager set to use based
on your customer’s
locale
.
LocalizingInventoryManager
contains the following properties:
defaultLocaleKey
– the locale to use to determine which
InventoryManager
to
use when the locale cannot be determined from the request.
defaultInventoryManager
– the
InventoryManager
to use when the
InventoryManager
cannot be determined from the locale.
inventoryManagers
– a Map pairing
localeKeys
to their corresponding
InventoryManager
components.
useDefaultInventoryManager
– a Boolean property that determines whether to
use the
defaultInventoryManager
if an
InventoryManager
cannot be found for
the user’s locale.
LocalizingInventoryManager
implements all the
InventoryManager
methods twice:
once with the signature provided in the
InventoryManager
interface
once with an extra
pLocaleKey
String parameter
The methods with the
InventoryManager
signatures call the second implementations, passing the value
of the
defaultLocaleKey
property as the extra parameter.
The second methods retrieve the proper
InventoryManager
by calling the
getInventoryManager
method with the
localeKey
as the parameter. Then, they call the corresponding method in the
InventoryManager
that was retrieved.
LocalizingInventoryManager
is compatible with the
InventoryManager
interface because you can
pass it the same parameters and it will use the default
InventoryManager
to perform operations. You
also can make your calls with the extra
pLocaleKey
parameter, and use
LocalizingInventoryManager
to handle multiple
InventoryManager
instances.
The
getInventoryManager
method takes the
localeKey
parameter and checks the
inventoryManagers
map for a corresponding
InventoryManager
. If it finds one, it is returned.
Otherwise, it checks the
useDefaultInventoryManager
property. If true, it returns the
DefaultInventoryManager
. If false, an error is thrown.
Examples of Using the Inventory Manager
This section provides a few simple examples of how the
InventoryManager
can be used during
fulfillment. These examples include:
Allocating Items for an Order
Canceling or Removing an Item from an Order
Displaying an Item’s Availability to a Customer
51
ATG C om mer ce P ro g ramm in g Gui d e
45 1
19 - I n ven t o ry Fra mewo rk
Filling Partial Orders
Preventing Inventory Deadlocks
Allocating Items for an Order
For the first example, if a customer orders five of item ‘sku-0’ then the inventory system can be used to
allocate, or “purchase” that item:
String itemId = "sku-0";
long quantity = 5;
// Assume inventory manager is defined as a property in this class.
InventoryManager inventory = getInventoryManager();
int status = inventory.purchase(itemId, quantity);
The purchase call
status
at this time is either
INVENTORY_STATUS_SUCCEED
, or
INVENTORY_STATUS_FAIL
. If it is
INVENTORY_STATUS_SUCCEED
, then everything is ready and processing
can continue. If the status is
INVENTORY_STATUS_FAIL
, then check the availability status of the item to
determine why it failed:
int availability = inventory.queryAvailabilityStatus(itemId);
The next step depends on the availability status. The following sample sets the
newStatus
value based
on the retrieved availability status.
int newStatus;
if(availability == inventory.AVAILABILITY_STATUS_BACKORDERABLE)
newStatus = inventory.backorder(itemId, quantity);
else if(availability == inventory.AVAILABILITY_STATUS_IN_STOCK)
newStatus = inventory.backorder(itemId, quantity);
else if(availability == inventory.AVAILABILITY_STATUS_PREORDERABLE_
newStatus = inventory.preorder(itemId, quantity);
else // the only other option is AVAILABILITY_STATUS_OUT_OF_STOCK
newStatus = inventory.INVENTORY_STATUS_FAIL;
If the availability status is IN_STOCK, then backorder is called. Backorder is called because the only way
that the purchase call could fail if the item is in stock is if the requested quantity is higher than the current
stocklevel
. If the item is backordered, it can be reallocated later, after the stock level increases.
The
newStatus
value INVENTORY_STATUS_FAIL indicates one of the following situations:
The item is out of stock.
56
ATG C om merce P ro gra mm in g G ui d e
45 2
19 - I n ven t or y Fram ewo rk
The request is attempting to allocate more items than available.
The item is backorderable but the system could not successfully backorder the item.
This could occur if the quantity in the order was higher than the number of items
available to be backordered.
The item is discontinued.
If the
newStatus
value is INVENTORY_STATUS_FAIL during fulfillment, then the system sets the state of
the item to
FAILED
.
The above example does not include tracking features. Tracking is an important part of the inventory
system. For example, you can track backordering or preordering the item and then change that item’s
state. If an item is backordered and then the
stockLevel
is later increased, simply calling
purchase
is
insufficient to remove the item from backorder.
The following changes must be made to the first code sample. This ensures that the
backorderLevel
and
preorderLevel
for the given items are current. For more information on states, see ATG Commerce
States.
String itemId = "sku-0";
long quantity = 5;
// assume we have some way of getting the state of the given item
// in DCS during fulfillment this is done using
// ShippingGroupCommerceItemRelationship.getState();
int itemState = getItemState();
InventoryManager inventory = getInventoryManager();
// now, use the appropriate method, depending on the state
int status;
if(itemState == INITIAL) // normal case
status = inventory.purchase(itemId, quantity);
else if(itemState == BACK_ORDERED)
status = inventory.purchaseOffBackorder(itemId, quantity);
else if(itemState == PRE_ORDERED)
status = inventory.purchaseOffPreorder(itemId, quantity)
Canceling or Removing an Item from an Order
The following example describes how to use the inventory manager to cancel or remove an item from the
order.
String id = "sku-0";
long quantity = 5;
int itemState = getItemState();
InventoryManager inventory = getInventoryManager();
// now, use the appropriate method, depending on the state
int status;
if(itemState == PENDING_DELIVERY) // normal case
Documents you may be interested
Documents you may be interested