Skip to content

Deals Workflow

1. Executive Summary

Purpose

The Deals workflow is the entry point for all financial operations in Client Processing. A deal represents the commercial agreement between UTA and a buyer on behalf of a client (artist, talent, or creator). Every downstream financial operation — billing items, cash receipts, worksheets, settlements, and outbound payments — traces back to a deal. Users create and manage deals through deal master management (reference and party setup) and manage sales items and payment terms through the sales pipeline. The result is revenue items and billing items that the cash management workflow applies payments against.

Scope

Covered:

  • Creating and editing deal master records (deal, deal_party)
  • Managing deal parties and their commission structures
  • Managing sales pipeline items (sales_block, sales_item, payment_term) from the Sales screen (create, update, split, process)
  • Processing sales blocks into revenue items and billing items via processRevenueUpdate
  • Searching, filtering, and viewing deal data

Not covered (documented separately):

Key Objectives

  • Capture the commercial agreement (deal) and the parties involved, including commission structures and payment routing.
  • Produce payment terms that define the expected billing schedule (who pays, how much, and when).
  • Generate billing items that drive the receivables used in the cash management workflow.
  • Maintain versioned history of sales data as terms evolve over time.

2. Process Overview

mermaid
flowchart TD
    A[User selects client] --> B[Create or edit Deal]
    B --> C[Assign Deal Parties with commission]
    C --> F[Sales Item arrives in Sales Block]
    F --> K{Validate sales block}
    K -->|Pass| M[Process Revenue Update]
    K -->|Fail| N[Block set to Failed status]
    N --> O[User corrects data and retries]
    O --> K
    M --> P[Revenue Items created/updated]
    P --> Q[Billing Items created/updated]
    Q --> R[Cash management workflow begins]

Walkthrough

  1. Create or edit deal — The user creates a new deal record with a name, reference, date range, and active status, then assigns parties (client, buyer, agent, attorney, etc.) with commission terms and bank routing.
  2. Sales items enter the pipeline — Sales items and payment terms are created in the sales pipeline (sales_block, sales_item, payment_term). Each sales block groups one sales item with its associated payment terms.
  3. Process revenue update — The user (from the Sales screen) runs processRevenueUpdate for the sales block. This validates the block through three layers (data, consistency, referential) and creates or updates revenue_items and billing_item / billing_item_detail records.
  4. Billing items available — The resulting billing items (each with one REV detail and one PAY detail) are now available to the cash management workflow for applying receipts.

3. Business Rules

3.1 Sales Item Gross Must Equal Payment Term Sum

Business rule: The sum of all payment_term.gross_amt values for a sales item must equal sales_item.gross_amt within a $0.01 tolerance. Revenue processing is rejected if this check fails.

Foundation reference: Process Revenue Update — Step 2: Run Three-Layer Validation

Workflow context: The data validation layer checks this constraint before allowing revenue processing to proceed.


3.2 Deal Reference Auto-Generation

Business rule: If no deal.deal_reference is provided when creating a deal, the system generates one automatically using the pattern DEAL-{random_alphanumeric}.

Foundation reference: Create Deal — Step 1: Resolve Deal Reference


3.3 Party List Is Authoritative on Upsert

Business rule: When saving a deal with a party list, the submitted list is treated as authoritative. Any existing deal_party row not represented in the submitted list (or explicitly marked isDeleted) is deleted. This ensures the deal's party composition exactly matches the submitted list.

Foundation reference: Upsert Deal with Parties

Workflow context: The deal party management dialog submits the full list of parties on save. Removing a party row from the UI and saving will delete the corresponding deal_party record.


3.4 Commission Sanitization

Business rule: Blank or null values for deal_party.deal_party_commission_perc and deal_party.deal_party_commission_amt are defaulted to '0' during upsert. The system does not accept blank strings for numeric commission fields.

Foundation reference: Upsert Deal with Parties — Step 3: Process the Provided Party List


3.5 Three-Layer Validation Before Revenue Processing

Business rule: Before a sales_block is processed into revenue and billing items, the system runs three validation layers in order: (1) data validation — required fields present, amounts non-negative, payment term sum matches gross within $0.01; (2) consistency validation — immutable fields on existing revenue_items match the incoming data; (3) referential validation — all foreign key references and code master values exist. A single failure at any layer sets sales_block.process_status_cd to 'F' and populates sales_block.error_description.

Foundation reference: Process Revenue Update — Step 2: Run Three-Layer Validation


3.6 Sales Block Creates New Pipeline Rows on Every Version

Business rule: Every time a sales item is updated, a new sales_block is created along with new sales_item and payment_term rows in the pipeline tables. The shared sales_item_ref and payment_term_ref values link records across all versions.

IMPORTANT

The pipeline tables accumulate new rows for every save. The current version of a sales item is identified by following the sales_item_ref to the most recently processed sales_block (i.e., the one with process_status_cd = 'P'). Downstream billing_item records link to payment terms by payment_term_ref value.


3.7 Sales Item Split Requires Exactly One Payment Term

Business rule: The split operation is only permitted when the source item has exactly one payment term. The split carves off a specified amount into a new item, each retaining a single payment term.

Foundation reference: Split Sales Item Pipeline — Step 2: Validate Single Payment Term


3.8 Commission Percentage Precision Differs by Level

Business rule: deal_party.deal_party_commission_perc uses decimal(7,4) (max 999.9999%), while sales_item_party.sales_item_party_commission_perc uses decimal(5,4) (max 9.9999%). The wider precision at the deal-party level is intentional and supports override scenarios.

Foundation reference: Deals Sales Items Payment Terms Data Model — Section 2.3 deal_party


4. Data Access & Operations References

4.1 Queries Used

OperationFoundation DocPurpose in This Workflow
getDealByIdGet Deal by IDLoads deal header and party details when a row is clicked in the Deals search results, and on the Deal Detail screen
getAllDealsList All DealsPopulates deal selector dropdowns
searchDealsSearch DealsExecutes user-initiated search on the Deals search screen by reference, name, date range, and active status
getDealsByClientGet Deals by ClientLoads the deal list for a selected client with aggregate financial summaries
getSalesItemsGet Sales ItemsLoads all sales_item rows from the sales pipeline for the Sales management screen
getPaymentTermsGet Payment TermsLoads payment_term rows for a selected sales_item on the Sales screen

4.2 Procedures Used

OperationFoundation DocTrigger in This Workflow
createDealCreate DealUser submits the Create Deal dialog
updateDealUpdate Deal DetailsUser edits and saves a deal from the Deal Management dialog
upsertDealWithPartiesUpsert Deal with PartiesUser saves the deal form including the full party list
createDealPartyCreate Deal PartyUser adds a new party to an existing deal
updateDealPartyUpdate Deal PartyUser edits an existing party entry on a deal
deleteDealPartyDelete Deal PartyUser removes a party row from a deal, or a resubmitted party list omits the party
processRevenueUpdateProcess Revenue UpdateTriggered manually by user from the Sales screen
splitSalesItemPipelineSplit Sales Item PipelineUser initiates a split on a sales_item from the Sales management screen
updateSalesItemPipelineUpdate Sales Item PipelineUser edits a sales_item record from the Sales management screen
createSalesItemPipelineCreate Sales Item PipelineUser creates a new sales item from the Sales management screen

5. Key User Actions

5.1 Create Deal

Preconditions:

  • User has navigated to the Deals screen.
  • User has clicked "Add New Deal."

Procedure reference: Create Deal

Steps:

  1. User enters the deal name (required) and optionally a reference, start date, end date, and active status.
  2. User adds parties: selects a party by lookup, assigns a role (PARTY_ROLE_TYPE_CD), enters commission percentage or flat amount, and optionally selects a bank account.
  3. User submits. If no deal_reference is provided, the system generates one with the pattern DEAL-{random_alphanumeric}.
  4. The system inserts the deal row and synchronizes the deal_party rows.

Postconditions:

  • One new deal row exists with an auto-generated or user-provided deal.deal_reference.
  • deal_party rows exist for all submitted parties, with blank commission values defaulted to '0'.

UI trigger: "Add New Deal" button. Visible when on the Deals screen. Always enabled.


5.2 Edit Deal

Preconditions:

  • A deal exists.
  • User has clicked the edit icon on a deal row.

Procedure reference: Upsert Deal with Parties

Steps:

  1. The Deal Management dialog opens pre-populated with the existing deal fields and party list.
  2. User edits any combination of name, reference, dates, active status, and parties (add, update, or remove rows).
  3. User submits. The system updates the deal row and reconciles deal_party rows to exactly match the submitted list.

Postconditions:

  • deal row reflects updated field values.
  • deal_party rows exactly match the submitted list (new parties inserted, removed parties deleted, updated parties modified).

UI trigger: Edit icon on a deal row. Visible for all deal rows. Always enabled.


5.3 Process Revenue Update (Sales Screen)

Preconditions:

  • One or more sales_item rows exist in the Sales pipeline with sales_block.process_status_cd = 'U' (Unprocessed) or 'F' (Failed).
  • User has selected one or more rows using checkboxes on the Sales screen.

Procedure reference: Process Revenue Update

Steps:

  1. User selects one or more sales pipeline item rows and clicks "Process Revenue Update."
  2. For each selected item's sales_block, the system runs three-layer validation in order.
  3. On success: revenue items and billing items are created or updated; sales_block.process_status_cd set to 'P'.
  4. On failure: sales_block.process_status_cd set to 'F'; sales_block.error_description populated; a toast error is shown.

Postconditions:

  • sales_block.process_status_cd = 'P' for successfully processed blocks.
  • Revenue items and billing items exist for all successfully processed blocks.

UI trigger: "Process Revenue Update" button at the top of the Sales Items grid. Visible always. Enabled only when at least one row checkbox is selected. Label shows "Processing... (N)" during the operation.


5.4 Edit Sales Item (Sales Pipeline Screen)

Preconditions:

  • A sales_item row exists in the sales pipeline.
  • User has clicked the "Edit" button on the row.

Procedure reference: Update Sales Item Pipeline

Steps:

  1. The Sales Item Management dialog opens pre-populated with the current sales_item field values.
  2. User edits fields. Metadata-only changes (name, sales_item_status_cd, revenue_date_status_cd) copy existing payment terms with incremented versions. Financial or schedule changes regenerate payment terms from scratch.
  3. On save, the system creates a new sales_block with a new sales_item row at an incremented sales_item_ver.

Postconditions:

  • A new sales_block and sales_item row exist in the pipeline.
  • Payment terms regenerated (financial/schedule change) or copied with incremented payment_term_ver (metadata-only change).

UI trigger: "Edit" button on each row of the Sales Items grid. Always visible. Always enabled.


5.5 Split Payment Item (Sales Pipeline Screen)

Preconditions:

  • A sales_item row is selected in the Sales grid (payment terms panel is open).
  • Exactly one payment_term row is selected via checkbox in the payment terms panel.

Procedure reference: Split Sales Item Pipeline

Steps:

  1. User selects a payment term and clicks "Split Payment Item."
  2. The Split dialog opens. User enters the Revenue Item ID, split amount, and new item due date.
  3. The system validates the inputs and executes the split, creating a new sales_item for the split portion.

Postconditions:

  • The original payment_term.gross_amt is reduced by the split amount.
  • A new sales_item and payment_term exist for the split portion.
  • Downstream revenue and billing items updated.

UI trigger: "Split Payment Item" button in the Payment Terms panel. Visible when payment terms are loaded. Enabled only when exactly one payment term checkbox is selected.


5.6 Create Sales Item (Sales Pipeline Screen)

Preconditions:

  • User is on the Sales Management screen.
  • User has clicked "Create Sales Item."

Procedure reference: Create Sales Item Pipeline

Steps:

  1. User selects the deal, UTA entity, client, contracted party, buyer, department, and currency.
  2. User enters gross amount, commission type and percentage/amount, revenue dates, and recognition style.
  3. User adds payment terms with amounts and due dates.
  4. User submits. The system creates a new sales_block with sales_item and payment_term rows.

Postconditions:

  • A new sales_block, sales_item, and N payment_term rows exist in the pipeline.
  • The sales block is ready for revenue processing.

UI trigger: "Create Sales Item" button on the Sales Management screen. Always visible. Always enabled.


5.7 Search Deals

Preconditions:

  • User is on the Deals search screen.

Procedure reference: Search Deals

Steps:

  1. User enters one or more search criteria: deal reference (partial), deal name (partial), start date range, end date range, and optionally restricts to active deals only.
  2. User clicks Search. The system executes searchDeals with all provided criteria combined as AND conditions.
  3. Results appear in the deals grid. Clicking a row loads the deal party detail panel.

Postconditions:

  • deal rows matching all provided criteria are displayed in the results grid.
  • Clicking a row loads deal_party data for the selected deal via getDealById.

UI trigger: "Search" button in the Search Deals collapsible panel. The results grid is not populated until the user executes a search.


6. Permissions & Role-Based Access

**PoC Artifact:**

The current PoC does not enforce role-based access on deal management screens. All mutations use 'SYSTEM' as the actor identifier. The table below describes the intended production model. Cash management roles (CASH_MANAGER, CASH_PROCESSOR, SETTLEMENT_APPROVER) should be read-only on deals data.

ActionCASH_MANAGERCASH_PROCESSORSETTLEMENT_APPROVERIT
Search and view dealsYesYesYesYes
View deal party detailsYesYesYesYes
View sales items and payment termsYesYesYesYes
Create / edit dealYes
Manage deal parties (add, update, remove)Yes
Create / edit sales pipeline item (Sales screen)Yes
Split sales item (Sales screen)Yes
Process revenue update (Sales screen)Yes

Field-level restrictions:

  • deal.deal_reference, party commission fields (deal_party_commission_perc, deal_party_commission_amt), and all sales_item financial fields are editable only by IT in the current PoC.
  • All users can view deal summary data, navigate to /deals/[id], and follow the link to related revenue items.

7. Integration Points

7.1 Upstream

SourceData ProvidedMechanism
Party master dataparty.party_id, party.display_name, party.first_name, party.last_name, party.company_name for party assignment on deals and sales itemsFK lookup via party table
UTA Entity masteruta_entity.uta_entity_id, uta_entity.uta_entity_name for billing entity selection on sales itemsFK lookup via uta_entity table
Department masterdepartment.department_id, department.department_name for department assignment on sales itemsFK lookup via department table
Code masterCommission type (COMMISSION_TYPE_CD), revenue recognition style (REVENUE_ITEM_REC_STYLE_CD), revenue date status (REVENUE_ITEM_DATE_STATUS_CD), sales item status (REVENUE_ITEM_STATUS_CD), currency (CURRENCY_CD), party role type (PARTY_ROLE_TYPE_CD)code_master table lookups

7.2 Downstream

ConsumerData ConsumedMechanism
Billing Items workflowbilling_item and billing_item_detail (REV and PAY) rows created by processRevenueUpdate; billing_item.payment_term_ref soft-joins to payment_term.payment_term_refPipeline processing writes billing_item rows from payment_term records
Revenue Items workflowrevenue_items and revenue_item_schedules created or updated by processRevenueUpdate; soft-joined by sales_item_refPipeline processing writes revenue_items rows from sales_item records
Worksheets workflowbilling_item_detail rows (REV and PAY) are the receivables applied when cash is receivedFK via cash_receipt_application.billing_item_detail_id
Tax and Withholdingsales_item.service_country_cd and service_state_cd drive tax jurisdiction determination at worksheet apply timeRead by WithholdingTaxService via billing_itemsales_item_refsales_item
Assignments workflowdeal.deal_id is the top level of the responsibility assignment hierarchy (Deal → Client → Department)FK via assignment.deal_id; hierarchy walks up if no deal-level owner found

7.3 External Integrations

No external integrations for this workflow. Deal and sales item data is entered and managed entirely within the application. Bank adapters and outbound payment execution are downstream of billing items, not deals.


8. Functional Screen Requirements

8.1 Deals Search Screen

Route: /deals

Data loading:

  • No data loaded on page entry. Results are populated only after the user executes a search.
  • searchDealsSearch Deals — executed on Search button click
  • getDealByIdGet Deal by ID — loaded when a deal row is clicked

Search Panel Region

Collapsible panel containing all search filter fields. Expanded by default when no search has been performed.

Field / ColumnSourceEditable?Condition
Deal ReferenceUser input → filter on deal.deal_reference (partial match)YesAlways visible
Deal NameUser input → filter on deal.deal_name (partial match)YesAlways visible
Start Date FromUser input → lower bound on deal.deal_start_dtYesAlways visible
Start Date ToUser input → upper bound on deal.deal_start_dtYesAlways visible
End Date FromUser input → lower bound on deal.deal_end_dtYesAlways visible
End Date ToUser input → upper bound on deal.deal_end_dtYesAlways visible
Active Only (checkbox)User input → filter deal.active_ind = trueYesAlways visible

Grid features:

  • Sortable columns: N/A (search panel, not a grid)
  • Filters: N/A (this region IS the filter panel)
  • Row selection: N/A
  • Pagination: N/A

Conditional display:

  • Search panel is expanded by default when no search has been performed.
  • "No Search Performed" empty state shown below the panel until the user clicks Search.
  • Saved search controls (Save, Load, Delete) visible after at least one search has been performed.

Results Grid Region

Displays deals matching the search criteria after the user executes a search.

Field / ColumnSourceEditable?Condition
Deal IDdeal.deal_idNoAlways visible
Referencedeal.deal_referenceNoAlways visible
Namedeal.deal_nameNoAlways visible
Start Datedeal.deal_start_dtNoAlways visible
End Datedeal.deal_end_dtNoAlways visible
Activedeal.active_ind rendered as "Yes" / "No"NoAlways visible

Grid features:

  • Sortable columns: All columns
  • Filters: Global text filter
  • Row selection: Single-click loads the Deal Parties panel; checkbox for multi-select
  • Pagination: Yes

Conditional display:

  • Results grid visible only after a search has been executed.
  • Clicking a deal row loads the Deal Parties panel below.
  • Deep-linking via ?dealId={id} URL parameter auto-selects the deal on page load.

Deal Parties Detail Panel Region

Appears below the results grid when a deal row is selected.

Field / ColumnSourceEditable?Condition
Party IDdeal_party.party_idNoAlways visible
First Nameparty.first_nameNoAlways visible
Last Nameparty.last_nameNoAlways visible
Company Nameparty.company_nameNoAlways visible
Commission %deal_party.deal_party_commission_percNoAlways visible
Commission Amtdeal_party.deal_party_commission_amtNoAlways visible

Grid features:

  • Sortable columns: All columns
  • Filters: Global text filter
  • Row selection: Checkbox multi-select
  • Pagination: Yes

Conditional display:

  • Panel visible only when a deal row is selected.
  • "Loading details..." shown while getDealById is in progress.
  • "No parties found for this deal" shown when the deal has zero deal_party rows.
  • "Failed to load details" shown on error.
  • Panel heading shows the deal reference (or deal ID if reference is absent).

8.2 Deal Detail Screen

Route: /deals/[id]

Data loading:

  • getDealByIdGet Deal by ID — loaded on page entry; renders 404 if deal not found

Information Region

Displays core deal header fields.

Field / ColumnSourceEditable?Condition
IDdeal.deal_idNoAlways visible
Referencedeal.deal_referenceNoAlways visible
Namedeal.deal_nameNoAlways visible
Start Datedeal.deal_start_dtNoAlways visible
End Datedeal.deal_end_dtNoAlways visible
Activedeal.active_ind rendered as "Yes" / "No"NoAlways visible

Deal Parties Region

Field / ColumnSourceEditable?Condition
Party IDdeal_party.party_idNoAlways visible
Commission %deal_party.deal_party_commission_percNoAlways visible
Commission Amtdeal_party.deal_party_commission_amtNoAlways visible

Grid features:

  • Sortable columns: Party ID, Commission %
  • Filters: None
  • Row selection: None
  • Pagination: No
Field / ColumnSourceEditable?Condition
Revenue Items linkNavigation link: /revenue?dealId={deal.deal_id}NoAlways visible

Conditional display:

  • "Back to Deals" button navigates to /deals.
  • Revenue items link always visible.

8.3 Sales Management Screen

Route: /sales

Data loading:

  • getSalesItemsGet Sales Items — loads all sales_item rows from the pipeline on page entry

Sales Items Grid Region

Field / ColumnSourceEditable?Condition
Sales Item IDsales_item.sales_item_idNoHidden by default
Sales Block IDsales_item.sales_block_idNoHidden by default
Refsales_item.sales_item_refNoAlways visible
Versales_item.sales_item_verNoAlways visible
Block Statussales_block.process_status_cd rendered as Unprocessed / Processed / Failed / SkippedNoAlways visible
Dealdeal.deal_name resolved from sales_item.deal_idNoAlways visible
Namesales_item.nameNoAlways visible
ClientResolved from sales_item.client_entity_id → party nameNoAlways visible
Gross Amtsales_item.gross_amtNoAlways visible
Comm Typesales_item.uta_commission_typeNoHidden by default
Comm %sales_item.uta_commission_percNoAlways visible
Comm Amtsales_item.uta_commission_amtNoAlways visible
Start Datesales_item.revenue_start_dtNoAlways visible
End Datesales_item.revenue_end_dtNoAlways visible
Rev StyleResolved sales_item.rev_rec_style_cd descriptionNoAlways visible
Date StatusResolved sales_item.revenue_date_status_cd descriptionNoAlways visible
Item StatusResolved sales_item.sales_item_status_cd descriptionNoAlways visible
Created Bysales_item.created_byNoHidden by default
Created Datesales_item.created_dtNoHidden by default
Updated Bysales_item.updated_byNoHidden by default
Updated Datesales_item.updated_dtNoHidden by default

Grid features:

  • Sortable columns: All visible columns
  • Filters: Global text filter
  • Row selection: Checkbox multi-select for batch "Process Revenue Update"; single-click expands the payment terms panel below
  • Pagination: Yes

Conditional display:

  • "Process Revenue Update" button visible always. Enabled when at least one row checkbox is selected. Shows "Processing... (N)" during operation.
  • Block Status badge: Unprocessed (yellow), Processed (green), Failed (red), Skipped (grey). Failed rows show sales_block.error_description as tooltip hover.
  • "Edit" button on each row always visible and enabled.
  • "Create Sales Item" button always visible and enabled.

Payment Terms Panel Region

Appears below the grid when a sales item row is single-clicked.

Field / ColumnSourceEditable?Condition
Namepayment_term.nameNoAlways visible
Amountpayment_term.gross_amtNoAlways visible
Due Datepayment_term.due_dtNoAlways visible
Refpayment_term.payment_term_refNoAlways visible
Verpayment_term.payment_term_verNoAlways visible

Grid features:

  • Sortable columns: Name, Amount, Due Date, Ref, Ver
  • Filters: None
  • Row selection: Checkbox single-select (required for Split Payment Item)
  • Pagination: No

Conditional display:

  • "Split Payment Item" button visible. Enabled only when exactly one payment term checkbox is selected.
  • Close button (✕) in the top-right dismisses the panel and deselects the active row.

9. Additional Diagrams

Revenue Processing Validation Flow

mermaid
flowchart TD
    SB["sales_block\nprocess_status_cd = 'U'"] --> L1{"Layer 1\nData Validation"}
    L1 -->|"Required fields missing\nor amounts invalid\nor term sum mismatch"| F["Set process_status_cd = 'F'\npopulate error_description"]
    L1 -->|Pass| L2{"Layer 2\nConsistency Validation"}
    L2 -->|"Existing revenue_items found\nwith changed immutable field"| F
    L2 -->|Pass| L3{"Layer 3\nReferential Validation"}
    L3 -->|"FK or code master\nreference not found"| F
    L3 -->|Pass| CHECK{"revenue_items exists\nfor sales_item_ref?"}
    CHECK -->|Yes - Update path| UPD["Update revenue_items\nand billing items"]
    CHECK -->|No - Create path| CRE["INSERT revenue_items\nINSERT billing_item rows\nINSERT billing_item_detail REV+PAY"]
    UPD --> DONE["Set process_status_cd = 'P'"]
    CRE --> DONE

10. Cross-References

DocumentRelationship
Deals Sales Items Payment Terms Data ModelDefines all tables used in this workflow: deal, deal_party, sales_item, sales_item_party, sales_meta_data, sales_block, payment_term
Deals Sales Items Payment Terms QueriesSpecifies all read operations used in this workflow: deal master queries, sales pipeline queries, and metadata queries
Deals Sales Items Payment Terms ProceduresSpecifies all data mutation operations: deal CRUD, deal party management, sales item lifecycle, payment term management, revenue processing, and splits
Billing Items WorkflowDownstream: processRevenueUpdate creates billing_item and billing_item_detail records from payment_term data. These are the receivables applied in cash management.
Worksheets WorkflowDownstream: billing_item_detail rows (REV and PAY) are the receivables that users apply when a cash receipt arrives.
Assignments Workflowdeal.deal_id is the top level of the responsibility assignment hierarchy. If no deal-level assignment exists, the system walks up to client then department.
Tax Forms Workflowsales_item.service_country_cd and service_state_cd drive tax jurisdiction determination at worksheet apply time via WithholdingTaxService.

11. Gherkin Scenarios

gherkin
Feature: Deals - Deal Master Management

  Scenario: Create a new deal with parties
    Given no deal exists for client "Taylor Swift" (party_id = 101)
    When a user creates a deal with deal_name = "2026 Eras Tour - Stadium Block"
    And assigns a party with party_id = 202 (StadiumCo), party_role_type_cd = 'BUYER', deal_party_commission_perc = '0.0000'
    And assigns a party with party_id = 101 (Taylor Swift), party_role_type_cd = 'CLIENT', deal_party_commission_perc = '15.0000'
    Then a new deal row exists with deal_name = "2026 Eras Tour - Stadium Block"
    And deal.deal_reference is auto-generated matching the pattern 'DEAL-[A-Z0-9]+'
    And two deal_party rows exist linked to the new deal.deal_id
    And deal_party.deal_party_commission_perc = '15.0000' for party_id = 101

  Scenario: Edit deal party commission percentage
    Given a deal (deal_id = 500) has a deal_party row (deal_party_id = 88) with deal_party_commission_perc = '15.0000'
    When a user updates deal_party_id = 88 to deal_party_commission_perc = '20.0000'
    Then deal_party.deal_party_commission_perc = '20.0000' for deal_party_id = 88

  Scenario: Remove a party from a deal via full-list upsert
    Given a deal (deal_id = 500) has deal_party rows for deal_party_id = 88, 89, and 90
    When a user saves the deal with a party list containing only deal_party_id = 88 and deal_party_id = 89
    Then the deal_party row with deal_party_id = 90 no longer exists
    And deal_party rows for deal_party_id = 88 and 89 still exist

  Scenario: Blank commission value is defaulted to zero on save
    Given a user creates a deal party with deal_party_commission_perc left blank
    Then deal_party.deal_party_commission_perc = '0' in the saved deal_party row
gherkin
Feature: Deals - Revenue Processing

  Scenario: Process revenue update succeeds for a valid sales block
    Given a sales_block (sales_block_id = 300) has process_status_cd = 'U'
    And the associated sales_item has all required fields present and gross_amt = '75000.00'
    And SUM(payment_term.gross_amt) for sales_block_id = 300 equals '75000.00'
    And all deal, party, and code_master references resolve successfully
    When a user selects the sales item row and clicks "Process Revenue Update"
    Then sales_block.process_status_cd = 'P' for sales_block_id = 300
    And one revenue_items row exists with sales_item_ref matching the block's sales_item
    And N billing_item rows exist (one per payment_term in the block), each with two billing_item_detail rows typed 'REV' and 'PAY'

  Scenario: Process revenue update fails referential validation
    Given a sales_block (sales_block_id = 301) has process_status_cd = 'U'
    And its associated sales_item references deal_id = 9999 which does not exist in the deal table
    When the system processes sales_block_id = 301
    Then sales_block.process_status_cd = 'F' for sales_block_id = 301
    And sales_block.error_description contains the referential failure message
    And no revenue_items or billing_item rows are created

  Scenario: Consistency validation blocks immutable field change
    Given a revenue_items row exists with sales_item_ref = 'REF-ABCD12', current_item_ind = true, and uta_entity_id = 10
    And a new sales_block (sales_block_id = 302) has a sales_item with sales_item_ref = 'REF-ABCD12' and uta_entity_id = 20
    When the system processes sales_block_id = 302
    Then sales_block.process_status_cd = 'F' for sales_block_id = 302
    And sales_block.error_description describes an immutable field mismatch on uta_entity_id
gherkin
Feature: Deals - Sales Item Management

  Scenario: Edit a sales pipeline item with metadata-only change
    Given a sales_item (sales_item_id = 400) exists with sales_item_ref = 'REF-XYZ', sales_item_ver = 2
    And it has two payment_term rows
    When a user edits the sales_item name from "Q1 License" to "Q1 License Fee"
    Then a new sales_block is created with a new sales_item row at sales_item_ver = 3 and sales_item_ref = 'REF-XYZ'
    And the two payment_term rows are copied with incremented payment_term_ver values

  Scenario: Split a sales pipeline payment item
    Given a sales_item (sales_item_id = 410) has gross_amt = '100000.00' and exactly one payment_term with gross_amt = '100000.00'
    When a user splits with splitAmount = 40000.00 and newItemDueDate = '2026-06-30'
    Then the original payment_term.gross_amt is reduced to '60000.00'
    And a new sales_item exists with gross_amt = '40000.00' and one payment_term with due_dt = '2026-06-30'

  Scenario: Split fails when the item has multiple payment terms
    Given a sales_item (sales_item_id = 420) has two payment_term rows
    When a user attempts to split sales_item_id = 420
    Then the system returns an error that the item must have exactly one payment term to be split
    And no changes are made to any rows
gherkin
Feature: Deals - Deal Search

  Scenario: Search for active deals by name
    Given multiple deal rows exist, some with active_ind = true and some with active_ind = false
    When a user enters deal_name = "Eras Tour", checks the Active Only filter, and clicks Search
    Then only deal rows where deal.deal_name ILIKE '%Eras Tour%' AND deal.active_ind = true are returned
    And the results grid displays the matching rows

  Scenario: View party details for a deal in search results
    Given a search has returned deal (deal_id = 500) in the results grid
    And deal_id = 500 has two deal_party rows linked to it
    When a user clicks the row for deal_id = 500
    Then getDealById is executed with deal_id = 500
    And the Deal Parties panel displays both deal_party rows with party names and commission fields

  Scenario: Deep-link to a specific deal via URL parameter
    Given a deal with deal_id = 500 exists
    When a user navigates to /deals?dealId=500
    Then getDealById is executed with deal_id = 500
    And the deal appears in the results grid as the only result
    And the Deal Parties panel is automatically populated for deal_id = 500

Confidential. For internal use only.