Appearance
Sales Projects
| Backlog field | Value |
|---|---|
| Story ID | AP-SAL-013 |
| Epic | Sales |
| Story type | Business workflow |
| Review status | Draft - business analyst and business owner review required |
| Source evidence | AppsPortal.Apis controller, application command/query handlers, validators, domain entities, and matching MFE workflow where available |
| Last source review | 2026-07-10 |
User story
As project sales users, I want to maintain sales projects and issue project invoices so that project-based revenue and customer balances are traceable.
Acceptance criteria
- Only authorized users can view or execute the feature's actions.
- Required business data, active dependencies, tenant/branch scope, and current document state are validated.
- Invalid requests return actionable validation errors without applying a partial change.
- Search, list, view, print, and export operations use the same authorized business scope.
- Material create, edit, status, approval, posting, reversal, and integration actions are auditable where applicable.
- Financial or stock effects are applied atomically and no more than once.
Business rules
Required
Project code/name, customer, effective status/dates, and responsible scope are required; project invoices require eligible project and billing lines.
Optional or conditional
Budget, milestones, terms, team, attachments, and notes are optional/conditional.
Action behavior
Project Save creates no GL; Project Invoice Post follows Sales Invoice accounting, balances, tax, and credit rules.
Blocking rule or downstream effect
Closed/cancelled projects cannot accept new billing beyond policy.
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/page | Component | Mode | Route permission/guard | Mapping confidence | Source |
|---|---|---|---|---|---|
| (module default) | ProjectInvoiceListComponent | List/navigation | Permission: AppSalesPermissions.ProjectInvoice_List; Guards: PolicyAuthGuard | Explicit frontend feature rule | apps/sales/src/app/remote-entry/transaction/transaction.module.ts:347 |
| add/:projectId | AddProjectInvoiceComponent | Add | Permission: AppSalesPermissions.ProjectInvoice_Add; Guards: PolicyAuthGuard | Explicit frontend feature rule | apps/sales/src/app/remote-entry/transaction/transaction.module.ts:357 |
| edit/:projectId | EditProjectInvoiceComponent | Edit | Permission: AppSalesPermissions.ProjectInvoice_Edit; Guards: PolicyAuthGuard, preventPostedGuard | Explicit frontend feature rule | apps/sales/src/app/remote-entry/transaction/transaction.module.ts:367 |
| project-invoice | MainProjectInvoiceComponent | List/navigation | Permission: AppSalesPermissions.ProjectInvoice_List; Guards: PolicyAuthGuard | Explicit frontend feature rule | apps/sales/src/app/remote-entry/transaction/transaction.module.ts:338 |
| view/:id | ViewProjectInvoiceComponent | View/detail | Permission: AppSalesPermissions.ProjectInvoice_View; Guards: PolicyAuthGuard | Explicit frontend feature rule | apps/sales/src/app/remote-entry/transaction/transaction.module.ts:378 |
Observed frontend fields and validation
| Component | Control | Observed frontend rule | Component source |
|---|---|---|---|
| EditInvoiceLinesTableComponent | itemValue | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/edit-project-invoice/edit-invoice-lines-table/edit-invoice-lines-table.component.ts |
| EditInvoiceMainInfoComponent | description | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/edit-project-invoice/edit-invoice-main-info/edit-invoice-main-info.component.ts |
| EditInvoiceMainInfoComponent | invoiceDate | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/edit-project-invoice/edit-invoice-main-info/edit-invoice-main-info.component.ts |
| EditInvoiceMainInfoComponent | taxId | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/edit-project-invoice/edit-invoice-main-info/edit-invoice-main-info.component.ts |
| EditInvoiceMainInfoComponent | vatPercentage | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/edit-project-invoice/edit-invoice-main-info/edit-invoice-main-info.component.ts |
| InvoiceLinesTableComponent | itemValue | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/add-project-invoice/invoice-lines-table/invoice-lines-table.component.ts |
| InvoiceMainInfoComponent | description | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/add-project-invoice/invoice-main-info/invoice-main-info.component.ts |
| InvoiceMainInfoComponent | invoiceDate | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/add-project-invoice/invoice-main-info/invoice-main-info.component.ts |
| InvoiceMainInfoComponent | taxId | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/add-project-invoice/invoice-main-info/invoice-main-info.component.ts |
| InvoiceMainInfoComponent | vatPercentage | Visible control; optional or API-dependent | apps/sales/src/app/remote-entry/transaction/pages/project-invoice/add-project-invoice/invoice-main-info/invoice-main-info.component.ts |
Observed frontend actions
| Component | Click action/handler | Business review requirement | Component source |
|---|---|---|---|
| EditInvoiceLinesTableComponent | emit | Document 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/project-invoice/edit-project-invoice/edit-invoice-lines-table/edit-invoice-lines-table.component.ts |
| InvoiceLinesTableComponent | emit | Document 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/project-invoice/add-project-invoice/invoice-lines-table/invoice-lines-table.component.ts |
| ProjectInvoiceListComponent | onDelete | Available 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/project-invoice/project-invoice-list/project-invoice-list.component.ts |
| ProjectInvoiceListComponent | onEdit | Open 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/project-invoice/project-invoice-list/project-invoice-list.component.ts |
| ProjectInvoiceListComponent | onPrintOutWithZatcaConfirm | Generate 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/project-invoice/project-invoice-list/project-invoice-list.component.ts |
| ProjectInvoiceListComponent | onView | Open 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/project-invoice/project-invoice-list/project-invoice-list.component.ts |
Page-specific frontend acceptance criteria
- (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.ProjectInvoice_List; Guards: PolicyAuthGuard
- add/:projectId - Add: Render permitted fields, required indicators, defaults, dependent lookups, validation, Save/Cancel, loading, success, and API-error states. Security observed: Permission: AppSalesPermissions.ProjectInvoice_Add; Guards: PolicyAuthGuard
- edit/:projectId - Edit: Load the identified record, enforce state/permission field locks, preserve concurrency identity, validate changes, and return without losing filters. Security observed: Permission: AppSalesPermissions.ProjectInvoice_Edit; Guards: PolicyAuthGuard, preventPostedGuard
- project-invoice - 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.ProjectInvoice_List; Guards: PolicyAuthGuard
- 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.ProjectInvoice_View; Guards: PolicyAuthGuard