Invoicing Workflow
1. Executive Summary
Purpose
The Invoicing workflow enables UTA finance staff to generate formal payment request documents from billing items and transmit them to buyers or clients. An invoice is the mechanism by which UTA communicates what is owed: either a Commission invoice sent to a client for UTA's revenue share (REV), or a Total Due invoice sent to a buyer for the full amount owed under a deal (PAY). This workflow sits downstream of deal and billing item creation and upstream of cash receipt matching — once billing items have been created and their amounts confirmed from the deal engine, invoicing converts those receivables into outbound payment requests. Generated invoices are tracked through a lifecycle (DRAFT → ISSUED → PAID → VOID) and produce PDF documents that include payment instructions drawn from bank detail configuration.
Scope
Covered:
- Browsing billing item details that have not yet been invoiced, filtered by recipient type and invoice type
- Selecting billing item details for invoicing, individually or in bulk
- Generating invoice records with automatic grouping by UTA entity, currency, recipient, and (where applicable) client
- Automatic sequential invoice number generation per UTA entity per calendar year
- PDF generation and download for any existing invoice
- Viewing the full list of generated invoices with status filtering
Not covered (documented separately):
- Billing item creation and management — see Billing Items Workflow
- Statement generation (client statements, settlement statements, AR aging) — see Statements Workflow
- Cash receipt matching that transitions an invoice to Paid status — see Worksheets Workflow
- Write-offs of uncollectable receivables — see Write-Offs Workflow
Key Objectives
- Produce unique, well-formatted invoice documents for each UTA entity's outstanding billing items
- Enforce grouping rules that keep each invoice scoped to one entity, one currency, and (for UK entities) one client
- Prevent the same billing item detail from being invoiced twice under the same document type
- Provide downloadable PDF invoices with the correct bank payment instructions for the issuing entity and currency
2. Process Overview
flowchart TD
A([Billing items exist without billing_item_document links]) --> B[User opens Generate Invoices screen]
B --> C[User selects Invoice Recipient and Invoice Type filters]
C --> D[System loads uninvoiced billing item details matching the filter]
D --> E[User selects one or more billing item details]
E --> F{Items selected?}
F -->|No| E
F -->|Yes| G[System previews invoice count based on grouping]
G --> H[User clicks Generate Invoice]
H --> I[System validates all selected details match invoice type]
I --> J{Validation passed?}
J -->|No| K[Error returned — generation aborted]
J -->|Yes| L[System groups items into invoice batches by entity, currency, recipient, client]
L --> M[For each batch: generate invoice number, calculate totals, insert invoice record]
M --> N[For each batch: insert billing_item_document links]
N --> O[Invoice records created with status DRAFT]
O --> P[Selected items removed from available-for-invoicing list]
P --> Q([User downloads PDF from Invoice List])Walkthrough
Filter and load — The user opens the Generate Invoices screen and selects an Invoice Recipient (
CLIENTorBUYER) and an Invoice Type (COMMISSIONorTOTAL_DUE). The system loads only billing item details of the correspondingbilling_item_detail_type_cd(REVfor Commission,PAYfor Total Due) that have no existingbilling_item_documentlink of the matching document type.Browse the grouped table — Loaded billing items are displayed in a collapsible hierarchy: Level 1 groups by client or buyer (matching the selected recipient), Level 2 sub-groups by UTA entity and currency, and Level 3 (for Buyer recipient without Multi-Client, or for UK entities regardless) further sub-groups by client. Each level has a checkbox for bulk selection. The system shows a live count of how many invoices the current selection will produce.
Select items — The user checks individual rows, client sub-group rows (Level 3), entity/currency sub-group rows (Level 2), or recipient group rows (Level 1). The live invoice count updates to reflect how many discrete invoice batches the selection spans.
Generate — The user clicks Generate Invoice. The system validates that all selected details match the chosen invoice type, groups them into batches by entity/currency/recipient/client rules, generates a sequential invoice number per batch, inserts each invoice record with
status_cd = 'DRAFT', and writesbilling_item_documentbridge rows to mark those billing items as invoiced.View and download — The user navigates to the Invoice List screen, optionally filters by status, and downloads a PDF for any invoice. The PDF renders line items, totals, payment instructions, and addresses.
3. Business Rules
3.1 Each Invoice Covers Exactly One UTA Entity
Business rule: All billing item details on a single invoice must belong to the same UTA entity (billing_item.uta_entity_id). Items from different entities cannot be combined.
Foundation reference: Generate Invoices — Step 3: Group Items into Invoice Batches
Workflow context: The billing item table groups automatically by UTA entity at Level 2 (the sub-group row). Selecting items across multiple entity sub-groups under the same Level 1 recipient group produces multiple invoices, one per entity.
3.2 Each Invoice Covers Exactly One Currency
Business rule: All billing item details on a single invoice must share the same currency_cd. Items in different currencies generate separate invoices.
Foundation reference: Generate Invoices — Step 3: Group Items into Invoice Batches
Workflow context: Currency is part of the Level 2 sub-group display label (e.g., "UTA US Entity — USD"). Items in USD and GBP for the same buyer produce two invoices.
3.3 UK Entity: Always One Client Per Invoice
Business rule: When the issuing UTA entity is the UK entity (entity ID = 2), each invoice may contain billing items for only one client, regardless of the Multi-Client Invoice setting.
Foundation reference: Generate Invoices — Step 3: Group Items into Invoice Batches
Workflow context: For UK entity sub-groups in Buyer recipient mode, the table always shows a Level 3 client sub-group layer. The Multi-Client Invoice checkbox has no effect on UK entity batches. This is enforced both in the UI grouping logic and in the server-side batching logic.
3.4 US Entity Buyer Mode: Multi-Client Is Optional
Business rule: For US entities in Buyer recipient mode, the user may choose to combine multiple clients into a single buyer invoice by enabling Multi-Client Invoice. When disabled (default), each client gets its own invoice from a given buyer.
Foundation reference: Generate Invoices — Step 3: Group Items into Invoice Batches
Workflow context: The Multi-Client Invoice checkbox appears on the filter bar only when BUYER is selected as the recipient. Toggling it resets the current selection and regroups the table. When enabled, client sub-groups collapse into the entity/currency sub-group level; when disabled, client sub-groups reappear.
3.5 Invoice Type Must Match Billing Item Detail Type
Business rule: A Commission invoice (COMMISSION) may only contain REV-type billing item details (billing_item_detail_type_cd = 'REV'). A Total Due invoice (TOTAL_DUE) may only contain PAY-type details. Mixing types is not permitted.
Foundation reference: Generate Invoices — Step 2: Fetch and Validate Selected Billing Item Details
Workflow context: The filter bar enforces this at the query level: selecting COMMISSION loads only REV details; selecting TOTAL_DUE loads only PAY details. The validation is re-checked server-side at generation time as a safeguard against concurrent filter changes or direct API calls.
3.6 Client Recipient Always Gets Commission Invoices Only
Business rule: When the recipient is CLIENT, the invoice type is always COMMISSION. The system defaults Invoice Type to COMMISSION when the user selects CLIENT as the recipient and hides the TOTAL_DUE option.
Foundation reference: Invoice Type Code Master — INVOICE_TYPE_CD
Workflow context: The Invoice Type dropdown filters its options based on the selected recipient. When CLIENT is selected, only the COMMISSION option is shown and the dropdown is effectively pre-set.
3.7 A Billing Item Cannot Be Invoiced Twice for the Same Document Type
Business rule: Once a billing item is linked to an invoice of a given type (Commission or Buyer), it no longer appears in the available-for-invoicing list for that type and cannot be added to a new invoice of the same type.
Foundation reference: Get Billing Items Available for Invoicing — Exclusion Filter
Workflow context: After generation succeeds, the screen refreshes and the invoiced items disappear from the table. The uq_billing_item_document_item_type_doc unique constraint on billing_item_document (billing_item_id, document_type_cd, document_id) enforces this at the database level — concurrent inserts for the same billing item and document type will fail with a constraint violation.
3.8 Invoice Number Is Sequential Per Entity Per Calendar Year
Business rule: Invoice numbers follow the format {prefix}-{year}-{sequence} (e.g., UTA_US-2026-000001). The sequence resets to 1 at the start of each new calendar year and increments atomically for each new invoice within a year. The prefix is derived from uta_entity.invoice_prefix.
Foundation reference: Invoice Number Generation — Procedure 2.2
WARNING
The PoC uses a read-then-write pattern for sequence generation (SELECT then UPDATE), which is not safe under concurrent invoice creation. Production must use an atomic increment (e.g., UPDATE ... SET current_sequence = current_sequence + 1 RETURNING) or a serializable transaction to prevent duplicate invoice numbers.
3.9 Due Date Is Derived from Billing Terms
Business rule: invoice.due_date is always calculated by adding the billing_terms_cd offset to invoice.issue_date. The issue date defaults to the current date (PST) at generation time, and the billing terms default to DUE_RECEIPT (0 days offset) when not overridden.
Foundation reference: Generate Invoices — Step 4: Calculate Due Date
3.10 Bank Details Are Selected Automatically for PDF Generation
Business rule: When generating a PDF, the system resolves payment instructions by matching invoice.uta_entity_id and invoice.currency_cd to the invoice_bank_details table. If no active matching record exists, the PDF is generated without payment instructions.
Foundation reference: invoice_bank_details Table Definition
3.11 Invoice Lifecycle Is Forward-Only
Business rule: Invoices follow the lifecycle DRAFT → ISSUED → PAID → VOID. PAID and VOID are terminal states. No backward transition is permitted.
Foundation reference: Invoice Status Lifecycle — INVOICE_STATUS_CD
**PoC Artifact:** The PoC does not enforce allowed status transitions in the service layer. The `updateInvoiceStatus` operation accepts any target status. Production must enforce the allowed-transitions table as preconditions before updating `invoice.status_cd`.
4. Data Access & Operations References
4.1 Queries Used
| Operation | Foundation Doc | Purpose in This Workflow |
|---|---|---|
getBillingItemDetailsForInvoicing | Get Billing Items Available for Invoicing | Loads uninvoiced billing item details for display in the grouped table, filtered by billing_item_detail_type_cd |
getBillingItemDetailsByIds | Get Billing Items by IDs | Hydrates the selected detail IDs with full party, entity, address, and deal data at generation time |
getBillingItemDetailsByInvoiceId | Get Billing Items by Invoice ID | Loads line items for an invoice when generating its PDF |
getInvoices | Get All Invoices | Populates the Invoice List screen with optional invoice.status_cd filter |
getInvoiceDisplayById | Get Invoice by ID | Loads a single invoice with enriched display data (entity name, recipient name, type description) for PDF rendering |
getNextInvoiceNumber (sequence read) | Invoice Number Generation | Reads the current invoice_number_sequence.current_sequence for the entity-year before incrementing |
getInvoiceBankDetails | Invoice Queries — Bank Details | Resolves payment instructions by uta_entity_id + currency_cd for PDF generation |
getUtaEntityWithDetails | TODO: Document in foundation/queries/invoices-and-statements.md | Fetches UTA entity name and configuration for PDF header rendering |
4.2 Procedures Used
| Operation | Foundation Doc | Trigger in This Workflow |
|---|---|---|
generateInvoices | Generate Invoices from Billing Items | User clicks Generate Invoice button with one or more items selected |
getNextInvoiceNumber | Invoice Number Generation | Called internally once per invoice batch during generation |
createBillingItemDocumentLinks | Link Billing Items to Invoice | Called internally once per invoice batch to write billing_item_document bridge rows |
updateInvoiceStatus | Update Invoice Status | User transitions an invoice's invoice.status_cd (e.g., Draft → Issued, Issued → Void); not yet surfaced as a distinct UI action in the PoC |
generateInvoicePdf | Generate Invoice PDF | User clicks the PDF download icon on any row in the Invoice List |
upsertInvoiceBankDetails | Add or Update Invoice Bank Details | Administrator sets up payment instructions for an entity/currency combination before PDF generation (admin workflow, not surfaced in the PoC invoicing screens) |
5. Key User Actions
5.1 Load Billing Items Available for Invoicing
Preconditions:
- User has selected both an Invoice Recipient (
CLIENTorBUYER) and an Invoice Type (COMMISSIONorTOTAL_DUE) from the filter bar. billing_item_detailrecords of the correspondingbilling_item_detail_type_cdmust exist without a matchingbilling_item_documentlink of the relevant document type.
Procedure reference: Get Billing Items Available for Invoicing
Steps:
- User selects Invoice Recipient; the system defaults Invoice Type to
COMMISSIONwhenCLIENTis chosen, orTOTAL_DUEwhenBUYERis chosen. - User confirms or overrides Invoice Type.
- The system fetches uninvoiced
billing_item_detailrecords filtered by the selectedbilling_item_detail_type_cd. - The grouped table renders with items organized by recipient party (Level 1), UTA entity and currency (Level 2), and client (Level 3 where applicable). All groups are collapsed by default.
Postconditions:
- The grouped table is populated. Selection state is cleared.
UI trigger: Automatic — fires when both filter dropdowns have non-empty values. A Refresh button in the page header re-runs the fetch manually.
5.2 Select Billing Items for Invoice Generation
Preconditions:
- The grouped table is populated (both filters are set and data has loaded).
Procedure reference: Not a data mutation — selection is client-side state only until Generate Invoice is submitted.
Steps:
- User checks or unchecks individual detail rows, client sub-group rows (Level 3), entity/currency sub-group rows (Level 2), or recipient group rows (Level 1).
- Selecting a parent-level checkbox selects all children below it; deselecting a parent deselects all children.
- The action bar shows a count of selected items, a preview of how many invoices will be generated, and enables the Generate Invoice button.
- User may use Select All to select every visible item or Clear Selection to deselect all.
- Expand All / Collapse All controls the visibility of hierarchy levels without affecting selection state.
Postconditions:
- A set of
billing_item_detail.billing_item_detail_idvalues is held in client state for submission.
UI trigger: Checkboxes on each row and group/sub-group header row. Select All and Clear Selection buttons in the action bar. Enabled when the table is populated.
5.3 Generate Invoices
Preconditions:
- At least one billing item detail is selected.
- Both Invoice Recipient and Invoice Type filters are set.
- All selected details must have
billing_item_detail_type_cdmatching the selected Invoice Type (REVfor Commission,PAYfor Total Due).
Procedure reference: Generate Invoices from Billing Items
Steps:
- User clicks Generate Invoice.
- The system validates that all selected
billing_item_detail_idvalues exist and theirbilling_item_detail_type_cdmatches the invoice type. - The system groups selected items into invoice batches using entity, currency, recipient party, and client rules.
- For each batch, the system generates a sequential invoice number via the
invoice_number_sequencemechanism. - For each batch, the system inserts an
invoicerecord withinvoice.status_cd = 'DRAFT', calculatedinvoice.total_gross_amt,invoice.total_commission_amt(Commission invoices only),invoice.issue_date(current date in PST), andinvoice.due_date(derived frombilling_terms_cd). - For each batch, the system inserts
billing_item_documentrows linking eachbilling_item_idto the newinvoice.invoice_idwith the appropriatedocument_type_cd('CI'for Commission,'BI'for Buyer). - On success, a confirmation message shows the count of invoices created. The selection is cleared and the table refreshes, removing the now-invoiced items.
Postconditions:
- One
invoicerecord exists per batch withinvoice.status_cd = 'DRAFT'. billing_item_documentrows exist for each billing item in each batch, preventing re-invoicing.- Invoiced items no longer appear in the available-for-invoicing table.
UI trigger: Generate Invoice button in the action bar. Visible always. Enabled when at least one item is selected and generation is not in progress. Shows a loading state ("Generating...") while in progress.
5.4 Download Invoice PDF
Preconditions:
- An
invoicerecord exists in any status (DRAFT,ISSUED,PAID, orVOID). - The invoice has at least one
billing_item_documentlink (i.e., at least one line item). - A
uta_entityrecord exists for the invoice'suta_entity_id.
Procedure reference: Generate Invoice PDF
Steps:
- User navigates to the Invoice List screen.
- User clicks the download icon on any invoice row.
- The system fetches the invoice header with display data, its linked billing item line items via
billing_item_document, the UTA entity details, and the matchinginvoice_bank_detailsrecord byuta_entity_id+currency_cd. - The system generates a PDF buffer containing the invoice number, issue and due dates, recipient name and address, line items with gross and commission amounts, totals, and (if available) payment instructions.
- The PDF is returned as a base64-encoded string, decoded in the browser, and downloaded as
Invoice_{invoice.invoice_number}.pdf.
Postconditions:
- No database mutation.
invoice.status_cdis not changed by PDF generation.
UI trigger: Download icon (per-row) in the Invoice List table. Always visible and enabled for every invoice row. Shows a loading pulse animation while the PDF is being generated for that row.
5.5 Filter Invoice List by Status
Preconditions:
- The Invoice List screen is open and invoices have been loaded.
Procedure reference: Get All Invoices
Steps:
- User opens the Invoice List screen; all invoices load by default (no status filter applied).
- User selects a status from the Status filter dropdown (
Draft,Issued,Paid,Void, orAll Statuses). - The system re-fetches
invoicerecords filtered by the selectedinvoice.status_cd. - The table updates to show only invoices matching the filter.
Postconditions:
- The table reflects only invoices with the selected
invoice.status_cd. No database state is changed.
UI trigger: Status dropdown in the Invoice List screen header. Always visible and enabled.
6. Permissions & Role-Based Access
**PoC Artifact:** The PoC does not enforce role-based access control for the invoicing workflow. The `invoice.created_by` field defaults to `'SYSTEM'` because user session resolution is not implemented. The role model below reflects the expected production design based on the existing role definitions in the system.
| Action | CASH_MANAGER | CASH_PROCESSOR | SETTLEMENT_APPROVER | IT |
|---|---|---|---|---|
| Load billing items available for invoicing | Yes | Yes | Yes | Yes |
| Select items and preview invoice count | Yes | Yes | Yes | Yes |
| Generate invoices | Yes | — | — | Yes |
| View Invoice List | Yes | Yes | Yes | Yes |
| Filter Invoice List by status | Yes | Yes | Yes | Yes |
| Download invoice PDF | Yes | Yes | Yes | Yes |
| Update invoice status (e.g., Draft → Issued, Issued → Void) | Yes | — | Yes | Yes |
Field-level restrictions:
invoice.status_cdtransitions are expected to requireCASH_MANAGERorSETTLEMENT_APPROVERrole in production. TheISSUED → PAIDtransition is expected to be driven by the cash matching workflow rather than a manual status change.- The Multi-Client Invoice option is available only when
BUYERis selected as the recipient and is currently unrestricted by role in the PoC.
7. Integration Points
7.1 Upstream
| Source | Data Provided | Mechanism |
|---|---|---|
| Deal Engine (via Revenue Sync) | revenue_item and billing_item records created from deal payment terms | Inbound data sync writes billing_item and billing_item_detail rows that become available for invoicing |
| Billing Items workflow | billing_item and billing_item_detail records with REV/PAY amounts, entity, currency, client, and buyer associations | FK lookup: billing_item_detail.billing_item_id → billing_item → revenue_item (sales_item) → deal |
| UTA Entity Configuration | Invoice prefix from uta_entity.invoice_prefix; entity name for PDF header | FK lookup: billing_item.uta_entity_id → uta_entity |
| Invoice Bank Details | Payment instructions (bank_name, account_number, swift_code, iban, sort_code, aba_routing_number) for PDF rendering | FK lookup: invoice.uta_entity_id + invoice.currency_cd → invoice_bank_details |
| Party Addresses | Recipient and contracted party mailing addresses for PDF | FK lookup: billing_item.buyer_id / client_id → party_addresses (primary address) |
7.2 Downstream
| Consumer | Data Consumed | Mechanism |
|---|---|---|
| Cash Receipts / Worksheets workflow | billing_item_document bridge rows identify which billing items have been invoiced; invoice.status_cd transitions to PAID when cash is matched | FK lookup: billing_item_document.document_id = invoice.invoice_id |
| Statements workflow | invoice records associated with billing items may be referenced in client and deal statement generation | FK lookup via billing_item_document |
| AR Aging reports | billing_item_document links indicate which receivables have been invoiced, used as a status indicator in aging views | FK lookup via billing_item_document |
7.3 External Integrations
No external integrations for this workflow. Invoice PDFs are generated in-process and returned directly to the browser. No outbound transmission to buyer or client systems is currently implemented; PDF delivery is manual (the user downloads and sends separately).
8. Functional Screen Requirements
8.1 Generate Invoices Screen
Route: /invoices
Data loading:
- No data is loaded on initial page entry — the grouped table remains hidden until both filter dropdowns are set.
getBillingItemDetailsForInvoicing— Get Billing Items Available for Invoicing — triggered automatically when both Invoice Recipient and Invoice Type are selected, and manually via the Refresh button.
Filter Bar Region
The filter bar collects the two required parameters that control which billing items are loaded and how they are grouped and invoiced.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Invoice Recipient | Client state (maps to invoice.invoice_recipient_cd: CLIENT or BUYER) | Yes | Always visible |
| Invoice Type | Client state (maps to invoice.invoice_type_cd: COMMISSION or TOTAL_DUE) | Yes | Always visible; filtered to COMMISSION only when recipient is CLIENT |
| Multi-Client Invoice | Client state (boolean; maps to multiClientInvoice parameter on the generate request) | Yes | Visible only when Invoice Recipient = BUYER |
Conditional display:
- The Multi-Client Invoice checkbox is visible only when Invoice Recipient =
BUYER. - When Invoice Recipient =
CLIENT, the Invoice Type dropdown shows onlyCommissionand is auto-selected. - When Invoice Recipient =
BUYER, the Invoice Type dropdown defaults toTotal Duebut allowsCommissionas well. - The billing item table and action bar are hidden and a placeholder is shown until both Invoice Recipient and Invoice Type are set.
Action Bar Region
The action bar shows selection statistics, a live invoice count preview, and the generate trigger.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Selected items count | Computed: count of billing_item_detail_id values in client selection state | No | Visible when filter is complete and data has loaded |
| Total items count | Computed: total count of loaded billing_item_detail rows | No | Visible when filter is complete and data has loaded |
| Invoice count preview | Computed: number of distinct invoice batches the current selection will produce | No | Visible when at least one item is selected |
Grid features:
- Sortable columns: none
- Filters: driven by filter bar dropdowns only
- Row selection: multi-checkbox with hierarchy-aware Select All / Clear Selection
- Pagination: none
Conditional display:
- Select All button: always enabled when filter is complete and data has loaded.
- Clear Selection button: enabled only when at least one item is selected.
- Expand All / Collapse All: always enabled when data has loaded.
- Generate Invoice button: enabled only when at least one item is selected and generation is not in progress.
- The invoice count preview sentence ("Will generate N invoices") appears only when at least one item is selected.
Grouped Billing Items Table Region
The grouped table presents billing items in a collapsible hierarchy. Each level has a checkbox for bulk selection and a row count and total amount summary.
Level 1 — Recipient Group Row
Groups items by the recipient party name (client name for CLIENT mode; buyer name for BUYER mode).
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Group name | party.party_name (client or buyer depending on recipient mode) | No | Always visible |
| Item count | Computed: total billing_item_detail rows in the group | No | Always visible |
| Group selection checkbox | Client state | Yes | Always visible |
| Expand/collapse toggle | Client state | Yes | Always visible |
Level 2 — UTA Entity + Currency Sub-Group Row
Groups items within a recipient group by billing_item.uta_entity_id and billing_item.currency_cd.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Sub-group label | uta_entity.uta_entity_name + billing_item.currency_cd | No | Visible when parent group is expanded |
| Item count | Computed: count of billing_item_detail rows in the sub-group | No | Visible when parent group is expanded |
| Total amount | Computed: SUM(billing_item_detail.billing_item_detail_amt) for sub-group items | No | Visible when parent group is expanded |
| Sub-group selection checkbox | Client state | Yes | Visible when parent group is expanded |
Level 3 — Client Sub-Group Row (Buyer mode without Multi-Client, or UK entity)
Groups items within an entity/currency sub-group by billing_item.client_id. Each client sub-group represents one invoice that will be created.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Client name | party.party_name (client) | No | Visible when sub-group is expanded and has client grouping |
| Item count | Computed: count of items for this client | No | Visible when sub-group is expanded and has client grouping |
| Total amount | Computed: SUM(billing_item_detail.billing_item_detail_amt) for this client's items | No | Visible when sub-group is expanded and has client grouping |
| Client sub-group selection checkbox | Client state | Yes | Visible when sub-group is expanded and has client grouping |
Detail Row (Individual Billing Item Detail)
One row per billing_item_detail record.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Row selection checkbox | Client state | Yes | Visible when parent row is expanded |
| UTA Entity | uta_entity.uta_entity_name | No | Always shown |
| Currency | billing_item.currency_cd | No | Always shown |
| Client | party.party_name (client via billing_item.client_id) | No | Always shown |
| Buyer | party.party_name (buyer via billing_item.buyer_id) | No | Always shown |
| Deal | deal.deal_name | No | Always shown |
| Billing Description | billing_item.billing_item_name | No | Always shown |
| Due Date | billing_item.billing_item_due_dt | No | Always shown |
| Type | billing_item_detail.billing_item_detail_type_cd displayed as a badge (REV or PAY) | No | Always shown |
| Gross | billing_item_detail.billing_item_detail_gross_amt | No | Always shown |
| Commission / Net | billing_item_detail.billing_item_detail_amt | No | Shown only when Invoice Type = COMMISSION; column header is "Commission" for CLIENT recipient, "Net" for BUYER recipient |
| Service Period | revenue_item.revenue_item_start_dt to revenue_item.revenue_item_end_dt | No | Always shown |
Conditional display:
- The entire table and action bar are hidden until both filter dropdowns have values.
- When data loads with zero results, an empty state message ("No billing items available for invoicing with the selected criteria") is shown.
- The Level 3 client sub-group layer is shown only in Buyer mode when Multi-Client Invoice is unchecked, or when the entity is the UK entity regardless of the Multi-Client checkbox.
- The Commission/Net column is hidden entirely when Invoice Type =
TOTAL_DUE. - Selecting any item automatically expands its parent group, sub-group, and client sub-group (if applicable) to make the selection visible.
8.2 Invoice List Screen
Route: /invoices/list
Data loading:
getInvoices— Get All Invoices — loads on mount; re-runs when the status filter changes.
Header Region
Shows page title, record count, a Refresh button, and a Generate Invoice navigation link.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Invoice count label | Computed: count of displayed invoice rows after filtering | No | Always visible |
| Status filter | Client state (maps to invoice.status_cd filter parameter; 'all' = no filter) | Yes | Always visible |
Conditional display:
- The Generate Invoice button navigates to
/invoices(the Generate Invoices screen). - When the list is empty and no status filter is active, an empty state with an icon and a Generate Invoice call-to-action is shown.
- When the list is empty with a status filter active, a message prompts the user to change the filter.
Invoice Table Region
One row per invoice record.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Invoice # | invoice.invoice_number | No | Always visible |
| Status | invoice.status_cd displayed as a status badge | No | Always visible |
| Type | invoice.invoice_type_cd (display description) | No | Always visible |
| Recipient | party.party_name via invoice.recipient_party_id | No | Always visible |
| Entity | uta_entity.uta_entity_name via invoice.uta_entity_id | No | Always visible |
| Issue Date | invoice.issue_date | No | Always visible |
| Due Date | invoice.due_date | No | Always visible |
| Amount | invoice.total_gross_amt formatted with invoice.currency_cd | No | Always visible |
| PDF download button | — triggers generateInvoicePdf for the row's invoice.invoice_id | — | Always visible; per-row |
Grid features:
- Sortable columns: none (invoices are sorted by creation date descending from the query)
- Filters: status filter dropdown in the header filters by
invoice.status_cd - Row selection: none
- Pagination: none in the PoC
Conditional display:
- The PDF download button shows a loading animation while the PDF is being generated for that specific invoice row.
- Status badge appearance varies by
invoice.status_cd:DRAFT= muted/secondary,ISSUED= default/primary,PAID= outline,VOID= destructive.
9. Additional Diagrams
Invoice Grouping Logic (Generate Invoices)
The following diagram shows how selected billing item details are partitioned into invoice batches during generation.
flowchart TD
A([Selected billing_item_detail IDs]) --> B{Recipient type?}
B -->|CLIENT| C["Batch key: uta_entity_id + currency_cd + client_party_id"]
B -->|BUYER| D{Is UK entity ID = 2?}
D -->|Yes — UK restriction| E["Batch key: uta_entity_id + currency_cd + buyer_party_id + client_party_id"]
D -->|No — US entity| F{multiClientInvoice = true?}
F -->|No — one client per invoice| G["Batch key: uta_entity_id + currency_cd + buyer_party_id + client_party_id"]
F -->|Yes — combine clients| H["Batch key: uta_entity_id + currency_cd + buyer_party_id"]
C --> I([One invoice record per batch key])
E --> I
G --> I
H --> IAll diagrams for this workflow are included in the sections above.
10. Cross-References
| Document | Relationship |
|---|---|
| Invoices and Statements Data Model | Defines invoice, invoice_number_sequence, invoice_bank_details, billing_item_document, and generated_statement tables used in this workflow |
| Invoices and Statements Queries | Specifies all data retrieval operations used in this workflow |
| Invoices and Statements Procedures | Specifies all data mutation operations used in this workflow |
| Billing Items Data Model | billing_item and billing_item_detail are the source records displayed and invoiced in this workflow; billing_item_document is the bridge table (owned by Billing Items) that marks items as invoiced |
| Billing Items Workflow | Upstream: billing items are created from deal engine revenue sync before they appear in the invoicing queue |
| Statements Workflow | Sibling: statements summarize financial activity for clients and settlements; invoices are payment requests. Both workflows produce PDF documents but serve different purposes |
| Worksheets Workflow | Downstream: cash receipts are applied against billing item details in worksheets; matching a receipt to an invoice transitions invoice.status_cd to PAID |
| Write-Offs Workflow | Adjacent: REV billing item details that are written off have billing_item_detail.write_off_status_cd = 'WRITTEN_OFF'; written-off items may still be invoiced but represent amounts deemed uncollectable |
11. Gherkin Scenarios
Feature: Invoicing - Generate Commission Invoices for Clients
Scenario: User generates a single commission invoice for a client
Given billing_item_detail records exist for client "Taylor Swift" with billing_item_detail_type_cd = 'REV'
And no billing_item_document row exists for those billing_item rows with document_type_cd = 'CI'
And the billing items have billing_item.uta_entity_id = 1 (UTA US) and billing_item.currency_cd = 'USD'
When the user selects Invoice Recipient = 'CLIENT' and Invoice Type = 'COMMISSION'
And the user selects all billing item details for "Taylor Swift"
And the user clicks Generate Invoice
Then one invoice record is created with invoice.status_cd = 'DRAFT'
And invoice.invoice_type_cd = 'COMMISSION' and invoice.invoice_recipient_cd = 'CLIENT'
And invoice.uta_entity_id = 1 and invoice.currency_cd = 'USD'
And invoice.invoice_number matches the pattern 'UTA_US-2026-{6-digit zero-padded sequence}'
And invoice.total_gross_amt = SUM(billing_item_detail.billing_item_detail_gross_amt) for selected items
And invoice.total_commission_amt = SUM(billing_item_detail.billing_item_detail_amt) for selected items
And billing_item_document rows are created with document_type_cd = 'CI' linking each billing_item_id to the new invoice.invoice_id
And the selected items no longer appear in the available-for-invoicing list
Scenario: UK entity always produces separate invoices per client even when Multi-Client is checked
Given billing_item_detail records exist for two clients "Ed Sheeran" and "Adele"
And both clients have billing items with billing_item.uta_entity_id = 2 (UTA UK) and currency_cd = 'GBP'
And Invoice Recipient = 'BUYER' and Multi-Client Invoice checkbox is checked
When the user selects all billing item details for both clients under the same buyer
And the user clicks Generate Invoice
Then two invoice records are created — one for "Ed Sheeran" and one for "Adele"
And both invoices have invoice.uta_entity_id = 2 and invoice.currency_cd = 'GBP'
And invoice.multi_client_ind = false for both invoices
And billing_item_document links with document_type_cd = 'BI' are created for each invoice separately
Scenario: US entity in Buyer mode with Multi-Client enabled combines clients into one invoice
Given billing_item_detail records exist for clients "Imagine Dragons" and "The Weeknd"
And both have billing_item.buyer_id pointing to buyer "Live Nation" under billing_item.uta_entity_id = 1 (UTA US) with currency_cd = 'USD'
And Invoice Recipient = 'BUYER', Invoice Type = 'TOTAL_DUE', Multi-Client Invoice = true
When the user selects all items for both clients and clicks Generate Invoice
Then one invoice record is created for recipient "Live Nation"
And invoice.multi_client_ind = true
And billing_item_document links with document_type_cd = 'BI' cover billing items from both clients
Scenario: Items across two currencies produce separate invoices
Given billing_item_detail records exist for buyer "Netflix" under billing_item.uta_entity_id = 1 (UTA US)
And some items have billing_item.currency_cd = 'USD' and others have billing_item.currency_cd = 'EUR'
And Invoice Recipient = 'BUYER', Invoice Type = 'TOTAL_DUE', Multi-Client Invoice = true
When the user selects all items for Netflix and clicks Generate Invoice
Then two invoice records are created — one with invoice.currency_cd = 'USD' and one with invoice.currency_cd = 'EUR'
And both invoice.invoice_number values are globally unique
Scenario: Generate Invoice button is disabled until items are selected
Given the user has selected Invoice Recipient = 'CLIENT' and Invoice Type = 'COMMISSION'
And the billing item table is loaded with results
And no items are currently selected
Then the Generate Invoice button is disabled
And the invoice count preview is not shown in the action bar
Feature: Invoicing - Error Handling
Scenario: Generation fails due to invoice type mismatch
Given billing_item_detail record ID 2001 has billing_item_detail_type_cd = 'PAY'
And Invoice Type = 'COMMISSION' is selected (which requires billing_item_detail_type_cd = 'REV')
When a generate request is submitted including billing_item_detail_id = 2001
Then the service rejects the request with an error indicating invoice type mismatch
And no invoice records are created
And no billing_item_document rows are inserted
Scenario: Concurrent generation blocked by unique constraint on billing_item_document
Given billing_item_id = 501 has billing_item_detail_type_cd = 'REV' and no billing_item_document row with document_type_cd = 'CI'
And two users simultaneously select billing_item_detail for billing_item_id = 501 and click Generate Invoice
When both requests reach the billing_item_document INSERT step
Then the first request succeeds and inserts billing_item_document with document_type_cd = 'CI' for billing_item_id = 501
And the second request fails with a uq_billing_item_document_item_type_doc constraint violation
And only one invoice record is committed
Feature: Invoicing - PDF Download
Scenario: User downloads a PDF for a Draft invoice with bank details configured
Given invoice record with invoice_id = 500 exists with invoice.status_cd = 'DRAFT'
And billing_item_document rows link billing items to invoice_id = 500
And invoice_bank_details exists for invoice.uta_entity_id and invoice.currency_cd with is_active = true
When the user clicks the download icon for invoice_id = 500 on the Invoice List screen
Then the system fetches invoice display data, line items, entity details, and bank details
And generates a PDF containing invoice.invoice_number, invoice.issue_date, invoice.due_date, line items, totals, and payment instructions
And the browser downloads a file named 'Invoice_{invoice.invoice_number}.pdf'
And invoice.status_cd remains 'DRAFT' — no database mutation occurs
Scenario: PDF generated without payment instructions when no bank details exist
Given invoice record with invoice_id = 501 exists for invoice.uta_entity_id = 3 and invoice.currency_cd = 'CAD'
And no invoice_bank_details row exists with uta_entity_id = 3 and currency_cd = 'CAD' and is_active = true
When the user clicks the download icon for invoice_id = 501
Then the system generates a PDF without a payment instructions section
And the download succeeds with the correct invoice header and line item content
Feature: Invoicing - Invoice List Management
Scenario: User filters the Invoice List to show only Issued invoices
Given multiple invoice records exist with invoice.status_cd values of 'DRAFT', 'ISSUED', and 'PAID'
When the user selects 'Issued' from the Status filter dropdown on the Invoice List screen
Then the table shows only invoice rows where invoice.status_cd = 'ISSUED'
And the invoice count label reflects only the filtered count
Scenario: Invoice sequence increments correctly within the same year
Given invoice_number_sequence exists for uta_entity_id = 1 and current_year = 2026 with current_sequence = 5
When a new invoice is generated for uta_entity_id = 1
Then invoice_number_sequence.current_sequence for uta_entity_id = 1 and current_year = 2026 is updated to 6
And the new invoice.invoice_number = 'UTA_US-2026-000006'
Scenario: Invoice sequence resets at the start of a new calendar year
Given invoice_number_sequence exists for uta_entity_id = 1 and current_year = 2025 with current_sequence = 999
And the current system date is in 2026
When a new invoice is generated for uta_entity_id = 1
Then a new invoice_number_sequence row is created with uta_entity_id = 1, current_year = 2026, current_sequence = 1
And the new invoice.invoice_number = 'UTA_US-2026-000001'