Skip to main content

Advanced Inventory Management

Overview​

Advanced Inventory Management counts stock per location rather than only per product. A store holding stock in more than one place — a shop and a warehouse, several branches — gets a stock figure per location, transfers that move stock between them with their own lifecycle, an audit log recording every change with its reason, and a daily low-stock alert email.

It is a premium module. Enable it from Empora → Modules once your license includes inventory; enabling it creates its three tables and seeds its settings.

Availability​

ItemValue
Module keyinventory
TierPremium
Entitlement keyinventory
Admin tabinventory, under Operations
Enabled optionaiowc_module_enabled_inventory (off until enabled)
REST namespaceaiowc/v1

Settings​

Stored in the bundled option row aiowc_iv_settings. The prefix was renamed from an older one that collided with the Invoicing module's storage; existing installs have their per-key options copied across on the first request after upgrade.

Stored keyDefaultMeaning
enable_multi_locationtrueCount stock per location.
enable_transferstrueAllow stock transfers between locations.
enable_audit_logtrueRecord every stock change.
enable_low_stock_alertstrueSend the low-stock email.
low_stock_threshold5Quantity at or below which a product counts as low.
alert_emailsite admin emailWhere the low-stock email goes.
show_location_stockfalseShow per-location stock on the product page.
show_stock_status_labeltrueShow a stock badge in the shop loop.
enable_auto_synctrueLet the sync job run.
sync_intervalhourlyhourly, twicedaily or daily; anything else falls back to hourly.

Admin screen​

The Inventory tab holds five sub-tabs, with the active one held in the URL: Overview, Locations, Audit Logs, Transfers and Settings. All five call the routes below.

REST API endpoints​

Registered by InventoryRest on rest_api_init and listed in the REST contract file. Each is gated on the shared manage_woocommerce permission check, which also verifies the REST nonce on cookie-authenticated requests. Unlike most of the plugin, these routes return their payload directly rather than wrapped in the shared response envelope — see Known gaps.

MethodPathPurposeRequired args
GET/inventory/summaryOverview figures.–
GET/inventory/locationsList locations; accepts active_only.–
POST/inventory/locationsCreate a location; accepts address, contact, is_default, is_active, priority.name
GET/inventory/locations/{id}Read a location.id
PUT/inventory/locations/{id}Update a location.id
DELETE/inventory/locations/{id}Delete a location.id
GET/inventory/logsAudit log; accepts product_id, location_id, change_type, start_date, end_date, limit, offset.–
GET/inventory/low-stockProducts at or below a threshold; accepts threshold, limit.–
POST/inventory/products/{product_id}/adjustAdjust stock; accepts reason and location_id.product_id, quantity
GET/inventory/products/{product_id}/historyStock history for one product; accepts limit.product_id
GET/inventory/transfersList transfers; accepts status, limit, offset.–
POST/inventory/transfersCreate a transfer; accepts notes.from_location_id, to_location_id, product_id, quantity
GET/inventory/transfers/{id}Read a transfer.id
POST/inventory/transfers/{id}/shipMove a transfer to in transit.id
POST/inventory/transfers/{id}/completeComplete a transfer.id
POST/inventory/transfers/{id}/cancelCancel a transfer; accepts reason.id
GET/inventory/settingsRead the settings above.–
POST/inventory/settingsUpdate the settings above.–

A transfer moves through pending, in_transit, completed and cancelled; only a pending or in-transit transfer may be cancelled.

WooCommerce integration​

Attached by registerHooks() when the module is enabled and the license grants it.

HookIntent
woocommerce_product_set_stockRecord a stock change.
woocommerce_variation_set_stockRecord a variation stock change.
woocommerce_order_status_changedRecord stock movement caused by an order transition.
admin_initRegister the settings.
woocommerce_get_stock_htmlReplace the stock message.
woocommerce_after_add_to_cart_formShow per-location stock.
woocommerce_before_shop_loop_item_titleShow a stock badge in the loop.
manage_product_posts_columns and manage_product_posts_custom_columnAdd a stock column to the products list.
wp_enqueue_scriptsLoad the stock display assets.

Database schema​

Created by Schema/DatabaseSchema.php when the module is enabled.

TableHolds
{prefix}aiowc_inventory_locationsLocations: name, code, address, contact, default flag, active flag, priority.
{prefix}aiowc_inventory_logsStock changes with product, location, change type and reason.
{prefix}aiowc_inventory_transfersTransfers between locations with their status.

Background jobs​

Registered when the module is enabled and unscheduled when it is disabled.

HookScheduleIntent
aiowc_inventory_low_stock_alertsDailyEmails up to 100 low-stock products to alert_email. Returns immediately when enable_low_stock_alerts is off.
aiowc_inventory_stock_syncFrom sync_intervalVerifies stock levels and processes stale transfers. Returns immediately when enable_auto_sync is off.
aiowc_inventory_cleanupDailyDeletes log rows older than 90 days and completed or cancelled transfers older than 180 days. Both ages are fixed in the job.

Entitlement limits​

The entitlement is a single on/off grant: without inventory the module stays locked, and while it is absent none of the above loads. Nothing in the code applies a license-side quota to locations, transfers or log rows.

Known gaps​

The module's REST routes answer with the payload alone, where the rest of the plugin wraps a response in a shared envelope. A client reading these endpoints should expect the bare body.

Disabling the module unschedules its jobs but leaves its three tables and their rows in place, so stock history survives a module being switched off and on again.