Skip to content

Sales Orders

Backlog fieldValue
Story IDAP-SAL-012
EpicSales
Story typeBusiness workflow
Review statusDraft - business analyst and business owner review required
Source evidenceAppsPortal.Apis controller, application command/query handlers, validators, domain entities, and matching MFE workflow where available
Last source review2026-07-10

User story

As sales users, I want to create, approve, track, and fulfill customer orders so that commitments are controlled before invoicing.

Posting reference: AppsPortal Posting Ledger explains debit/credit construction. Delegation and Interaction Contracts explains module ownership, delegated commands, linked records, commit boundaries, and reversal propagation.

Acceptance criteria

  1. Only authorized users can view or execute the feature's actions.
  2. Required business data, active dependencies, tenant/branch scope, and current document state are validated.
  3. Invalid requests return actionable validation errors without applying a partial change.
  4. Search, list, view, print, and export operations use the same authorized business scope.
  5. Material create, edit, status, approval, posting, reversal, and integration actions are auditable where applicable.
  6. Financial or stock effects are applied atomically and no more than once.

Posting details

  1. Sales Order Post is an approval/commitment operation and creates no revenue journal, receivable, payment, or stock movement.
  2. Validate customer, date, currency/rate, price/discount authority, lines, quantities, optional workflow approval, and commercial rules.
  3. Mark the order Posted/approved and expose remaining quantities for Sales Invoice fulfillment.
  4. Later invoices reduce remaining order quantity and may close lines/order.
  5. Over-invoicing and modification/cancellation of fulfilled quantities are rejected.

General ledger posting

ConditionDebitCreditResult
Sales Order Post--No GL entry, receivable, revenue, tax, COGS, or payment is created.

Other module and document effects

AreaEffectConditional/no effect
InventoryNo Stock Out and no reservation movement from Post itself.Availability may be validated/displayed only.
Sales InvoiceExposes approved remaining quantities; later invoices reduce them and close fulfilled lines/order.Standalone invoices do not affect this order.
Customer/FinanceCommercial commitment only.No balance, credit consumption, due schedule, or cash movement until invoice/payment.

Core acceptance scenarios

  1. Given a valid Draft sales order, when the sales user submits/posts it, then the commitment and remaining fulfillment quantities become effective without GL, receivable, or stock posting.
  2. Given invoicing exceeds the remaining order quantity, when the operation is attempted, then the excess is rejected.
  3. Given the same Post request is retried after success, when the source is no longer Draft, then no duplicate journal, stock, balance, payment, or lifecycle effect is created.

Business rules

Required

Draft order, customer, date, currency/rate, and at least one positive item/service line are required.

Optional or conditional

Warehouse, price policy, salesperson, tax, discount, payment term, delivery, project, notes, and approval are conditional.

Action behavior

Save/Post records commitment but creates no stock/receivable/GL effect until invoice/fulfillment.

Blocking rule or downstream effect

Fulfillment updates remaining quantities and prevents over-invoicing/canceling fulfilled lines.

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)SalesOrderListComponentList/navigationPermission: AppSalesPermissions.SalesOrder_List; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/sales/src/app/remote-entry/transaction/transaction.module.ts:421
addAddSalesOrderComponentAddPermission: AppSalesPermissions.SalesOrder_Add; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/sales/src/app/remote-entry/transaction/transaction.module.ts:432
edit/:idEditSalesOrderComponentEditPermission: AppSalesPermissions.SalesOrder_Edit; Guards: PolicyAuthGuard, preventPostedGuardExplicit frontend feature ruleapps/sales/src/app/remote-entry/transaction/transaction.module.ts:443
sales-orderMainSalesOrderComponentList/navigationPermission: AppSalesPermissions.SalesOrder_List; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/sales/src/app/remote-entry/transaction/transaction.module.ts:412
view/:idViewSalesOrderComponentView/detailPermission: AppSalesPermissions.SalesOrder_View; Guards: PolicyAuthGuardExplicit frontend feature ruleapps/sales/src/app/remote-entry/transaction/transaction.module.ts:455

Observed frontend fields and validation

ComponentControlObserved frontend ruleComponent source
MainFormDataSectionComponentcurrencyIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentcustomerIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentdescriptionVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentexpiryDateVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentorderDateRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentpaymentTermIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentpricePolicyIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentsalesmanIdVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponenttermsAndConditionsVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
TableDetailsSectionComponentbarCodeVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentdiscountAmountVisible control; optional or API-dependentapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentitemIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentpriceConditionally required/validated in componentapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentquantityRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentuomIdRequired in component validatorapps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts

Observed frontend actions

ComponentClick action/handlerBusiness review requirementComponent source
HeaderViewSalesOrderComponentonOpenAttachmentDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/components/header-view-sales-order/header-view-sales-order.component.ts
MainFormDataSectionComponentaddDiscountDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentonOpenAttachmentDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
MainFormDataSectionComponentopenCustomerAdvancedSearchDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/components/main-form-data-section/main-form-data-section.component.ts
SalesOrderListComponentonDeleteAvailable 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/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
SalesOrderListComponentonEditOpen 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/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
SalesOrderListComponentonVeiwOpen 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/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
SalesOrderListComponentpostSalesOrderAvailable 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/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
SalesOrderListComponentprintoutGenerate 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/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
SalesOrderListComponenttoSalesInvoiceDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/pages/sales-order/sales-order-list/sales-order-list.component.ts
TableDetailsSectionComponentaddDiscountDocument the enabled state, permission, input context, resulting API or navigation effect, success refresh, and concrete failure behavior for this handler.apps/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentonAddLineAdd 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/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentonDeleteRowAvailable 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/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.component.ts
TableDetailsSectionComponentopenDialogOpen 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/sales/src/app/remote-entry/transaction/components/table-details-section/table-details-section.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: AppSalesPermissions.SalesOrder_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: AppSalesPermissions.SalesOrder_Add; Guards: PolicyAuthGuard
  3. 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: AppSalesPermissions.SalesOrder_Edit; Guards: PolicyAuthGuard, preventPostedGuard
  4. sales-order - 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: AppSalesPermissions.SalesOrder_List; Guards: PolicyAuthGuard
  5. 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: AppSalesPermissions.SalesOrder_View; Guards: PolicyAuthGuard

Internal Documentation — Microtec