Accounting Jobs Workflow
1. Executive Summary
Purpose
The Accounting Jobs workflow is the mechanism by which all financial events in UTA Client Payments are converted into double-entry subledger transactions for transmission to the enterprise General Ledger (GL). Every significant financial event — revenue recognition, billing, cash receipts, cash applications, payouts, FX adjustments, client ledger entries, and period-end AR true-ups — produces a balanced pair of debit and credit entries in the transaction table. These transactions are never created directly by users; they are generated by batch jobs that scan for unposted source records and produce grouped batches. The workflow also provides an Accounting Jobs Dashboard where administrators can trigger these jobs for a selected effective date, monitor the most recent execution of each job type, and inspect the resulting transaction ledger through four aggregated and detail views.
Scope
Covered:
- Running one or more batch accounting jobs against a selected effective date
- Setting the current fiscal period as part of job execution
- Viewing the last execution date for each job type on the dashboard
- Searching and filtering subledger transactions by class, source, account, period, client, entity, department, batch, and date
- Viewing transactions in four perspectives: Top Level crosstab (period × source × account), Client Level crosstab (period × source × client × rev ref × account), Rev Level crosstab (rev ref × account), and Transaction Detail flat list
- Drilling down from a crosstab cell into the matching Transaction Detail rows
- Reading job execution history from
accounting_job_execution_history
Not covered (documented separately):
- Revenue schedules — see the Billing Items workflow (billing-items.md) for how revenue items are created and scheduled
- Billing items and billing item details — see the Billing Items workflow for how billing items are created and due dates are set
- Cash receipts — see the Cash Receipts workflow (cash-receipts.md) for how receipts are posted and reach
CR-eligible status - Worksheets and cash applications — see the Worksheets workflow (worksheets.md) for the Apply step that makes applications eligible for the
APPjob - Settlements and payouts — see the Settlements workflow for the bank confirmation step that makes payouts eligible for the
POjob - GL transmission to the enterprise system — the
transaction.gl_status_cdlifecycle is defined in the data model but the actual GL transmission adapter is not yet implemented in the PoC
Key Objectives
- Provide a single, controlled point of entry for converting business events into balanced subledger journal entries
- Ensure idempotency: jobs can be safely re-run for the same effective date because prior transactions for the same source and date range are deleted before new ones are inserted
- Record an audit trail of every job execution (start time, end time, outcome, record counts) in
accounting_job_execution_history - Give accounting staff a multi-dimensional view of the transaction ledger for reconciliation and period-end close work
2. Process Overview
flowchart TD
A[User opens Accounting Jobs Dashboard] --> B[Select effective date]
B --> C[Select one or more job types]
C --> D[Submit: Run Selected Jobs]
D --> E[Set current fiscal period\nbased on effective date]
E --> F{For each selected job}
F --> G[REV: Revenue Recognition]
F --> H[BILL: Billing Posting]
F --> I[CR: Cash Receipt Posting]
F --> J[APP: Cash Application Posting]
F --> K[PO: Payout Posting]
F --> L[TRUE: AR True-Up]
F --> M[FX / CL: Not yet implemented]
G --> N[Cleanup prior transactions\nfor this source/date]
H --> N
I --> N
J --> N
K --> N
L --> N
N --> O[Reset source record posting status]
O --> P[Fetch eligible source records\nup to effective date]
P --> Q[Compute posting date per record\nusing posting date formula]
Q --> R[Generate debit/credit pairs\ngrouped by batch_id]
R --> S[Batch insert into transaction table]
S --> T[Mark source records as Posted]
T --> U[Record execution in\naccounting_job_execution_history]
U --> F
F --> V[Return summary to dashboard]
V --> W[Dashboard refreshes:\nlast execution dates updated]
W --> X[User searches transactions\nusing filter panel]
X --> Y{Select view tab}
Y --> |Top Level| Z[Period × Source × Account crosstab]
Y --> |Client Level| AA[Period × Source × Client × Rev Ref × Account crosstab]
Y --> |Rev Level| AB[Rev Ref × Account crosstab]
Y --> |Transaction Detail| AC[Flat transaction list]
Z --> AD[Click cell to drill down\ninto Transaction Detail]
AA --> AD
AB --> ADWalkthrough
Select effective date — The user enters an effective date on the dashboard. This date controls which fiscal period becomes "current" and determines the upper boundary for eligible source records across all jobs.
Select job types — The user checks one or more of the eight job type checkboxes:
REV,BILL,CR,APP,PO,FX,TRUE,CL. Each checkbox shows the effective date of the last successful execution for that job type, allowing the user to see which jobs are stale.Submit — The user clicks "Run Selected Jobs." The system first sets the current fiscal period by finding the
fiscal_periodrow whose date range contains the effective date, resetting all others to non-current.Jobs execute sequentially — Each selected job runs in order. A failure in one job is recorded but does not halt subsequent jobs. The common job pattern is: (a) delete prior transactions for the same source and date range, (b) reset source records to unposted, (c) fetch eligible records up to the effective date, (d) compute posting dates, (e) generate balanced debit/credit transaction pairs, (f) batch-insert transactions, (g) mark source records as posted.
Execution history recorded — After each job completes (successfully or not), one row is inserted into
accounting_job_execution_historywith the job code, effective date, start and end timestamps, outcome status, and result summary (counts or error details).Dashboard refreshes — On success, the dashboard re-fetches the last execution dates so each job checkbox shows the newly updated effective date.
Transaction search — Independently of job execution, the user can search the
transactionledger using a filter panel. All four dataset queries (enriched detail, top-level aggregation, rev-level aggregation, client-level aggregation) execute concurrently when the user clicks Search.Crosstab views — Three of the four tabs display transactions as dynamic crosstab grids with account names as column headers. Amounts in parentheses represent negative values. A pinned Total row at the top shows column sums.
Drill-down — Clicking any non-zero, non-total cell in a crosstab tab switches the active tab to Transaction Detail and re-fetches the flat transaction list with the crosstab row's dimensional filters (period, source, account class, account number, client, rev ref) added on top of the existing global filters.
3. Business Rules
3.1 Effective Date Sets the Current Fiscal Period
Business rule: Before any job runs, the system identifies the fiscal period whose date range contains the selected effective date and marks it as the current period (fiscal_period.current_ind = true). All other periods are set to false. If no fiscal period covers the effective date, the job run fails with an error before any transactions are created.
Foundation reference: Set Current Period and Run Jobs Step 1
Workflow context: The dashboard displays the current period's reference string, start date, and end date in a summary block below the effective date field. This gives the user immediate confirmation of which period will be active before submitting. If the effective date changes, the current period display updates reactively.
3.2 Jobs Are Idempotent via Delete-Before-Insert
Business rule: Each job deletes all prior transaction rows for its source_cd and posting date range (on or after the effective date) before inserting new ones. This means a job can be safely re-run for the same effective date without producing duplicate transactions.
Foundation reference: Accounting Procedures — each job's Cleanup Step
Workflow context: The "Run Selected Jobs" button can be clicked multiple times for the same date without data corruption. Users should understand that re-running a job regenerates all transactions for that source from the effective date forward — it does not append to prior runs.
3.3 At Least One Job Must Be Selected
Business rule: The form cannot be submitted without selecting at least one job type. An effective date alone is not sufficient to trigger a run.
Foundation reference: Run Jobs input validation
Workflow context: The "Run Selected Jobs" button submits the form. If no job checkboxes are checked, the server action returns an error message: "At least one job must be selected." No fiscal period change occurs, and no history record is created.
3.4 Posting Date Logic
Business rule: Transactions do not necessarily post on the date their source record was created. If a source record's creation date is earlier than its business event date (the "driver date"), the transaction posts on the first day of the fiscal period containing the driver date. If the creation date is on or after the driver date, the transaction posts on the creation date. This prevents retroactive entries from landing in the wrong period.
Foundation reference: Posting Date Determination
3.5 Batches Must Balance (Net to Zero)
Business rule: All transaction rows sharing a batch_id must have their debit amounts equal their credit amounts (total nets to zero). Every accounting job produces exactly two transaction rows per source record: one debit and one credit. The batch ID groups these two rows together.
Foundation reference: Batch must net to zero validation and Batch ID Generation
3.6 REV Applications Post Immediately; PAY Payouts Post Only After Bank Confirmation
Business rule: Cash application transactions (APP job) are created as soon as a worksheet reaches Applied status, because REV money stays in UTA accounts. Payout transactions (PO job) are created only after the bank confirms the payment has been sent (payment_item.payment_execution_status_cd is ACKNOWLEDGED or PAID), because the money must physically leave the building before the GL entry is made.
Foundation reference: APP vs PO posting timing
IMPORTANT
This two-stage timing distinction is critical to the reversal model. A payment that was never sent never had a GL entry posted for it, so its reversal must not post to GL either. See the CLAUDE.md domain notes for the full explanation.
3.7 Jobs Execute Sequentially; Failures Are Isolated
Business rule: When multiple jobs are selected, they execute in sequence (not in parallel). A failure in one job is recorded in accounting_job_execution_history with status_cd = 'FAILED', but subsequent jobs in the same run continue to execute. The overall run does not abort on a single job failure.
Foundation reference: Run Jobs Step 2
Workflow context: The result summary displayed after a run lists each job's outcome (e.g., "REV: 42 processed, BILL: Failed (No eligible records), CR: 7 processed"). A toast notification indicates overall success or failure.
3.8 Only Active Accounts Receive New Postings
Business rule: Only account rows with account.status_cd = 'A' (Active) are valid targets for new transaction postings. Inactive accounts (status_cd = 'I') cannot receive new entries, though existing transactions referencing them are unaffected.
Foundation reference: Active-only posting
3.9 AR True-Up Job Requires REV and BILL Jobs to Have Run First
Business rule: The TRUE job computes adjustments by reading existing transaction rows for each distinct rev_ref in the current period. If neither REV nor BILL has run for the current period, the TRUE job will find no candidates and produce no transactions. The recommended execution order for a full period-end close is: REV → BILL → CR → APP → PO → TRUE.
Foundation reference: AR True-Up Job
3.10 Transaction Search Results Are Capped at 1,000 Rows
Business rule: The Transaction Detail tab returns at most 1,000 raw transaction rows per search. Aggregated crosstab views have no row limit because they group transactions before returning them.
Foundation reference: searchTransactionsEnriched
Workflow context: Users who need to view more than 1,000 transactions should narrow their filter criteria (e.g., restrict the period range or source code) to reduce result size.
4. Data Access & Operations References
4.1 Queries Used
| Operation | Foundation Doc | Purpose in This Workflow |
|---|---|---|
getCurrentPeriod | Get Current Period | Load current fiscal period on dashboard page entry to display period summary below the effective date field |
getLastExecutions | Get Last Executions | Load the most recent execution date for each job type to display next to each job checkbox |
searchTransactionsEnriched | Search Transactions Enriched | Power the Transaction Detail tab; returns up to 1,000 enriched rows with resolved account, client, department, and entity names |
getAggregatedTransactions | Get Aggregated Transactions | Power the Top Level crosstab tab; groups transactions by period, source, and account |
getRevLevelAggregatedTransactions | Get Rev Level Aggregated Transactions | Power the Client Level crosstab tab; groups transactions by period, source, client, rev ref, and account |
getRevenueLevelAggregatedTransactions | Get Revenue Level Aggregated Transactions | Power the Rev Level crosstab tab; groups transactions by rev ref and account only |
searchAccounts | Search Accounts | Drive the Account autocomplete filter; returns up to 20 matching accounts by name or number |
getAllPeriods | Get All Periods | Load all fiscal periods into memory at the start of each job for efficient in-memory date-to-period matching |
4.2 Procedures Used
| Operation | Foundation Doc | Trigger in This Workflow |
|---|---|---|
runJobs | Job Orchestration | User submits the Run Selected Jobs form with an effective date and one or more job types |
setCurrentPeriod | Set Current Period | Called automatically as Step 1 of every runJobs execution |
runRevJob | Revenue Recognition Job (REV) | User selects REV checkbox and submits; dispatched by runJobs |
runBillJob | Billing Posting Job (BILL) | User selects BILL checkbox and submits; dispatched by runJobs |
runCashReceiptJob | Cash Receipt Posting Job (CR) | User selects CR checkbox and submits; dispatched by runJobs |
runCashReceiptApplicationJob | Cash Application Posting Job (APP) | User selects APP checkbox and submits; dispatched by runJobs |
runPayoutJob | Payout Posting Job (PO) | User selects PO checkbox and submits; dispatched by runJobs |
runTrueUpJob | AR True-Up Job (TRUE) | User selects TRUE checkbox and submits; dispatched by runJobs |
createJobExecution | Create Job Execution | Called automatically after each job completes (success or failure) to write the history record |
5. Key User Actions
5.1 Run Accounting Jobs
Preconditions:
- At least one fiscal period must exist in
fiscal_periodthat covers the selected effective date - At least one job type checkbox must be checked
- The user must have IT role access (only IT may execute accounting jobs — see Section 6)
Procedure reference: Job Orchestration
Steps:
- User enters an effective date in the date field. The current fiscal period summary updates to show the period that would become current.
- User checks one or more job type checkboxes. Each checkbox optionally shows the effective date of its last successful run.
- User clicks "Run Selected Jobs." The button label changes to "Processing Jobs..." and becomes disabled while the run is in progress.
- The system sets the current fiscal period, then executes each selected job sequentially per the procedures referenced above.
- On completion, the dashboard displays a summary message listing each job's outcome and record counts.
Postconditions:
fiscal_period.current_ind = trueon the period matching the effective date; all other periods havecurrent_ind = false- One
accounting_job_execution_historyrow inserted per dispatched job, withstatus_cdofSUCCESSorFAILED - For each successfully run job: new balanced
transactionrows inserted withgl_status_cd = 'U'; prior transactions for the same source/date range deleted; source records updated to posted status - The "last run" date next to each executed job checkbox updates to the effective date
UI trigger: "Run Selected Jobs" button in the Run Accounting Jobs panel. Enabled when at least one job checkbox is checked. Disabled while the form is submitting.
5.2 Search Transactions
Preconditions:
- The Transaction section is always visible on the Accounting Jobs Dashboard
- No jobs need to have run first — the search panel queries existing transactions
Procedure reference: searchTransactionsEnriched, getAggregatedTransactions, getRevLevelAggregatedTransactions, getRevenueLevelAggregatedTransactions
Steps:
- User sets one or more filter values in the filter panel (see Section 8 for filter fields).
- User clicks the "Search" button or presses Enter.
- All four dataset queries execute concurrently: enriched transaction list, top-level aggregation, client-level aggregation, and revenue-level aggregation.
- Results populate all four tabs simultaneously. The currently active tab updates first.
Postconditions:
transactionsstate updated with up to 1,000 enrichedtransactionrows matching the filtersaggregatedTransactions,revLevelTransactions, andclientLevelTransactionsstates updated with aggregated rows
UI trigger: "Search" button in the Transactions section filter panel. Enabled at all times. Also triggered by pressing Enter while focus is in any filter field.
5.3 Drill Down from Crosstab to Transaction Detail
Preconditions:
- A Search has been performed and crosstab data is populated
- The user is viewing the Top Level, Client Level, or Rev Level tab
- The target cell must be non-zero and must not be the Total row
Procedure reference: searchTransactionsEnriched
Steps:
- User clicks an amount cell in the Top Level, Client Level, or Rev Level crosstab.
- The dashboard automatically switches to the Transaction Detail tab.
- A new enriched transaction search executes with the crosstab row's dimensional filters (period ref, source code, account class, account number, and optionally client name or rev ref) merged with any existing global filter values.
- Drill-down active filters appear as removable badge chips above the tab list.
Postconditions:
activeTabstate set to'transactions'activeDrillDownFiltersstate set to the dimensional filters from the clicked celltransactionsstate updated with the matching enriched transaction rows
UI trigger: Clicking any non-zero, non-total amount cell in the Top Level, Client Level, or Rev Level crosstab. Each clickable cell renders as a button with hover underline styling.
5.4 Clear Drill-Down Filters
Preconditions:
- Active drill-down filters are present (the user has previously drilled down from a crosstab cell)
Procedure reference: searchTransactionsEnriched
Steps:
- User clicks "Clear All" to remove all drill-down filters at once, or clicks the "×" on an individual filter badge to remove that single filter dimension.
- The Transaction Detail tab re-fetches using only the remaining global filters (no drill-down context).
Postconditions:
activeDrillDownFiltersstate cleared (null) or reduced by the removed keytransactionsstate updated with results using only global filters
UI trigger: "Clear All" button visible next to drill-down badge chips when activeDrillDownFilters is non-null. Individual "×" buttons on each badge chip.
6. Permissions & Role-Based Access
| Action | CASH_MANAGER | CASH_PROCESSOR | SETTLEMENT_APPROVER | IT |
|---|---|---|---|---|
| Run accounting jobs (submit the jobs form) | — | — | — | Yes |
| View Accounting Jobs Dashboard | — | — | — | Yes |
| Search and view transactions | — | — | — | Yes |
| View job execution history (last run dates) | — | — | — | Yes |
Field-level restrictions:
- The Accounting Jobs Dashboard and all accounting job operations are restricted to the
ITrole. No other role can access this screen or trigger batch job execution. - In the PoC, role enforcement is not fully implemented at the server action layer for this feature. The production system must enforce IT-only access on the
runAccountingJobsActionserver action and on the page route.
**PoC Artifact:**
The PoC does not enforce role-based access control on the Accounting Jobs Dashboard page or the runAccountingJobsAction server action. Any authenticated user can access the dashboard and trigger jobs. The production system must add IT-only authorization before shipping.
7. Integration Points
7.1 Upstream
| Source | Data Provided | Mechanism |
|---|---|---|
| Revenue schedules workflow | revenue_item_schedule rows with revenue_item_posting_status_cd = 'U' and revenue_dt <= effective_date — inputs to the REV job | FK reference: transaction.source_id → revenue_item_schedule.revenue_item_schedule_id |
| Billing items workflow | billing_item_detail rows with posting_status_cd = 'U' and parent billing_item.billing_item_due_dt <= effective_date — inputs to the BILL job | FK reference: transaction.source_id → billing_item_detail.billing_item_detail_id |
| Cash receipts workflow | cash_receipt rows with posting_status_cd = 'U' — inputs to the CR job | FK reference: transaction.source_id → cash_receipt.cash_receipt_id |
| Worksheets workflow | cash_receipt_application rows with billing_item_detail_type_cd = 'REV' from worksheets at Applied (P) or Returned (R) status — inputs to the APP job | FK reference: transaction.source_id → cash_receipt_application.cash_receipt_application_id |
| Worksheets workflow | cash_receipt_client_ledger rows from Applied worksheets — inputs to the CL job | FK reference: transaction.source_id → cash_receipt_client_ledger.cash_receipt_client_ledger_id |
| Settlements / Payments workflow | payment_item rows with payment_execution_status_cd IN (ACKNOWLEDGED, PAID) — inputs to the PO job | FK reference: transaction.source_id → payment_item.payment_item_id |
| Transaction table (self) | Existing transaction rows with matching rev_ref — used by the TRUE job to compute Deferred/Unbilled balances for AR true-up | Aggregated by transaction.rev_ref and account.account_class |
7.2 Downstream
| Consumer | Data Consumed | Mechanism |
|---|---|---|
| Enterprise GL system | transaction rows with gl_status_cd = 'U' — awaiting transmission | GL posting batch reads unposted transactions; sets gl_status_cd = 'P' and gl_posting_dt on success |
| AR Aging report | transaction rows — particularly BILL-sourced AR entries and APP-sourced applications | Direct query of transaction table filtered by source_cd and class_cd |
7.3 External Integrations
No external integrations for this workflow. The Accounting Jobs Dashboard is an internal operational tool. GL transmission to the enterprise system is a downstream process triggered separately outside this workflow.
8. Functional Screen Requirements
8.1 Accounting Jobs Dashboard
Route: /accounting/accounting-jobs
Data loading:
getCurrentFiscalPeriodAction— loads the current fiscal period on mount to display the period summary; see Get Current PeriodgetLastJobExecutionsAction— loads one execution summary row per job type to display last-run dates next to each checkbox; see Get Last ExecutionssearchUtaEntitiesAction— loads UTA entity options for the Entity multi-select filter in the Transactions section
Run Accounting Jobs Panel
Displays a form for selecting an effective date and one or more batch job types to execute.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Effective Date | User input; defaults to today's date | Yes | Always visible |
| Current period summary (Period ref, Start, End) | fiscal_period.period_ref, fiscal_period.period_start_dt, fiscal_period.period_end_dt | No | Visible when a fiscal period exists for the effective date |
| REV — Revenue Job checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| BILL — Billing Job checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| CR — Cash Receipt checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| APP — Cash Application checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| PO — Payouts checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| FX — FX Adjustment checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| TRUE — AR True-Up checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| CL — Client Ledger Job checkbox | Static job definition; last run date from accounting_job_execution_history.effective_dt | Yes | Always visible |
| Last Job Status message | accounting_job_execution_history.result_summary (rendered after submit) | No | Visible after a run has completed in this session |
Conditional display:
- Current period summary block visible only when the effective date maps to an existing
fiscal_periodrow - "Processing Jobs..." label and disabled state on the Run button while the form submission is in flight
- Last Job Status block visible only after the form has been submitted at least once in the current session
- Each job checkbox shows a parenthetical last-run date (formatted as local date) when
accounting_job_execution_historyhas a record for thatjob_cd
Transactions Filter Panel
Provides filter controls that drive all four transaction view tabs simultaneously.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Class Cd (multi-select) | Options: REV, AR, CASH, TAX, FX — matches transaction.class_cd | Yes | Always visible |
| Source Cd (multi-select) | Options: REV, BILL, CR, APP, PO, FX, TRUE, CL — matches transaction.source_cd | Yes | Always visible |
| Parent Ref | Free text — case-insensitive substring match on transaction.rev_ref | Yes | Always visible |
| Source Ref | Free text — case-insensitive substring match on transaction.source_ref | Yes | Always visible |
| Account | Autocomplete — resolves to transaction.account_id; searches account.account_full_name and account.account_number | Yes | Always visible |
| Posting From | Date input — lower bound on transaction.posting_dt (inclusive) | Yes | Always visible |
| Posting To | Date input — upper bound on transaction.posting_dt (inclusive) | Yes | Always visible |
| Client | Client search autocomplete — resolves to transaction.client_id | Yes | Always visible |
| Entity (multi-select) | Loaded from uta_entity — matches transaction.uta_entity_id | Yes | Always visible |
| Dept | Department autocomplete — resolves to transaction.department_id | Yes | Always visible |
| Period Ref From | Free text in YYYY-MM format — lower bound on transaction.posting_period_ref (inclusive) | Yes | Always visible |
| Period Ref To | Free text in YYYY-MM format — upper bound on transaction.posting_period_ref (inclusive) | Yes | Always visible |
| Batch ID | Free text — case-insensitive substring match on transaction.batch_id | Yes | Always visible |
| Search button | — | — | Always visible |
Grid features:
- No grid in the filter panel itself — it drives the tab grids below
- Pressing Enter while focused in any filter field triggers the Search action
Conditional display:
- All filters are always visible; none are conditionally shown or hidden
- The Search button shows "Searching..." and is disabled while queries are in flight
Top Level Crosstab Tab
Displays transactions aggregated by fiscal period and source job, with one dynamic column per unique account class-number combination found in the result set.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Fiscal Period | fiscal_period.period_ref (via transaction.posting_period_id) | No | Always visible |
| Source | transaction.source_cd | No | Always visible |
| [Account Class]-[Account Number] (dynamic, one column per unique account) | SUM(transaction.trans_amt) grouped by period, source, account.account_class, account.account_number | No | Column appears when at least one matching transaction exists for that account |
| Total row | Sum of all rows per account column | No | Pinned at the top of the grid |
Grid features:
- Sortable columns: Fiscal Period, Source, all account columns
- Filters: None (global filters applied via the filter panel above)
- Row selection: None
- Pagination: Yes
- Column ordering: User can reorder columns
- Amounts displayed with currency formatting; negative amounts shown in parentheses (e.g.,
($1,234.56))
Conditional display:
- Amount cells in the Total row are not clickable (not drill-down targets)
- Amount cells with value
0are not clickable - Non-zero, non-total amount cells are clickable drill-down triggers that switch to the Transaction Detail tab
Client Level Crosstab Tab
Displays transactions aggregated at the most granular level: fiscal period, source job, client name, and revenue reference, with one dynamic column per unique account.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Fiscal Period | fiscal_period.period_ref | No | Always visible |
| Source | transaction.source_cd | No | Always visible |
| Client | party.display_name (via transaction.client_id) | No | Always visible |
| Rev Ref | transaction.rev_ref | No | Always visible |
| [Account Class]-[Account Number] (dynamic) | SUM(transaction.trans_amt) grouped by period, source, client, rev ref, and account | No | Column appears when at least one matching transaction exists |
| Total row | Sum of all rows per account column | No | Pinned at the top of the grid |
Grid features:
- Sortable columns: Fiscal Period, Source, Client, Rev Ref, all account columns
- Filters: None (global filters applied via filter panel)
- Row selection: None
- Pagination: Yes
- Column ordering: User can reorder columns
Conditional display:
- Same clickable cell behavior as Top Level: Total row and zero-value cells are not drill-down targets; all others are
Rev Level Crosstab Tab
Displays transactions aggregated by revenue reference only, with one dynamic column per unique account. Useful for tracing all postings against a specific deal or revenue item across all periods.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Rev Ref | transaction.rev_ref | No | Always visible |
| [Account Class]-[Account Number] (dynamic) | SUM(transaction.trans_amt) grouped by rev ref and account | No | Column appears when at least one matching transaction exists |
| Total row | Sum of all rows per account column | No | Pinned at the top of the grid |
Grid features:
- Sortable columns: Rev Ref, all account columns
- Filters: None (global filters applied via filter panel)
- Row selection: None
- Pagination: Yes
- Column ordering: User can reorder columns
Conditional display:
- Same clickable cell behavior as Top Level
Transaction Detail Tab
Displays the raw enriched transaction list, one row per transaction record, up to 1,000 rows.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| ID | transaction.transaction_id | No | Always visible |
| Posting Date | transaction.posting_dt | No | Always visible |
| Ref Date | transaction.transaction_ref_dt | No | Always visible |
| Class | transaction.class_cd | No | Always visible |
| Source | transaction.source_cd | No | Always visible |
| Rev Ref | transaction.rev_ref | No | Always visible; rendered as a hyperlink to /revenue?salesItemRef=[value] when non-null |
| Ref | transaction.source_ref | No | Always visible; for BILL and APP source codes, the link resolves using transaction.rev_ref as the lookup value rather than source_ref itself |
| Amount | transaction.trans_amt | No | Always visible; rendered right-aligned with debit/credit type indicator in parentheses; positive entries shown in green, reversal entries (transaction.reverse_ind = true) shown in red |
| Client | party.display_name (via transaction.client_id) | No | Always visible; rendered as hyperlink to /clients/[client_id]?tab=revenue when client_id is non-null |
| Dept | department.name (via transaction.department_id) | No | Always visible |
| Account | account.account_full_name (via transaction.account_id) | No | Always visible; falls back to transaction.account_id when name is unavailable |
| Entity | uta_entity.name (via transaction.uta_entity_id) | No | Always visible; falls back to transaction.uta_entity_id |
| Batch ID | transaction.batch_id | No | Always visible |
Grid features:
- Sortable columns: ID, Posting Date, Ref Date, Class, Source, Rev Ref, Ref, Amount, Client, Dept, Account, Entity, Batch ID
- Filters: None (global filters and drill-down filters applied via filter panel and drill-down action)
- Row selection: None
- Pagination: Yes (standard page size)
Conditional display:
- When drill-down filters are active, a row of removable badge chips appears above the tab list showing each active drill-down dimension (e.g.,
periodRef: 2026-01,sourceCd: REV) - "Clear All" button appears next to the badge chips when drill-down filters are active
- Each badge chip has an "×" to remove that individual dimension and re-run the search
9. Additional Diagrams
Job Execution State Diagram
stateDiagram-v2
[*] --> RUNNING : Job dispatched by runJobs
RUNNING --> SUCCESS : Job completes without error
RUNNING --> FAILED : Job throws unhandled exception
SUCCESS --> [*]
FAILED --> [*]Jobs do not retry automatically. A failed job must be re-run manually by the user.
Transaction GL Status Lifecycle
stateDiagram-v2
[*] --> U : Created by accounting job\n(gl_status_cd = 'U')
U --> P : GL transmission succeeds\n(gl_posting_dt set)
U --> X : Manually excluded
U --> F : GL transmission fails
F --> P : Retry succeeds
F --> X : Manually excluded after failureAll new transactions start in state U (Unposted). The progression to P (Posted) is performed by a separate GL transmission batch outside the scope of this workflow.
Recommended Job Execution Order for Period-End Close
flowchart LR
A[REV\nRevenue Recognition] --> B[BILL\nBilling Posting]
B --> C[CR\nCash Receipt Posting]
C --> D[APP\nCash Application Posting]
D --> E[PO\nPayout Posting]
E --> F[TRUE\nAR True-Up]
G[CL\nClient Ledger] --> FREV and BILL must precede TRUE because the true-up job reads their transaction output. APP must precede TRUE because application transactions affect Deferred/Unbilled balances. CL and PO can be run before TRUE but are independent of the REV/BILL ordering constraint.
10. Cross-References
| Document | Relationship |
|---|---|
| Accounting Data Model | Defines transaction, account, fiscal_period, and accounting_job_execution_history — all four tables used in this workflow |
| Accounting Queries | Specifies all read operations: transaction search variants, aggregation queries, account search, fiscal period queries, and job history queries |
| Accounting Procedures | Specifies all eight batch job procedures: REV, BILL, CR, APP, PO, TRUE, FX (not implemented), CL (not implemented); plus the job orchestration and fiscal period management procedures |
| Cash Receipts Workflow | Upstream: posted cash_receipt records are the source records for the CR job |
| Worksheets Workflow | Upstream: REV-type cash_receipt_application records from Applied worksheets are source records for the APP job; cash_receipt_client_ledger records are source records for the CL job |
| Settlements Workflow | Upstream: payment_item records with bank-confirmed execution status are source records for the PO job |
| Billing Items Workflow | Upstream: billing_item_detail records and revenue_item_schedule records are source records for the BILL and REV jobs respectively |
11. Gherkin Scenarios
Feature: Accounting Jobs - Job Execution
Scenario: Successful multi-job run sets fiscal period and creates transactions
Given fiscal_period rows exist for 2026-03 with period_start_dt = '2026-03-01' and period_end_dt = '2026-03-31'
And revenue_item_schedule rows exist with revenue_item_posting_status_cd = 'U' and revenue_dt <= '2026-03-15'
And billing_item_detail rows exist with posting_status_cd = 'U' and parent billing_item.billing_item_due_dt <= '2026-03-15'
When the user submits the Run Accounting Jobs form with effective_date = '2026-03-15' and job_types = ['REV', 'BILL']
Then fiscal_period.current_ind = true for the period with period_ref = '2026-03'
And all other fiscal_period.current_ind values are set to false
And two transaction rows (debit account_id = 1, credit account_id = 13) are inserted per eligible revenue_item_schedule with gl_status_cd = 'U'
And two transaction rows (debit account_id = 4, credit account_id = 6) are inserted per eligible billing_item_detail with gl_status_cd = 'U'
And two accounting_job_execution_history rows exist with job_cd IN ('REV', 'BILL') and status_cd = 'SUCCESS' and effective_dt = '2026-03-15'
And the REV job checkbox on the dashboard shows last run date '2026-03-15'
Scenario: Job run is idempotent — re-running deletes and regenerates transactions
Given accounting jobs REV and BILL were previously run with effective_date = '2026-03-10'
And transaction rows exist with source_cd = 'REV' and posting_dt = '2026-03-01'
And transaction rows exist with source_cd = 'BILL' and posting_dt = '2026-03-01'
When the user re-submits the Run Accounting Jobs form with effective_date = '2026-03-15' and job_types = ['REV', 'BILL']
Then all prior transaction rows with source_cd = 'REV' and posting_dt >= '2026-03-15' are deleted before new rows are inserted
And all prior transaction rows with source_cd = 'BILL' and posting_dt >= '2026-03-15' are deleted before new rows are inserted
And the resulting transaction count matches the current count of eligible source records up to '2026-03-15'
And no duplicate transaction rows exist for the same source_id
Scenario: Job run fails when no fiscal period covers the effective date
Given no fiscal_period row exists with period_start_dt <= '2026-06-15' and period_end_dt >= '2026-06-15'
When the user submits the Run Accounting Jobs form with effective_date = '2026-06-15' and job_types = ['REV']
Then the system returns an error: "Failed to set current fiscal period"
And no transaction rows are inserted
And no accounting_job_execution_history row is created
Scenario: Submitting with no job types selected returns an error
Given fiscal_period rows exist for 2026-03
When the user submits the Run Accounting Jobs form with effective_date = '2026-03-15' and no job_types selected
Then the system returns an error: "At least one job must be selected"
And fiscal_period.current_ind is not changed
And no accounting_job_execution_history row is created
Feature: Accounting Jobs - Transaction Search and Filtering
Scenario: Searching by source code returns only matching transactions
Given transaction rows exist with source_cd = 'REV' for client "Taylor Swift" and source_cd = 'APP' for client "Drake"
When the user sets Source Cd filter to ['REV'] and clicks Search
Then the Transaction Detail tab displays only transaction rows with transaction.source_cd = 'REV'
And the Top Level crosstab shows only REV-sourced amounts per period per account
And no APP-sourced rows appear in any tab
Scenario: Drilling down from a Top Level crosstab cell filters Transaction Detail
Given a search has returned aggregated data with a non-zero amount in period '2026-03', source 'REV', account class 'Revenue', account number '1300'
When the user clicks that amount cell in the Top Level crosstab
Then the active tab switches to 'transactions'
And a new enriched transaction search is executed with added filters: periodRef = '2026-03', sourceCd = 'REV', accountClass = 'Revenue', accountNumber = '1300'
And activeDrillDownFilters badge chips show 'periodRef: 2026-03', 'sourceCd: REV', 'accountClass: Revenue', 'accountNumber: 1300'
Scenario: Removing a drill-down filter badge re-fetches with remaining filters
Given the user has drilled down with activeDrillDownFilters = { periodRef: '2026-03', sourceCd: 'REV', accountClass: 'Revenue', accountNumber: '1300' }
When the user clicks "×" on the 'sourceCd: REV' badge chip
Then the Transaction Detail tab re-fetches with filters: periodRef = '2026-03', accountClass = 'Revenue', accountNumber = '1300' (no sourceCd filter)
And the 'sourceCd' badge chip is no longer displayed
Scenario: Transaction search result is capped at 1,000 rows
Given more than 1,000 transaction rows exist with source_cd = 'REV'
When the user searches with Source Cd filter = ['REV'] and no other filters
Then the Transaction Detail tab displays exactly 1,000 rows
And the Top Level and other aggregation tabs continue to show full totals (no row limit on aggregated queries)
Feature: Accounting Jobs - Posting Date Logic
Scenario: Revenue schedule created before its revenue date posts to start of revenue period
Given a revenue_item_schedule row exists with created_dt = '2026-01-15' and revenue_dt = '2026-03-10'
And fiscal_period row exists for 2026-03 with period_start_dt = '2026-03-01'
When the REV job runs with effective_date = '2026-03-15'
Then the resulting transaction rows have posting_dt = '2026-03-01'
And transaction.transaction_ref_dt = '2026-03-10'
And transaction.posting_period_ref = '2026-03'
Scenario: Revenue schedule created after its revenue date posts to the creation date
Given a revenue_item_schedule row exists with created_dt = '2026-03-12' and revenue_dt = '2026-03-10'
When the REV job runs with effective_date = '2026-03-15'
Then the resulting transaction rows have posting_dt = '2026-03-12'
And transaction.transaction_ref_dt = '2026-03-10'
Feature: Accounting Jobs - PAY vs REV Posting Timing
Scenario: APP job creates transactions for REV-type applications only
Given a cash_receipt_worksheet with worksheet_status_cd = 'P' (Applied)
And the worksheet has cash_receipt_application rows: one with billing_item_detail_type_cd = 'REV' and one with billing_item_detail_type_cd = 'PAY'
When the APP job runs with effective_date = '2026-03-15'
Then transaction rows are created for the REV-type application (source_cd = 'APP')
And no transaction rows are created for the PAY-type application
Scenario: PO job creates transactions only for bank-confirmed payouts
Given payment_item rows exist: one with payment_execution_status_cd = 'ACKNOWLEDGED' and one with payment_execution_status_cd = 'PENDING'
When the PO job runs with effective_date = '2026-03-15'
Then transaction rows (source_cd = 'PO') are created only for the payment_item with payment_execution_status_cd = 'ACKNOWLEDGED'
And no transaction rows are created for the PENDING payment_item