Inventory is deceptively deep. On the surface it's items, quantities, and locations, but underneath it's a valuation engine (FIFO, average, standard cost) tied to every issue and receipt, which means an extension that looks like a simple field addition can quietly touch cost layers if you're not careful about where it hooks in.
Core DACs and screens
INItem (Stock and Non-Stock Items, IN202500) is the item master, INLocation holds warehouse locations, and INTran is the transaction table every movement — issue, receipt, transfer, adjustment — ultimately writes to. The primary graph for item maintenance is InventoryItemMaint, while movement screens (issues, receipts, transfers) each have their own graph built around INTran.
Extension points
Custom item attributes are usually a straightforward PXCacheExtension<INItem> plus fields surfaced on the item screen — this is safe and doesn't touch valuation. Anything that changes quantity or cost calculation is riskier: a RowInserting or RowPersisting handler on INTran that adjusts quantity based on custom logic needs to run before the cost engine picks up the transaction, and needs to be idempotent, because inventory transactions can be part of a larger multi-line document (a shipment with ten lines) that gets saved and re-saved as the user works through it.
Adding a "hazmat class" field to INItem is a low-risk, well-trodden customization. Changing how a cost layer is consumed on issue is not — it affects every module downstream of inventory valuation, including GL postings for COGS. Treat these as different categories of work with different levels of testing rigor, not variations on the same task.
A realistic scenario: custom replenishment signal
Stock replenishment (min/max, reorder point) is configurable per item, but some businesses need a replenishment trigger based on a factor Acumatica doesn't track natively — seasonal demand curves, or a signal from an external planning system. This is usually implemented as a scheduled process that reads INItem/ItemAvailability data and either writes suggested purchase requisitions or flags items for the buyer's attention, rather than trying to override the built-in reorder point calculation.
public class SeasonalReplenishmentCheck : PXGraph<SeasonalReplenishmentCheck>
{
public virtual void FlagLowStockItems()
{
PXResultset<INItem> items = PXSelectJoin<INItem,
InnerJoin<INItemSite, On<INItemSite.inventoryID, Equal<INItem.inventoryID>>>,
Where<INItemSite.qtyAvail, LessEqual<INItemSite.reorderPoint>>>
.Select(this);
foreach (INItem item in items)
{
decimal seasonalFactor = SeasonalFactorLookup.Get(item.InventoryCD, DateTime.Today.Month);
if (seasonalFactor > 1.2m)
{
// Write a suggestion row rather than auto-creating a PO —
// let the buyer confirm before committing spend.
ReplenishmentSuggestions.Insert(new ReplenishmentSuggestion
{
InventoryID = item.InventoryID,
SuggestedQty = item.SafetyStock * seasonalFactor
});
}
}
}
}
Writing a suggestion rather than auto-creating a purchase requisition is a deliberate choice — automated purchasing decisions are exactly the kind of customization that should have a human checkpoint until the logic has a track record.
Lot/serial and valuation methods
If the item uses lot or serial tracking, or a valuation method other than average cost, any custom transaction logic needs to account for that — a customization built and tested against a simple average-cost, non-lot item will frequently break the first time it's run against an FIFO-costed, lot-tracked item, because the number of cost layers and the tracking fields involved are genuinely different.
Testing considerations
Test inventory extensions against at least one item per valuation method and tracking type in use at the client — average cost, FIFO or standard cost if used, and lot/serial if used. A single happy-path item is not representative of what actually lives in a real inventory module.
Wrapping up
Inventory extensions split cleanly into low-risk attribute work and high-risk transaction/valuation work — know which one you're doing before you start. Keep automated decisions (auto-reorder, auto-transfer) advisory until proven, and test against every valuation method and tracking configuration actually in use, not just the simplest one.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.