Skip to content

Stock Transfer

Backlog fieldValue
Story IDINV-DASH-021
EpicInventory
Story typeDashboard
Review statusDraft - business analyst and business owner review required
Source evidenceInventory MFE route/form, Inventory.Apis controller, application command/query handlers, validators, domain entities, and posting services
Last source review2026-07-10

Purpose

Move stock between warehouses while preserving quantity, cost, and tracking identity.

User stories

  • As a warehouse user, I want to create a transfer from a source warehouse to a different destination warehouse.
  • As a warehouse user, I want to create a transfer from an approved transfer request when one is supplied.
  • As a supervisor, I want to post a valid transfer so that stock leaves the source and arrives at the destination as one controlled operation.
  • As an auditor, I want to view, search, export, and print transfer history.

Acceptance criteria

  1. Source and destination warehouses are valid and different.
  2. Transfer lines contain valid item variants, units, positive quantities, and tracking details where required.
  3. Source availability is validated before posting.
  4. A transfer request cannot be fulfilled beyond its remaining approved quantity.
  5. Posting decreases source stock and increases destination stock exactly once with no net quantity change across the company.
  6. Cost and tracking identity are preserved across the movement.
  7. A partially failed post does not leave only one side of the transfer effective.
  8. Edit/delete are limited to allowed pre-post states and corresponding permissions.

Posting details

  1. Post validates a Draft transfer, different active warehouses, open period, posted warehouse openings, no count lock, source availability, UOM/tracking integrity, and any linked request's approved remaining quantity. Transfer cost is derived from the inventory valuation data used by the Stock Out/Stock In handlers, including weighted-moving-average or last-purchase values where applicable.
  2. The transfer delegates the source leg to Stock Out and the destination leg to Stock In with their internal save-to-context behavior so the parent transfer controls the final commit. The source journal credits the source Warehouse GL and debits Goods in Transit; the destination journal debits the destination Warehouse GL and credits Goods in Transit.
  3. Goods in Transit is the bridge account, so its two entries must net to zero for the same transferred value. The process does not recognize revenue, expense, customer, or vendor balances.
  4. Posting consumes source layers, recreates destination layers with the same cost and tracking identity, links both stock documents and journals, marks the transfer Posted, and updates a linked Transfer Request to Partially Transferred or Done based on remaining quantity.
  5. Both warehouse legs, both journals, request progress, links, and transfer status commit atomically. Failure of either delegate rolls back the entire transfer; retry must not duplicate either leg. Reversal must reverse both linked stock movements and both journals together.

General ledger posting

Transfer legDebitCreditAmount basisNet effect
Source Stock OutGoods in TransitSource Warehouse GLTransferred inventory costRemoves value from source warehouse.
Destination Stock InDestination Warehouse GLGoods in TransitSame transferred inventory costAdds equal value to destination warehouse.
Complete transferDestination Warehouse GLSource Warehouse GLSame cost through GIT bridgeGoods in Transit nets to zero.

Module and data effects

Affected areaEffectConditional/no-effect rule
Source warehouseQuantity and valuation decrease through linked Stock Out.No source effect unless destination leg also succeeds.
Destination warehouseQuantity and same-cost valuation increase through linked Stock In.No destination effect unless source leg succeeds.
TrackingBatch/serial/expiry identity moves without changing total company quantity.Untracked items have no identity records.
Transfer RequestRemaining quantity and Partially Transferred/Done status update.Standalone transfer affects no request.
Sales/Purchase/FinanceNo receivable, payable, revenue, tax, or cash effect.Transfer is internal inventory movement only.

Core acceptance scenarios

  1. Given a valid Draft transfer with sufficient source stock, when Post is clicked, then linked Stock Out and Stock In plus their journals commit together and Goods in Transit nets to zero.
  2. Given a linked Transfer Request, when quantities are posted, then remaining quantities and Partially Transferred/Done state update in the same commit.
  3. Given either delegated stock leg fails, when Post is attempted, then neither warehouse balance, journal, request, nor transfer status changes.

Required and optional data

  • Required: receipt date, issued warehouse, target warehouse, source type, and at least one line.
  • Conditional: source ID for a source-driven transfer and transfer-request ID when created from a request.
  • Required per line: item, variant, UOM, positive quantity, and tracking values required by the item.
  • Optional: notes and source-detail references.
  • Issued and target warehouses must be different. The issued warehouse must contain sufficient matching stock.

Clicking Post

  1. Accepts only Draft and revalidates active references.
  2. Reads the Inventory costing method. Weighted Average selects WMA cost; otherwise Last Purchase cost. Missing stock resolves to zero cost and should be treated as a review risk.
  3. Creates and posts a linked Stock Out in the issued warehouse without committing separately.
  4. Creates and posts a linked Stock In in the target warehouse without committing separately.
  5. Stores both Stock Out and Stock In IDs/codes on the transfer.
  6. Marks the transfer Posted.
  7. If linked to a transfer request, marks that request Done when every remaining quantity is zero or less; otherwise Partially Transferred.
  8. Commits transfer, both stock documents, stock balances, and journals as one unit.

Stock and GL effect

  • Quantity: decrease issued warehouse and increase target warehouse by the same base quantity; company total is unchanged.
  • Cost/tracking: preserve selected valuation and tracking identity.
  • GL outbound: debit Goods in Transit, credit issued Warehouse GL.
  • GL inbound: debit target Warehouse GL, credit Goods in Transit.
  • The Goods in Transit entries should net to zero for the same transfer value.

Failure behavior

If either stock leg or journal fails, the transfer must not be partially posted. Posting is blocked for missing general settings, accounts, UOM conversion, stock, tracking, or inactive master data.

Status, action, and reversal controls

ActionRequired state/authorityPreconditions and affected dataFailure/reversal rule
Add/SaveTransfer Add; DraftDifferent warehouses, valid lines/tracking, optional eligible requestSaves commitment only; neither warehouse changes
Edit/DeleteDraft plus permissionRequest remaining quantity and source availability revalidatedPosted/fulfilled transfer is locked
PostDraft plus PostOpen period, both openings, no locks, sufficient source, same-cost destination, GIT and both Warehouse accountsSource Stock Out, destination Stock In, both journals, request progress, and status commit together
View/PrintView/print authorityAuthorized transferShows both warehouse legs, journals, request, cost and tracking links
ReverseTransfer reversal authorityNo later destination consumption/count/transfer and allowed periodReverse destination receipt and source issue together; restore request remaining state

Reconciliation controls

ControlRequired equality
Source issued base quantityDestination received base quantity
Source issue costDestination receipt cost
GIT debitGIT credit, net zero in local currency
Tracking identitiesSame item/batch/serial/expiry moved between warehouses
Request fulfilled quantitySum of linked posted transfers, not above approval

Frontend page coverage

The following UI coverage is sourced from the pulled MFE route configuration. A Module-level supporting artifact mapping is evidence of a reachable screen, but requires BA confirmation that it belongs to this story rather than a more specific feature story.

Route/pageComponentModeRoute permission/guardMapping confidenceSource
(module default)StockTransferListComponentList/navigationPermission: AppInventoryPermissions.StockTransfer_List; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:209
addAddStockTransferComponentAddPermission: AppInventoryPermissions.StockTransfer_Add; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:220
add/:stockTransferIdAddStockTransferComponentAddPermission: AppInventoryPermissions.StockTransfer_Add; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:231
edit/:idEditStockTransferComponentEditPermission: AppInventoryPermissions.StockTransfer_Edit; Guards: PolicyAuthGuard, preventPostedGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:241
stocktransferMainStockTransferListComponentList/navigationPermission: AppInventoryPermissions.StockTransfer_List; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:199
view/:idViewStockTransferComponentView/detailPermission: AppInventoryPermissions.StockTransfer_View; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/inventory/src/app/remote-entry/transactions/transactions.module.ts:253

Observed frontend fields and validation

ComponentControlObserved frontend ruleComponent source
AddStockTransferComponentbarCodeVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentissuedWarehouseIdRequired in component validatorapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentitemNumberVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentnotesVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentquantityConditionally required/validated in componentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentreceiptDateRequired in component validatorapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentsourceIdVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentsourceTypeRequired in component validatorapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponenttargetWarehouseIdRequired in component validatorapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponenttrackingNoVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentuomIdRequired in component validatorapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
EditStockTransferComponentbarCodeVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentcodeVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentissuedWarehouseIdVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentitemNumberVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentnotesVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentquantityConditionally required/validated in componentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentreceiptDateVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentsourceIdVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentsourceTypeVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponenttargetWarehouseIdVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponenttrackingNoVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentuomIdVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
ViewStockTransferComponentcodeVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/view-stock-transfer/view-stock-transfer.component.ts
ViewStockTransferComponentissueWarehouseNameVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/view-stock-transfer/view-stock-transfer.component.ts
ViewStockTransferComponentnotesVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/view-stock-transfer/view-stock-transfer.component.ts
ViewStockTransferComponentreceiptDateVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/view-stock-transfer/view-stock-transfer.component.ts
ViewStockTransferComponenttargetWarehouseNameVisible control; optional or API-dependentapps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/view-stock-transfer/view-stock-transfer.component.ts

Observed frontend actions

ComponentClick action/handlerBusiness review requirementComponent source
AddStockTransferComponentaddNewRowAdd one initialized detail row without changing existing rows; apply defaults and line validators, preserve stable row identity, and exclude incomplete rows from Save/Post.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentdeleteRowAvailable only in deletable states with Delete permission; identify the record in confirmation, call delete once, remove/refresh the list row on success, and retain the row with the API reason on failure.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentopenChechAvaliablityDialogOpen the item/lookup/tracking dialog with the current warehouse, item, UOM, and remaining quantity context; accepted values must return to the correct line and cancel must not mutate it.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentopenDialogOpen the item/lookup/tracking dialog with the current warehouse, item, UOM, and remaining quantity context; accepted values must return to the correct line and cancel must not mutate it.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
AddStockTransferComponentopentTransferDialogOpen the item/lookup/tracking dialog with the current warehouse, item, UOM, and remaining quantity context; accepted values must return to the correct line and cancel must not mutate it.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/add-stock-transfer/add-stock-transfer.component.ts
EditStockTransferComponentaddNewRowAdd one initialized detail row without changing existing rows; apply defaults and line validators, preserve stable row identity, and exclude incomplete rows from Save/Post.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentdeleteRowAvailable only in deletable states with Delete permission; identify the record in confirmation, call delete once, remove/refresh the list row on success, and retain the row with the API reason on failure.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentopenDialogOpen the item/lookup/tracking dialog with the current warehouse, item, UOM, and remaining quantity context; accepted values must return to the correct line and cancel must not mutate it.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
EditStockTransferComponentopentTransferDialogOpen the item/lookup/tracking dialog with the current warehouse, item, UOM, and remaining quantity context; accepted values must return to the correct line and cancel must not mutate it.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/edit-stock-transfer/edit-stock-transfer.component.ts
StockTransferListComponentnavigateToModuleByIdDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts
StockTransferListComponentonDeleteAvailable only in deletable states with Delete permission; identify the record in confirmation, call delete once, remove/refresh the list row on success, and retain the row with the API reason on failure.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts
StockTransferListComponentonEditOpen the identified editable record only with Edit permission; posted/locked records remain blocked by route or action state and list context must be recoverable on return.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts
StockTransferListComponentonPostAvailable only for a postable Draft and Post permission; confirm the document, prevent a second submission, call the posting API, and refresh status, journal/stock links, and row actions. Failure must keep the pre-post state.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts
StockTransferListComponentonViewOpen the authorized record in view mode with its status, totals, lines, source and generated-document links; handle deleted, forbidden, and missing records without exposing stale data.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts
StockTransferListComponentprintoutGenerate the printout for the selected record and authorized branch/tenant; use posted/current values and surface print, template, ZATCA/ETA, or popup failures without changing transaction state.apps/inventory/src/app/remote-entry/transactions/pages/stock-transfer/stock-transfer-list/stock-transfer-list.component.ts

Page-specific frontend acceptance criteria

  1. (module default) - List/navigation: Load an authorized paged/searchable list or navigation page; preserve filters/sort/paging and expose only permitted row and bulk actions. Security observed: Permission: AppInventoryPermissions.StockTransfer_List; Guards: PolicyAuthGuard
  2. add - Add: Render permitted fields, required indicators, defaults, dependent lookups, validation, Save/Cancel, loading, success, and API-error states. Security observed: Permission: AppInventoryPermissions.StockTransfer_Add; Guards: PolicyAuthGuard
  3. add/:stockTransferId - Add: Render permitted fields, required indicators, defaults, dependent lookups, validation, Save/Cancel, loading, success, and API-error states. Security observed: Permission: AppInventoryPermissions.StockTransfer_Add; Guards: PolicyAuthGuard
  4. edit/:id - Edit: Load the identified record, enforce state/permission field locks, preserve concurrency identity, validate changes, and return without losing filters. Security observed: Permission: AppInventoryPermissions.StockTransfer_Edit; Guards: PolicyAuthGuard, preventPostedGuard
  5. stocktransfer - List/navigation: Load an authorized paged/searchable list or navigation page; preserve filters/sort/paging and expose only permitted row and bulk actions. Security observed: Permission: AppInventoryPermissions.StockTransfer_List; Guards: PolicyAuthGuard
  6. view/:id - View/detail: Load an authorized immutable/detail representation with status-aware actions, linked records, print/export where exposed, and not-found/forbidden handling. Security observed: Permission: AppInventoryPermissions.StockTransfer_View; Guards: PolicyAuthGuard

Internal Documentation — Microtec