Skip to content

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.

Not to be confused with the Engagement Applet under CRM. That applet keeps an audit/assurance engagement register in its own tables; the engagements on this page live in bl_rvm_cfp_engagement_hdr and the two are not linked.
The applet was forked from the Sales Invoice applet (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

DirectionWhatWhy
BeforeCustomer MaintenanceThe 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.
BeforeEntity MaintenanceEntity Branch drop-downs read bl_fi_mst_entity_branch_hdr for the chosen entity.
BeforeForexCurrency drop-downs are the tenant’s bl_fi_mst_ccy list.
BeforeTenant AdminProgram and engagement members must already be users of the tenant; the Verify button looks them up by e-mail or phone.
InsideProgram → Engagement → Line → Fiscal PeriodThe hierarchy this applet owns; the dashboard and both reports aggregate the fiscal-period rows.
AfterNothingNo 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.

MenuRouteWhat opens
ProgramprogramProgram Listing → Create Program / Edit Program → Select Entity (a three-column view stack)
EngagementengagementCFP Engagement Listing → Create / Edit Engagement → Select Entity
Dashboarddashboard (also engagement/dashboard)Engagement Dashboard
Report → Cashflow Projection Reportcashflow-projection-reportMonth-by-month projection grid
Report → Collection Delay Reportcollection-delay-reportFiscal 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:

TabWhat it holds
Memberbl_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.
EngagementThe 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 Itembl_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).

Every time this listing’s grid initialises it also calls the unfiltered 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:

TabWhat it holds
Main DetailsEngagement 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.
AccountEntity 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.
LinesOnly 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.
MemberOnly 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.
ExportOnly 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 in dashboard-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, so INACTIVE engagements 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

PrerequisiteWhere it is setWhy it matters
Customers / entitiesCustomer MaintenanceThe Account tab and the Program Item form select from the customer listing. Conglomerates come from the same master.
Entity branchesEntity MaintenanceEntity Branch drop-downs list bl_fi_mst_entity_branch_hdr rows of the selected entity; without them the drop-down offers only – None –.
CurrenciesForexCurrency is required on an engagement (Validators.required on ccy_code); the list is the first 200 rows of bl_fi_mst_ccy.
Tenant usersTenant AdminMembers are app_login_subject records; Verify fails with User not found for anyone who is not yet a user of the tenant.
Server-side permissionsSettings → Permission Wizard / Permission Set / User Permission / Role Permission in this appletEvery 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 SettingsNeeded 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):

SettingWhereWhat it controlsDefaultEffect when changed
Hide Program (HIDE_PROGRAM_MENU)Application Settings → Sidebar MenuRemoves 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 MenuRemoves Engagement from the sidebar.offAs 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 DEFAULTThe format pre-selected in the Export tab of every engagement form.noneThe 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 SelectionSINGLE or DOUBLE column layout for the Program and Engagement view stacks. Also rewritten every time you press the column toggle in a listing.noneBoth 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, and HIDE_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_PRICEBOOK is read by app.component.ts, which loads the pricebook into the store, but no reachable component uses it; DATE_TXN_LOGIC is 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_ORIENTATION only matters when VERTICAL_ORIENTATION is 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:

KeyWhereEffect here
HIDE_CREATED_DATEApplication Settings → Advanced Search FilterHides the Created Date filter on the Program and Engagement listings.
HIDE_UPDATED_DATEApplication Settings → Advanced Search FilterHides 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):

AreaPermission familyNotes
ProgramAPI_TNT_DM_ERP_CFP_PROGRAM_HDR_*
Program memberAPI_TNT_DM_ERP_CFP_PROGRAM_MEMBER_*
EngagementAPI_TNT_DM_ERP_CFP_ENGAGEMENT_HDR_*READ also gates print-pdf and the dashboard’s custom/query.
Engagement lineAPI_TNT_DM_ERP_CFP_ENGAGEMENT_LINE_*
Engagement memberAPI_TNT_DM_ERP_CFP_ENGAGEMENT_MEMBER_*
Program itemAPI_TNT_DM_ERP_CFP_ENGAGEMENT_FI_ITEM_HDR_*
Fiscal period rowAPI_TNT_DM_ERP_CFP_FP_ENG_LINE_LINK_*READ gates both reports.
Fiscal period audit trailAPI_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

FieldMeaningRequiredNotes
Program CodeShort identifierYes on createFree 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 NameLabelYes on create
DescriptionFree textNo
StatusACTIVE / INACTIVEDefault ACTIVE. The Program listing filters on it.
Created Date / By, Updated Date / ByAuditRead-only, edit only.

Program — Member

FieldMeaningRequiredNotes
User email or phone numberLogin principal to look upYesVerify searches app_login_principal and keeps the exact (case-insensitive) match; the resolved subject’s main_email is shown as “Verified”.
RankADMIN, CONTRIBUTOR, VIEWERYesStored in role; the backend accepts any string. Nothing in the applet or backend grants or denies anything based on it.
StatusACTIVE / INACTIVEYes

Program — Program Item

FieldMeaningRequiredNotes
Item CodeIdentifierYesNo uniqueness check.
Item NameLabelYes
Item TypeSERVICE, PRODUCT, OTHERYesDefault SERVICE.
Currencybl_fi_mst_ccy codeNo
EntityThe client entityNoOpens Select Entity; loads that entity’s branches into the next field.
Entity BranchBranch of the chosen entityNoDisabled until an entity with branches is chosen.
Sales EntityA second entity referenceNoStored in sales_entity_hdr_guid; nothing reads it.
External PIC 01 / 02Contact names, free textNo
RemarkFree textNo
StatusACTIVE / INACTIVEDefault ACTIVE.

Engagement — Main Details

FieldMeaningRequiredNotes
Engagement TitleLabelYes on createFree text.
ProgramParent programNoFirst 200 programs of any status. Fixed and hidden when created from a program’s Engagement tab.
Conglomeratebl_fi_mst_entity_conglomerate_hdrNoFirst 200 rows.
BranchEntity branchNoNever populated on this tab; use the Account tab.
Currencybl_fi_mst_ccy codeYes on create
StatusACTIVE / INACTIVEDefault ACTIVE. Only ACTIVE engagements show on the Engagement menu.
Process StatusPENDING_REVIEW, APPROVED, DUPLICATE, REJECTED or noneNoThe 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

FieldMeaningRequiredNotes
TitleLabelYes
ValueAmount, numeric(70,22)NoSummed as “Total Value” on the Lines tab, as Engagement Value on the dashboard and as Total Project Value on the projection report.
Process StatusSame four labels as the headerNoStored as plain text on the line.
StatusACTIVE / INACTIVEYes

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)

FieldMeaningRequiredNotes
Fiscal YearInteger yearYesNo range check anywhere.
Fiscal MonthInteger monthYesNo 1–12 check anywhere; the reports build a column per month value they find in 1–12 only.
Fiscal DayInteger dayNo
Txn DateDateNoUsed only by the dashboard’s Fiscal Txn Date filter.
ARAP Open BalanceOpening receivable/payable balanceNoReported as “Open Bal” and “AR/AP Open”.
Target BillingPlanned billing for the periodNo
Target AdjustmentAdjustment to the planNoAdded to Target Billing to give Adjusted Target Billing.
Target CollectionPlanned collectionNo
Actual BillingWhat was billedNoTyped in — not read from invoices.
Actual CollectionWhat was collectedNoTyped in — not read from receipts.
RemarksFree textNoShown on the projection report’s detail rows only.
StatusACTIVE / INACTIVEYesReports 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

FieldMeaningRequiredNotes
User Email or Phone NumberLogin principalYesVerify 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 / RoleOWNER, ADMIN, MANAGER, MEMBER, GUEST, VISITOR, ANONYMOUSYesDefault MEMBER. Free text on the backend; grants nothing.
StatusACTIVE / INACTIVEYes

Lifecycle and effects

Posting proof

AspectValue
Server document typeNone. No bl_rvm_cfp_* table has a ServerDocTypes entry; the seven JournalPostingTypeHandler document types do not include any of them.
Amount signumNot applicable — no FinancialDocDataConsistencyObject exists for these tables. The eight Cfp*DataConsistencyObject classes validate structure only (guid, revision, status, audit subjects, dates).
Quantity signumNot applicable — no stock processor references this domain.
Dr/Cr equationNone. 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 precedenceNot applicable. No GL code is stored on any of the eight tables.
Stock processorNone.
What VOID reversesThere 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 INACTIVE instead. 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_trail has a full CRUD controller, but CfpFpEngLineLinkUow.update does 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:

ColumnFormula
Monthly Open Bal, Target Billing, Adjustment, Actual Billing, Target Collection, Actual CollectionSUM of the fiscal-period rows of the engagement for that month.
Monthly Adj. Target BillingSUM(target_billing + target_adjustment).
Monthly Outstanding Amount (returned, not shown in the monthly columns)SUM(target_collection − actual_collection).
Monthly RemarksAlways blank in the summary rows — the summary query does not return remarks; only the detail grid does.
Year totalsThe monthly figures summed over the selected months.
Total Project ValueSUM(value) of the engagement’s lines — all lines, regardless of year.
Project BalanceYear 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

SymptomCauseFix
Collection Delay Report is empty although fiscal-period rows have actual below targetThe 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 rowsSame 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 ReportThe 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 menuThe 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 CodeCreate 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 monthThe 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 onesThe 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 currencyThe 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 PDFThe 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 sidebargh:…#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-screensOpen issue gh:…#72 (the Member, Lines, Item tabs render inline rather than in the three-column stack).Known limitation.

Related documentation

Last updated on