WMSSeptember 2026 · 4 min read

ASP.NET Core Inventory Management

By go2ismail · Published · .NET 10

At a glance

Stock is calculated from confirmed movement contributions per warehouse and product. Receipts add, deliveries subtract, and transfers separate dispatch from receipt.

Separate a balance from the operations that explain it

ASP.NET Core inventory management becomes easier to reason about when each stock-changing operation leaves an identifiable transaction. In Indotalent’s Blazor WMS Source Code, InventoryTransaction carries the product, warehouse, movement date, document reference, status, and signed stock contribution. The product entity itself does not contain a stock-balance property.

This article follows the calculation helper and report handlers in the source. The example quantities are illustrative so that you can reproduce the arithmetic in a development environment without relying on changing demo data.

Receiving and delivery have opposite directions

InventoryTransactionHelper.CalculateInvenTrans assigns the direction from ModuleName. A GoodsReceive movement is inbound. A DeliveryOrder movement is outbound. It also assigns warehouse-from and warehouse-to references, using system warehouses such as VENDOR and CUSTOMER for the external side of these operations.

// Actual signed-stock calculation in InventoryTransactionHelper
transaction.Stock = (transaction.Movement ?? 0.0)
    * (int)(transaction.TransType ?? InventoryTransType.In);

The enum values are In = 1 and Out = -1. A positive movement quantity of 12 therefore contributes either +12 or −12 according to its direction. The helper rejects nonpositive movement quantities for non-stock-count modules, so passing a negative number is not the general way to express an outbound operation.

Reconcile a small warehouse example

OperationStatusSigned contributionConfirmed balance
Receive 100 unitsConfirmed+100100
Deliver 24 unitsConfirmed−2476
Negative adjustment of 2Confirmed−274
Receive another 10DraftNot included in report74

The stock report filters exactly InventoryTransactionStatus.Confirmed. The enum also contains Draft, Cancelled, and Archived; these are not included by that equality filter. When investigating a changed balance, inspect status as well as quantity. Do not assume that an archived row remains part of the current stock report just because it was once confirmed.

The current stock-report handler also requires Product.Physical == true and Warehouse.SystemWarehouse == false. Its displayed balances therefore concern physical products in ordinary warehouses, rather than every record with a confirmed status.

Treat warehouse transfers as dispatch and receipt

The model contains separate TransferOut and TransferIn documents, with TransferIn referencing TransferOut. The calculation helper assigns outbound transfer movement from the source warehouse to a TRANSIT system warehouse, and inbound transfer movement from TRANSIT to the receiving warehouse.

If warehouse A starts with 74 and dispatches 10 confirmed units, A becomes 64. When warehouse B receives and confirms 10, B gains 10. These stages should be reviewed separately when investigating goods in transit. The existence of TRANSIT references alone does not prove that the application maintains an independently reconciled transit balance for every shipment.

Distinguish adjustments, scrapping, and physical counts

PositiveAdjustment adds a contribution, while NegativeAdjustment and Scrapping subtract one. Keeping these document types distinct helps explain why a correction happened. A physical stock count compares a counted quantity with the system quantity, rather than simply recording another receipt.

For StockCount, the helper obtains the current confirmed stock excluding the current transaction, then computes QtySCDelta = QtySCSys - QtySCCount. It uses the absolute delta for Movement. A negative delta produces an inbound correction; a nonnegative delta produces an outbound correction.

For example, system stock of 64 and a counted quantity of 61 produce delta 3 and contribution −3. System stock of 64 and count 67 produce delta −3 and contribution +3. The inspected helper rejects counted quantities of zero or below. If counting an empty bin is required, that is a concrete behavior to extend and test, not a supported case to assume.

Know which layer owns the calculation

Feature handlers construct transactions with document identifiers and product references, invoke the calculation helper, and save through AppDbContext. Update handlers for movement documents propagate document status to their transaction rows. Reports then query the resulting records. Writing an arbitrary transaction row directly to the database bypasses that application path.

A custom integration should therefore use the relevant business operation and inspect its behavior before treating the movement entity as a general-purpose public write API. The API article shows how to verify routes and responses using a smaller warehouse-maintenance feature.

Verify a workflow before extending it

For a development acceptance exercise, reconcile a receipt and delivery, leave one movement draft, and compare the stock and transaction reports. Then test a transfer’s two stages and a stock-count variance. For changes to confirmation or retry handling, include repeated and simultaneous requests; a simple sum calculation does not establish concurrency protection or exactly-once processing.

Use the inventory schema guide to identify the fields involved. For the complete operational application behind those fields, continue to Blazor WMS Source Code.