Cashflow Projection Applet
Overview
The Cashflow Projection Applet is a planning register for money you expect to bill and collect. You group work into programs, record each piece of client work as an engagement, break an engagement into lines with a value, and then — per line and per fiscal month — enter the target billing, target collection, actual billing and actual collection figures. A dashboard and two reports read those figures back as collection rates, outstanding amounts and month-by-month projections.
It is a standalone set of tables (bl_rvm_cfp_*). Nothing in it is a financial document: the
applet does not read invoices, receipts or the ledger, and — see
Lifecycle and effects — it writes nothing to them either. Every “actual”
figure is typed in by hand.
bl_rvm_cfp_engagement_hdr and the two are not linked.gh:bigledger/blg-applet-wavelet-cashflow-projection-applet#27).
Its NgRx state is still called SalesInvoiceStates, its Application Settings model still lists every
sales-invoice key, and app.component.ts still dispatches selectServerDocType("INTERNAL_SALES_INVOICE")
on start. None of that changes what the screens below do, but it explains the odd names you will
meet in the settings area.Where it fits
| Direction | What | Why |
|---|---|---|
| Before | Customer Maintenance | The Account tab and the Program Item form pick the client from the customer listing (entity/customers); the Conglomerate drop-down reads bl_fi_mst_entity_conglomerate_hdr. |
| Before | Entity Maintenance | Entity Branch drop-downs read bl_fi_mst_entity_branch_hdr for the chosen entity. |
| Before | Forex | Currency drop-downs are the tenant’s bl_fi_mst_ccy list. |
| Before | Tenant Admin | Program and engagement members must already be users of the tenant; the Verify button looks them up by e-mail or phone. |
| Inside | Program → Engagement → Line → Fiscal Period | The hierarchy this applet owns; the dashboard and both reports aggregate the fiscal-period rows. |
| After | Nothing | No document, journal, cashbook or stock record is created from this applet. |
Screens and menus
app.routing.ts (mainPath = applet/tnt/wavelet/erp/cashflow-projection-applet) declares the
menu routes below, plus settings/… and personalization/… children. An empty path redirects to
program; anything unknown goes to the applet’s 404 screen. The sidebar labels come from
models/menu-items.ts; the header title is Cashflow Projection Applet.
| Menu | Route | What opens |
|---|---|---|
| Program | program | Program Listing → Create Program / Edit Program → Select Entity (a three-column view stack) |
| Engagement | engagement | CFP Engagement Listing → Create / Edit Engagement → Select Entity |
| Dashboard | dashboard (also engagement/dashboard) | Engagement Dashboard |
| Report → Cashflow Projection Report | cashflow-projection-report | Month-by-month projection grid |
| Report → Collection Delay Report | collection-delay-report | Fiscal periods where actual collection fell short of target |
The settings gear (OWNER and ADMIN ranks) and the Personalization link render as in every applet;
the applet does not set the layout’s hideSettings flag.
Program
Program Listing is an ag-grid over bl_rvm_cfp_program_hdr with the columns Program Code,
Program Name, Description, Status, Created Date, Updated Date, Created By, Updated By (the last two
are resolved from app_login_subject.main_email). The advanced search offers Program Code, Program
Name, Status (ACTIVE / INACTIVE, preset to ACTIVE), Created By, Created Date and Updated
Date; a free-text keyword must be at least three characters. Created By is shown in the search
panel but buildCriteria() never sends it. The first load asks for everything (limit = 9999).
There is no delete button on this listing; onDelete() exists but nothing calls it.
Create Program has a single Main Details tab (Program Code, Program Name, Description, Status) and a CREATE button. Edit Program adds read-only audit fields and three more tabs:
| Tab | What it holds |
|---|---|
| Member | bl_rvm_cfp_program_member rows: User Email, Rank, Status, Created Date, Updated Date, with a quick “Search email” filter. Add Member asks for the user’s e-mail or phone number, a Verify button that resolves it to a tenant login, a Rank (ADMIN, CONTRIBUTOR, VIEWER) and a Status. ADD stays disabled until Verify succeeds. Editing offers UPDATE and DELETE. |
| Engagement | The engagements whose program_hdr_guid is this program: Title, Currency, Status, Process Status, Created By, Created Date, Updated Date. + opens an inline Create Engagement form; a row click opens Edit Engagement. Both are the same five-tab form described under Engagement below, except that the Program is fixed to the parent and there is no Program drop-down. |
| Program Item | bl_rvm_cfp_engagement_fi_item_hdr rows for this program: Item Code, Item Name, Item Type, Currency, Status, Created Date, Updated Date. Add Item / row-click Edit Item open the form in Fields; Edit has a DELETE button. Choosing Entity or Sales Entity navigates to the third column, Select Entity, and returns with the pick. |
Engagement
CFP Engagement Listing shows Title, Currency, Status, Process Status, Created By, Created Date
and Updated Date. The Title cell is an expandable group: opening it loads a detail grid of the
parent program’s items (Item Code, Item Name, Item Type, Currency, Status, Created Date —
gh:…#44). The advanced search offers Title, Currency and Created Date; only Title (sent as
search_word) and the dates are applied. The listing always sends status = ACTIVE — inactive
engagements never appear here (they still appear on a program’s Engagement tab).
GET …/cfp/engagement-hdrs/backoffice-ep
endpoint and writes the whole result to the browser console (// DEBUG in onGridReady), and
loadData() logs the query and the raw response. On a tenant with many engagements that is a second,
unpaged fetch on every visit.Create Engagement / Edit Engagement (one component, EngagementFormComponent, registered twice
in the view stack) has five tabs:
| Tab | What it holds |
|---|---|
| Main Details | Engagement Title, Program, Conglomerate, Branch, Currency, Status, Process Status, plus read-only Created/Updated Date and By in edit mode. The Branch drop-down on this tab is never populated (branches stays []), so its only option is – None –; set the branch on the Account tab instead. |
| Account | Entity Id (click to open Select Entity), a searchable Entity Branch drop-down, and read-only Status, Identity Type, Currency, Description, Entity Name, Entity Type, ID Number, Email, Phone Number copied from the chosen entity. Picking an entity stores entity_hdr_guid on the engagement; picking a branch stores entity_branch_guid. |
| Lines | Only after the first save (“Save the engagement first before adding lines.”). A Line Listing (Title, Value, Process Status, Status, Created Date, Updated Date) with a Total Value footer that sums the listed values, a Month From / Month To filter that filters on the line’s created date, + to add a line, and row-click to edit. Edit Line Item has a Main tab and a Fiscal Period tab (gh:…#59): a grid of bl_rvm_cfp_fiscal_period_engagement_line_link rows for the line (Txn Date, Fiscal Year, Fiscal Month, Fiscal Day, ARAP Open Balance, Target Billing, Target Adjustment, Target Collection, Actual Billing, Actual Collection, Remarks, Status) with its own Add / Edit / DELETE. |
| Member | Only after the first save. bl_rvm_cfp_engagement_member rows: Name, Email, Role, Status, Updated Date. Add Member takes an e-mail or phone number, Verify (exact match on EMAIL_USERNAME or MOBILE_USERNAME principals of this tenant), a Rank / Role (OWNER, ADMIN, MANAGER, MEMBER, GUEST, VISITOR, ANONYMOUS; default MEMBER) and Status. Editing offers UPDATE and REMOVE. |
| Export | Only after the first save. A Printable Format drop-down (preset from the PRINTABLE setting) and EXPORT AS PDF, which calls GET …/cfp/engagement-hdrs/print-pdf/backoffice-ep/{guid}?printableFormatHdrGuid=… and saves CFP_ENGAGEMENT_<guid>.pdf. The same action sits behind the PRINT PDF button in the title bar of the edit form. |
The SAVE button is disabled while the form is invalid only in create mode; in edit mode it is
always enabled and saveEdit() does not re-check validity.
Dashboard
Engagement Dashboard loads up to 5,000 engagements through
GET …/cfp/engagement-hdrs/backoffice-ep/custom/query, which returns each header together with the
sum and count of its lines and the sums of its fiscal-period figures (CfpEngagementHdrUow.getCustomQuery).
It then computes everything client-side:
- Filters — fiscal-year presets (This Year, Last Year, Last 3 Years, Last 5 Years), Engagement
Title (
search_word, which the backend matches against title or currency code), Process Status (multi), Currency (multi, from a fixed list of 13 ISO codes hard-coded indashboard-filters.component.ts, not from Forex), Fiscal Year From / To, Fiscal Month, Fiscal Day, Fiscal Txn Date From / To, Created From / To. When any fiscal filter is set, only engagements with at least one matching fiscal-period row are returned and the sums cover only those rows. No status filter is sent, soINACTIVEengagements are included. - KPI cards — Active Engagements (row count), Engagement Value (Σ line
value), Target Billing, Target Collection, Actual Collection, Collection Rate (actual ÷ target collection × 100), Pending Amount (max(0, target − actual collection)), AR/AP Open (Σarap_open_balance). - Charts — top engagements by line value; collection rate by engagement; process-status distribution; actual collection by currency; highest actual collection; engagements with the most fiscal-period rows. Clicking a chart segment filters the table below it (a removable chip).
- Table — Title, Currency, Status, Process Status, Lines, Target Collection, Actual Collection, Pending, Collection Rate, and a “View details” icon that only shows a toast. Export writes the table to CSV.
Reports
Cashflow Projection Report (GET …/cfp/cashflow-projection-report/backoffice-ep): search by
Program Name, Engagement, Fiscal Year (a select of the current year ± 2, preset to the current
year), Month From and Month To. One row per engagement, pinned Program and Engagement columns, then
a Total for <year> group — Total Project Value, Project Balance, Target Billing,
Adjustment, Adjusted Target Billing, Actual Billing, Target Collection, Actual Collection,
Outstanding Amount — and one column group per month in the range with Open Bal, Target Billing,
Adjustment, Adj. Target Billing, Actual Billing, Target Collection, Actual Collection and Remarks.
Expanding a row loads a per-item detail grid from …/detail-ep. The formulas are in
Lifecycle and effects.
Collection Delay Report (GET …/cfp/collection-variance-report/backoffice-ep): search by
Program Name, Engagement, Fiscal Year, Month From and Month To. Columns Program, Engagement, Item,
Year, Month, Target, Actual, Variance, Status — one row per fiscal-period row whose actual
collection is below its target collection.
Configuration
Before you can use it
| Prerequisite | Where it is set | Why it matters |
|---|---|---|
| Customers / entities | Customer Maintenance | The Account tab and the Program Item form select from the customer listing. Conglomerates come from the same master. |
| Entity branches | Entity Maintenance | Entity Branch drop-downs list bl_fi_mst_entity_branch_hdr rows of the selected entity; without them the drop-down offers only – None –. |
| Currencies | Forex | Currency is required on an engagement (Validators.required on ccy_code); the list is the first 200 rows of bl_fi_mst_ccy. |
| Tenant users | Tenant Admin | Members are app_login_subject records; Verify fails with User not found for anyone who is not yet a user of the tenant. |
| Server-side permissions | Settings → Permission Wizard / Permission Set / User Permission / Role Permission in this applet | Every endpoint checks an API_TNT_DM_ERP_CFP_* code (table below). A user with none of them sees empty grids and Failed to load … toasts. |
A .jrxml printable (optional) | Settings → Printable Format Settings | Needed only for PRINT PDF / EXPORT AS PDF. |
Applet settings
The settings gear opens the shared settings shell (blg-shared-utilities/modules/settings), whose
menu for this applet is: System Configuration — Application Settings, Default Selection,
Printable Format Settings (from settingItems in menu-items.ts); Server Side Permissions —
Permission Wizard, Permission Set, User Permission, Role Permission; Developer Tools — Release
Notes. Routes for email-template, webhook, feature-visibility, branch-settings,
workflow-settings, team-permission-listing, client-side-permission-listing,
role-pricing-scheme-link-listing and applet-log are declared in app.routing.ts but have no
menu entry; they are fork leftovers reachable only by typing the URL.
Application Settings is the shared FieldConfigurationComponent from blg-shared-utilities
(routed at settings/field-settings), not an applet-local screen. For appletCode === 'cashflowProjectionApplet'
it hides the Gen Doc Listing, Main Details, File Import, Account, Line Items and Miscellaneous tabs
and the Change view button, so what remains is a Sidebar Menu tab, an Advanced Search
Filter tab, a second small Gen Doc Listing tab and a Free Gift tab. Only an OWNER or ADMIN
can open it. SAVE writes the whole form as the applet’s master settings
(SessionActions.saveMasterSettingsInit).
Settings that pass all four proofs (declared in applet-settings.model.ts, rendered, persisted,
read by this applet’s code):
| Setting | Where | What it controls | Default | Effect when changed |
|---|---|---|---|---|
Hide Program (HIDE_PROGRAM_MENU) | Application Settings → Sidebar Menu | Removes Program from the sidebar (app.component.ts, updateMenuItem("program", …)). | off (?? false) | The menu item disappears on the next load. The route still exists, and the applet’s empty path still redirects to program, so the screen remains reachable. |
Hide Engagement (HIDE_ENGAGEMENT_MENU) | Application Settings → Sidebar Menu | Removes Engagement from the sidebar. | off | As above. The Dashboard and Report menus have no equivalent toggle (gh:…#52 asked for five; two were built). |
Default printable format (PRINTABLE) | Printable Format Settings → SET DEFAULT | The format pre-selected in the Export tab of every engagement form. | none | The Export tab’s drop-down and the PRINT PDF button use it until you pick another format on that screen. |
Default Toggle Column (DEFAULT_TOGGLE_COLUMN, personal) | Personalization → Default Selection | SINGLE or DOUBLE column layout for the Program and Engagement view stacks. Also rewritten every time you press the column toggle in a listing. | none | Both containers and both listings read it on load. |
Rendered on the same screens and persisted, but read by nothing reachable in this applet (changing them does nothing here):
- Application Settings:
HIDE_AUDIT_TRAIL_MENU(there is no audit-trail menu),ENABLE_INLINE_APPLET_CONFIG,DISABLE_GEN_DOC_LISTING,ENABLE_MULTIPLE_MAIN_ITEMS/FREE_GIFT_TOP_LEVEL_LOGIC, andHIDE_TRANSACTION_DATE(no search model in this applet has a transaction date). - Default Selection (master): Default Branch, Default Location, Default Pricing Scheme, Unit Price
Decimal Precision, Transaction Date Logic and the “Details Tab Ordering” list are all fields of the
sales-invoice screen this was forked from.
DEFAULT_PRICEBOOKis read byapp.component.ts, which loads the pricebook into the store, but no reachable component uses it;DATE_TXN_LOGICis read only by posting effects that nothing in this applet dispatches. - Personalization → Default Selection: Default Branch, Default Location, Default Delivery Branch,
Default Delivery Location and Default Tab Orientation (
DEFAULT_ORIENTATIONonly matters whenVERTICAL_ORIENTATIONis on, and that key has no control in this applet).
Read at runtime without a model declaration — the keys live only in the shared component but
this applet passes its settings into the shared advanced search on the Program and Engagement
listings and both reports ([appletSettings]), which honours them:
| Key | Where | Effect here |
|---|---|---|
HIDE_CREATED_DATE | Application Settings → Advanced Search Filter | Hides the Created Date filter on the Program and Engagement listings. |
HIDE_UPDATED_DATE | Application Settings → Advanced Search Filter | Hides the Updated Date filter on the Program listing. |
Printable Format Settings lists bl_fi_printable_format_hdr rows whose txn_type is
INTERNAL_SALES_INVOICE (Default, Format Code, Format Name, File Name, File Size, Created Date,
Updated Date, Updated By). + uploads a new format (Format Code, Format Name, one .jrxml file —
the button stays disabled for any other extension) and SET DEFAULT stores the selected row’s guid
as PRINTABLE. The document type is fixed by PrintableFormatConstants.docType, so the formats you
see here are the tenant’s Sales Invoice printable formats, and a CFP engagement template must be
registered under that type even though its parameters (title, ccy_code, status,
process_status, program_hdr_guid, entity_hdr_guid, entity_branch_guid, conglomerate_hdr_guid,
created_date, updated_date, and line_title / line_value / line_process_status /
line_status per engagement line) are nothing like an invoice’s.
Settings in other applets that control this applet
None found. The applet reads no bl_fi_* configuration, no default GL mapping, no document
numbering and no tax code (routes, settings components and services checked at commit 8aad54c).
Feature visibility and permissions
bl_applet_client_side_perm_dfn has no rows for applet code cashflowProjectionApplet
(checked against akaun_master, 2026-09-15); gh:…#49 (open) is the request to create them.
app.component.ts still looks for the Sales Invoice client-side codes (SHOW_PICK_PACK_QUEUE_MENU,
SHOW_FILE_IMPORT_MENU, …) and asks the permission-inquiry endpoint for
TNT_API_DOC_INTERNAL_SALES_INVOICE_*_TGT_GUID; the only place the answer is used is the branch
drop-down of the fork-inherited Default Selection screens.
Server-side gates (TntErpPermissionsV2, one family per table, each with OWNER, ADMIN,
CREATE, READ, UPDATE, DELETE; every controller maps its verbs correctly):
| Area | Permission family | Notes |
|---|---|---|
| Program | API_TNT_DM_ERP_CFP_PROGRAM_HDR_* | |
| Program member | API_TNT_DM_ERP_CFP_PROGRAM_MEMBER_* | |
| Engagement | API_TNT_DM_ERP_CFP_ENGAGEMENT_HDR_* | READ also gates print-pdf and the dashboard’s custom/query. |
| Engagement line | API_TNT_DM_ERP_CFP_ENGAGEMENT_LINE_* | |
| Engagement member | API_TNT_DM_ERP_CFP_ENGAGEMENT_MEMBER_* | |
| Program item | API_TNT_DM_ERP_CFP_ENGAGEMENT_FI_ITEM_HDR_* | |
| Fiscal period row | API_TNT_DM_ERP_CFP_FP_ENG_LINE_LINK_* | READ gates both reports. |
| Fiscal period audit trail | API_TNT_DM_ERP_CFP_FP_ENG_LINE_LINK_AUDIT_TRAIL_* | Endpoints exist; nothing in the product writes or reads the table. |
Each controller also exposes a /login-ep/query endpoint for portal (login-entity) users, gated by
UserPermissionService.isUserLoginEntity rather than a permission code. The applet UI does not call
them.
Fields
Validators are Angular reactive-form validators unless stated; the backend validates none of the business fields (see What the backend actually validates).
Program — Main Details
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Program Code | Short identifier | Yes on create | Free text; no uniqueness check on the server. On edit, a client-side lookup shows “This code already exists. Saving will fail.” and disables SAVE if another program has the code; create performs no such check. |
| Program Name | Label | Yes on create | |
| Description | Free text | No | |
| Status | ACTIVE / INACTIVE | — | Default ACTIVE. The Program listing filters on it. |
| Created Date / By, Updated Date / By | Audit | — | Read-only, edit only. |
Program — Member
| Field | Meaning | Required | Notes |
|---|---|---|---|
| User email or phone number | Login principal to look up | Yes | Verify searches app_login_principal and keeps the exact (case-insensitive) match; the resolved subject’s main_email is shown as “Verified”. |
| Rank | ADMIN, CONTRIBUTOR, VIEWER | Yes | Stored in role; the backend accepts any string. Nothing in the applet or backend grants or denies anything based on it. |
| Status | ACTIVE / INACTIVE | Yes |
Program — Program Item
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Item Code | Identifier | Yes | No uniqueness check. |
| Item Name | Label | Yes | |
| Item Type | SERVICE, PRODUCT, OTHER | Yes | Default SERVICE. |
| Currency | bl_fi_mst_ccy code | No | |
| Entity | The client entity | No | Opens Select Entity; loads that entity’s branches into the next field. |
| Entity Branch | Branch of the chosen entity | No | Disabled until an entity with branches is chosen. |
| Sales Entity | A second entity reference | No | Stored in sales_entity_hdr_guid; nothing reads it. |
| External PIC 01 / 02 | Contact names, free text | No | |
| Remark | Free text | No | |
| Status | ACTIVE / INACTIVE | — | Default ACTIVE. |
Engagement — Main Details
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Engagement Title | Label | Yes on create | Free text. |
| Program | Parent program | No | First 200 programs of any status. Fixed and hidden when created from a program’s Engagement tab. |
| Conglomerate | bl_fi_mst_entity_conglomerate_hdr | No | First 200 rows. |
| Branch | Entity branch | No | Never populated on this tab; use the Account tab. |
| Currency | bl_fi_mst_ccy code | Yes on create | |
| Status | ACTIVE / INACTIVE | — | Default ACTIVE. Only ACTIVE engagements show on the Engagement menu. |
| Process Status | PENDING_REVIEW, APPROVED, DUPLICATE, REJECTED or none | No | The header column is typed as the backend enum OcrConstants.ProcessStatus, so only these four values (or null) deserialize. A label, not a workflow — see Lifecycle. |
Engagement — Account
Only two controls write to the engagement: Entity Id (click to open Select Entity; sets
entity_hdr_guid) and Entity Branch (sets entity_branch_guid). Status, Identity Type,
Currency, Description, Entity Name, Entity Type, ID Number, Email and Phone Number are read-only
copies of the entity. The “Entity Id*” asterisk belongs to a local display form; the engagement’s
own form does not require an entity, so an engagement saves without one.
Engagement — Line
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Title | Label | Yes | |
| Value | Amount, numeric(70,22) | No | Summed as “Total Value” on the Lines tab, as Engagement Value on the dashboard and as Total Project Value on the projection report. |
| Process Status | Same four labels as the header | No | Stored as plain text on the line. |
| Status | ACTIVE / INACTIVE | Yes |
The line column engagement_item_hdr_guid (link to a Program Item) exists in the table and the
backend model but no screen sets it — see Troubleshooting for what that
does to the reports.
Engagement — Fiscal Period (per line)
| Field | Meaning | Required | Notes |
|---|---|---|---|
| Fiscal Year | Integer year | Yes | No range check anywhere. |
| Fiscal Month | Integer month | Yes | No 1–12 check anywhere; the reports build a column per month value they find in 1–12 only. |
| Fiscal Day | Integer day | No | |
| Txn Date | Date | No | Used only by the dashboard’s Fiscal Txn Date filter. |
| ARAP Open Balance | Opening receivable/payable balance | No | Reported as “Open Bal” and “AR/AP Open”. |
| Target Billing | Planned billing for the period | No | |
| Target Adjustment | Adjustment to the plan | No | Added to Target Billing to give Adjusted Target Billing. |
| Target Collection | Planned collection | No | |
| Actual Billing | What was billed | No | Typed in — not read from invoices. |
| Actual Collection | What was collected | No | Typed in — not read from receipts. |
| Remarks | Free text | No | Shown on the projection report’s detail rows only. |
| Status | ACTIVE / INACTIVE | Yes | Reports exclude only DELETED, so INACTIVE rows still count. |
The table also carries recurring_json, recurring_group_01_guid, recurring_group_02_guid,
recurring_previous_guid and recurring_next_guid; no screen or service populates them
(gh:…#74 asked how one-time versus recurring is expressed).
Engagement — Member
| Field | Meaning | Required | Notes |
|---|---|---|---|
| User Email or Phone Number | Login principal | Yes | Verify queries principal_type = EMAIL_USERNAME for an e-mail, MOBILE_USERNAME otherwise; “User not found in this tenant” otherwise. ADD is disabled until it succeeds. |
| Rank / Role | OWNER, ADMIN, MANAGER, MEMBER, GUEST, VISITOR, ANONYMOUS | Yes | Default MEMBER. Free text on the backend; grants nothing. |
| Status | ACTIVE / INACTIVE | Yes |
Lifecycle and effects
Posting proof
| Aspect | Value |
|---|---|
| Server document type | None. No bl_rvm_cfp_* table has a ServerDocTypes entry; the seven JournalPostingTypeHandler document types do not include any of them. |
| Amount signum | Not applicable — no FinancialDocDataConsistencyObject exists for these tables. The eight Cfp*DataConsistencyObject classes validate structure only (guid, revision, status, audit subjects, dates). |
| Quantity signum | Not applicable — no stock processor references this domain. |
| Dr/Cr equation | None. grep of bl_fi_journal, JournalPosting, StockBalance, StockProcessor, FinancialDocDataConsistency, ServerDocTypes and GenDoc across every file that mentions cashFlowProjection / Cfp / bl_rvm_cfp returns only TntErpPermissionsV2.java (which merely lists permission codes), and the reverse grep of JournalPosting* / *StockProcessor* for cfp returns nothing. |
| GL precedence | Not applicable. No GL code is stored on any of the eight tables. |
| Stock processor | None. |
| What VOID reverses | There is no VOID and no FINAL. Every write is a plain insert or update through DbTableDao; DELETE is a hard DELETE FROM … WHERE guid IN (…), not a status change. |
Everything the dashboard and reports show is therefore an arithmetic view of what users typed into the fiscal-period rows. Actual billing and actual collection are not reconciled against Sales Invoices or Receipt Vouchers.
Statuses
Every table has a status column (ACTIVE / INACTIVE from the screens; the backend default is
ACTIVE). Engagement headers and lines also carry a process_status label with four values
(PENDING_REVIEW, APPROVED, DUPLICATE, REJECTED). There are no transitions: any value can
be set at any time, nothing locks a record after “Approved”, and no notification, workflow or
approval step is attached (the Workflow Settings route in the settings area is a fork leftover
without a menu entry).
Relationships and deletes
- Engagement → Program, Line → Engagement, Fiscal Period → Line and Engagement, Member → Program or Engagement, Program Item → Program are foreign keys in the tenant schema.
- DELETE buttons (program item, program member, engagement line, fiscal period, engagement
member) issue a hard delete with
allGuidsHasToBeAffected = true. A row that is still referenced — for example a line that has fiscal-period rows — fails the foreign-key check and the screen shows Failed to delete line item. Delete the children first. - Programs and engagements have no delete button anywhere in the UI; set them
INACTIVEinstead. The API (DELETE …/backoffice-ep/{guid}) can remove them, subject to the same foreign keys. - The audit-trail table
bl_rvm_cfp_fiscal_period_engagement_line_link_audit_trailhas a full CRUD controller, butCfpFpEngLineLinkUow.updatedoes not write to it and no screen calls the audit-trail service. It stays empty unless something outside the product writes it.
What the backend actually validates
fillAndValidateForCreation / ForUpdate in each Cfp*DataConsistencyObject check that the guid
is absent-or-new (create) or present-and-existing (update), that revision and status are set,
that created_by_subject_guid / updated_by_subject_guid resolve to app_login_subject, and that
the dates are present. fillMissingDataForCreation fills the dates, defaults status to ACTIVE
and generates a revision. No foreign key, code uniqueness, month range, currency existence or
role value is checked in Java; the only “duplicate” error codes in
CashFlowProjectionErrorCodesConstants are *_GUID_DUPLICATE. Bad references surface as the
database’s foreign-key error, which the screens show as a generic Failed to create/update … toast.
What the reports compute
Both reports and the dashboard exclude rows whose status is DELETED — a value nothing in the
product sets — so in practice they include everything, INACTIVE included.
Cashflow Projection Report (CfpFpEngLineLinkUow.getCashflowProjectionSummary), for the chosen
fiscal year (default: the server’s current year) and optional month range:
| Column | Formula |
|---|---|
| Monthly Open Bal, Target Billing, Adjustment, Actual Billing, Target Collection, Actual Collection | SUM of the fiscal-period rows of the engagement for that month. |
| Monthly Adj. Target Billing | SUM(target_billing + target_adjustment). |
| Monthly Outstanding Amount (returned, not shown in the monthly columns) | SUM(target_collection − actual_collection). |
| Monthly Remarks | Always blank in the summary rows — the summary query does not return remarks; only the detail grid does. |
| Year totals | The monthly figures summed over the selected months. |
| Total Project Value | SUM(value) of the engagement’s lines — all lines, regardless of year. |
| Project Balance | Year target collection − year actual collection (the same number as the year’s Outstanding Amount). |
Rows are engagements INNER JOINed to their program, ordered by program name then title, twenty per
page; an engagement without a program is not listed. The detail grid (getCashflowProjectionDetail)
lists one row per engagement line INNER JOINed to a program item through
engagement_item_hdr_guid, with the line’s value as Project Value and the month columns from that
line’s fiscal-period rows.
Collection Delay Report (getCollectionVarianceReport): one row per fiscal-period row where
actual_collection < target_collection, INNER JOINed through the line to a program item and
through the engagement to a program. Variance is actual_collection − target_collection (negative
by construction). The backend also accepts a project_manager_guids filter that joins engagement
members with role = 'Project Manager' — a role value no screen can set — and the UI does not expose
the filter.
Related applets
- Customer Maintenance — the customer listing behind every Select Entity column, and the conglomerate master behind the Conglomerate drop-down.
- Entity Maintenance — where an entity’s branches are maintained; both Entity Branch drop-downs read them.
- Forex — the currency list on engagements and program items.
- Tenant Admin — the tenant users that program and engagement members are resolved from.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Collection Delay Report is empty although fiscal-period rows have actual below target | The report’s SQL INNER JOINs each line to a program item through bl_rvm_cfp_engagement_line.engagement_item_hdr_guid, and no screen in the applet ever sets that column (grep engagement_item_hdr_guid across the UI returns nothing). | Until a screen or the API links lines to program items, the report cannot show UI-created lines. Populate engagement_item_hdr_guid through the API (PUT …/cfp/engagement-lines/backoffice-ep) as a workaround. |
| Expanding an engagement on the Cashflow Projection Report shows no detail rows | Same join: the detail query lists only lines linked to a program item. The summary row still shows the totals. | As above. |
| An engagement is missing from the Cashflow Projection Report | The summary joins engagements to programs with an inner join; an engagement saved with Program = – None – is skipped. | Set the Program on the engagement’s Main Details tab. |
| Engagement vanished from the Engagement menu | The Engagement listing sends status = ACTIVE and offers no status filter, so an engagement set to INACTIVE disappears from that menu. | Open the parent program → Engagement tab, which lists engagements of any status, or set it back to ACTIVE. |
| The Branch drop-down on Main Details only offers – None – | branches is never loaded in engagement-form.component.ts or program-engagement-listing.component.ts. | Pick the entity on the Account tab; its Entity Branch drop-down is the one that works and writes the same entity_branch_guid. |
| Two programs with the same Program Code | Create Program does not check for duplicates and the backend has no uniqueness rule; only Edit Program runs the client-side check (and disables SAVE). | Search the listing before creating. Rename one of them through Edit Program. |
| “Failed to delete line item.” / “Failed to delete item.” / “Failed to delete member.” | Hard delete blocked by a foreign key — a line with fiscal-period rows, or a program item referenced by a line’s engagement_item_hdr_guid. | Delete the fiscal-period rows (or unlink the item) first, then the parent. |
| “User not found for the given email or phone number.” / “User not found in this tenant.” | Verify matches the principal exactly (e-mail, case-insensitive) against this tenant’s logins. The person is not yet a tenant user, or typed a different alias. | Add the user in Tenant Admin first, then verify again with the login e-mail. |
| Lines tab Month From / Month To hides lines that clearly belong to that month | The filter is applied to the line’s created date (created_date), not to the fiscal periods under it. | Clear the filter, or use the Cashflow Projection Report with a month range. |
| “Search keyword must more than 2 characters.” | The Program and Engagement listings reject free-text keywords shorter than three characters. | Type at least three characters, or use the advanced search fields. |
| Dashboard “Active Engagements” counts inactive ones | The dashboard sends no status to custom/query, so the backend returns every engagement not marked DELETED. | Set the process status or currency filters to narrow the set; there is no status filter on the dashboard. |
| Dashboard currency filter lacks the tenant’s currency | The Currency filter is a hard-coded list of 13 codes in dashboard-filters.component.ts, not the Forex list. | Leave the filter empty; the KPI and charts still group by whatever currency codes the engagements carry. |
| No PDF from EXPORT AS PDF / PRINT PDF | The button is disabled until a Printable Format is selected, and the list only contains formats registered under INTERNAL_SALES_INVOICE. A template built with invoice fields renders blank sections because the CFP print service supplies different parameters. | Upload a .jrxml built for the CFP parameters under Printable Format Settings, press SET DEFAULT, then export. |
| Only Program and Engagement can be hidden from the sidebar | gh:…#52 asked for Dashboard and both reports too; only HIDE_PROGRAM_MENU and HIDE_ENGAGEMENT_MENU were implemented. | Use server-side permissions (API_TNT_DM_ERP_CFP_FP_ENG_LINE_LINK_READ for the reports, …_ENGAGEMENT_HDR_READ for the dashboard) to deny access instead. |
Engagement listing feels slow and the browser console fills with [EngagementListing] DEBUG … | Leftover debug code fetches every engagement unpaged on grid init and logs each query and response. | Nothing to configure; it is in the shipped code. |
| No column view on the Program / Engagement sub-screens | Open issue gh:…#72 (the Member, Lines, Item tabs render inline rather than in the three-column stack). | Known limitation. |
Related documentation
- Financial Accounting module
- Customer Maintenance — customers, conglomerates
- Entity Maintenance — entity branches
- Tenant Admin Applet — tenant users for members
- Engagement Applet (CRM) — the other engagement register, not linked to this one