Worksheets Procedures
1. Executive Summary
Purpose
This document describes every data mutation operation in the worksheet domain — the step-by-step procedures that create, update, reverse, and delete records across the cash_receipt_worksheet, cash_receipt_application, cash_receipt_application_deduction, cash_receipt_client_ledger, and cash_receipt_payout tables. It serves as the definitive reference for implementing the worksheet lifecycle (Draft, Applied, Settled, Approved, Returned) and all associated sub-operations including receivable application, client ledger application, payout management, deduction handling, and the three-document return process.
Scope
Covered:
- Worksheet creation from a cash receipt split
- Adding, updating, and removing receivable applications (
cash_receipt_application) - Adding, updating, and removing client ledger applications (
cash_receipt_client_ledger) - Adding, updating, and removing payout records (
cash_receipt_payout) - Application deduction management (
cash_receipt_application_deduction) - Status transitions: Draft to Applied, Applied to Settled, Settled to Approved
- Reverse status transitions (rejections): Settled to Applied, Applied to Draft
- The return (reopen) process from Approved status producing three documents
- Worksheet abandonment and deletion
- Locking, classification, and bilateral lock rules for sent payments
- Balance and total applied calculations
- Billing item closure on approval
Not covered (documented separately):
- Settlement creation and approval — see Settlements Data Model
- Cash receipt and split lifecycle — see Cash Receipts Data Model
- Billing item detail types (REV/PAY) — see Billing Items Data Model
- Payment item bank transmission — see Settlements Procedures
2. Key Procedures
2.1 Create Worksheet
Operation: createWorksheet
Trigger: User with CASH_MANAGER or IT role initiates worksheet creation for a cash receipt split.
Input Parameters:
cashReceiptSplitId: Integer —cash_receipt_split.cash_receipt_split_iduserId: String — identifier for the authenticated user performing the operation
Creates a new Draft worksheet linked to a specific cash receipt split and locks the parent receipt for editing.
Step 1. Validate Split Exists
- Source:
cash_receipt_splitwherecash_receipt_split_id= inputcashReceiptSplitId. - Action: SELECT from
cash_receipt_split. - Logic:
- If no row is found, abort with error "Cash receipt split not found".
Step 2. Validate Receipt Eligibility
- Source:
cash_receiptviacash_receipt_split.cash_receipt_id. - Action: SELECT from
cash_receipt. - Logic:
- If
cash_receipt.posting_status_cd='V', abort: "Cannot create worksheet for a voided cash receipt". - If
cash_receipt.posting_status_cd='P', abort: "Cannot create worksheet for a posted cash receipt".
- If
Step 3. Check for Existing Active Worksheet
- Source:
cash_receipt_worksheetwherecash_receipt_split_id= input andcurrent_item_ind=true. - Action: SELECT from
cash_receipt_worksheet. - Logic:
- If a record is found, abort: "Active worksheet already exists for this cash receipt split".
Step 4. Check Receipt Lock
- Source:
cash_receipt.locked_by_user_id. - Action: Read lock field from
cash_receipt. - Logic:
- If
locked_by_user_idis non-null and does not matchuserId, abort: "This receipt is currently being worked on by another user".
- If
Step 5. Lock the Receipt
- Source:
cash_receiptrecord from Step 2. - Action: UPDATE
cash_receipt. - Logic:
- Set
cash_receipt.locked_by_user_id=userId.
- Set
Step 6. Create Worksheet
- Source: Validated
cashReceiptSplitIdfrom Step 1. - Action: INSERT into
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_split_id= inputcashReceiptSplitId. - Set
cash_receipt_worksheet_status_cd='D'(Draft). - Set
current_item_ind=true. - Set
created_by=userId,updated_by=userId,created_dt= now,updated_dt= now.
- Set
Side-effects:
- Sets
cash_receipt.locked_by_user_idtouserId, preventing concurrent worksheet creation by another user.
Postconditions:
- A new
cash_receipt_worksheetrecord exists withcash_receipt_worksheet_status_cd='D'andcurrent_item_ind=true. - The parent
cash_receiptis locked byuserId.
2.2 Get or Create Worksheet
Operation: getOrCreateWorksheet
Trigger: User opens a cash receipt for editing; the system finds or creates the current worksheet automatically.
Input Parameters:
cashReceiptId: Integer —cash_receipt.cash_receipt_iduserId: String — identifier for the authenticated user
Finds the existing current worksheet for a cash receipt, or creates one using the default split. Ensures the receipt is locked for the current user.
Step 1. Check for Existing Worksheet
- Source:
cash_receipt_worksheetjoined tocash_receipt_splitjoined tocash_receipt, wherecash_receipt_id= input andcurrent_item_ind=true. - Action: SELECT from
cash_receipt_worksheet. - Logic:
- If found, validate that
cash_receipt.locked_by_user_idis null or matchesuserId; if another user holds the lock, abort. - If found and lock is clear, set
cash_receipt.locked_by_user_id=userIdand return the existing worksheet.
- If found, validate that
Step 2. Find Default Split
- Source:
cash_receipt_splitwherecash_receipt_id= input. - Action: SELECT from
cash_receipt_split. - Logic:
- If no split exists, INSERT a new
cash_receipt_splitwithsplit_amt='0'andsplit_sequence= 1.
- If no split exists, INSERT a new
Step 3. Delegate to Create Worksheet
- Source:
cash_receipt_split_idfrom Step 2. - Action: Delegate to Create Worksheet using the found or newly created
cash_receipt_split_id. - Logic:
- All validations and lock logic from Create Worksheet apply.
Side-effects:
- May INSERT a new
cash_receipt_splitif none exists. - Locks the parent
cash_receiptby settinglocked_by_user_id=userId.
Postconditions:
- A current worksheet exists for the receipt and is accessible to
userId. - The parent
cash_receiptis locked byuserId.
2.3 Add Receivable Application
Operation: addApplication
Trigger: User selects a billing item on the worksheet and enters an amount to apply.
Input Parameters:
cashReceiptWorksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idbillingItemDetailId: Integer —billing_item_detail.billing_item_detail_idcashReceiptAmtApplied: Decimal(15,2) — amount to apply (transmitted as string)deductionAmtApplied: Decimal(15,2), optional — deduction amount (transmitted as string)userId: String — identifier for the authenticated userskipTotalValidation: Boolean, optional — bypass total validation during batch operations
Creates a cash_receipt_application record linking a worksheet to a billing item detail (REV or PAY).
Step 1. Validate Worksheet Status
- Source:
cash_receipt_worksheetwherecash_receipt_worksheet_id= input. - Action: SELECT from
cash_receipt_worksheet. - Logic:
- If
cash_receipt_worksheet_status_cd!='D', abort: "Cannot modify worksheet in Submitted or Approved status".
- If
Step 2. Validate Billing Item Detail Exists
- Source:
billing_item_detailjoined tobilling_itemwherebilling_item_detail_id= input. - Action: SELECT from
billing_item_detail. - Logic:
- If no row found, abort: "Billing item not found".
Step 3. Validate Currency Match
- Source:
cash_receiptvia the worksheet → split → receipt chain. - Action: Compare
billing_item.billing_item_currency_cdtocash_receipt.currency_cd. - Logic:
- If currencies differ, abort with "Currency mismatch: Cash receipt is
<X>, billing item is<Y>".
- If currencies differ, abort with "Currency mismatch: Cash receipt is
Step 4. Validate Total Does Not Exceed Receipt Amount
- Source: Computed sum of all
cash_receipt_application.cash_receipt_amt_applied+cash_receipt_client_ledger.cash_receipt_amt_applied+ non-settlementcash_receipt_payout.payment_item_amt+cash_receipt_application_deduction.deduction_amt_appliedfor the worksheet. - Action: Compare
currentTotal + newAmounttocash_receipt.net_receipt_amt. - Logic:
- If
currentTotal + newAmount > net_receipt_amt + 0.005, abort: over-application. - If
skipTotalValidation=true, skip this step entirely.
- If
Step 5. Insert Application
- Source: Validated input parameters.
- Action: INSERT into
cash_receipt_application. - Logic:
- Set
cash_receipt_worksheet_id= input. - Set
billing_item_detail_id= input. - Set
cash_receipt_amt_applied= input amount. - Set
created_by=userId,updated_by=userId.
- Set
Step 6. Insert Deduction (Conditional)
- Source:
billing_item_deductionwherebilling_item_detail_id= input, to determine deduction type. - Action: INSERT into
cash_receipt_application_deduction(only ifdeductionAmtAppliedis provided and non-zero). - Logic:
- Set
cash_receipt_application_id= newly created application ID. - Set
deduction_amt_applied= input deduction amount. - Set
billing_item_deduction_type_cd= first matching type from billing item deductions if available.
- Set
NOTE
Negative application amounts are permitted to allow credit adjustments. Over-application to individual billing item details is allowed; the only constraint is the worksheet total against the receipt amount.
Side-effects:
- None beyond the inserted records.
Postconditions:
- A new
cash_receipt_applicationrecord exists linked to the worksheet and billing item detail. - If a deduction was provided, a corresponding
cash_receipt_application_deductionrecord exists.
2.4 Add Receivable (REV + PAY Pair)
Operation: addReceivable
Trigger: User adds a billing item to the worksheet; both REV and PAY sides are applied in a single operation.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idbillingItemId: Integer —billing_item.billing_item_idrevDetailId: Integer, optional —billing_item_detail.billing_item_detail_idfor the REV detailpayDetailId: Integer, optional —billing_item_detail.billing_item_detail_idfor the PAY detailrevAmount: Decimal(15,2) — REV amount to applypayAmount: Decimal(15,2) — PAY amount to applyrevDeductionAmount: Decimal(15,2), optional — REV deductionpayDeductionAmount: Decimal(15,2), optional — PAY deduction
Creates both REV and PAY application records for a single billing item in one atomic operation.
Step 1. Apply REV Side
- Source:
revDetailIdandrevAmountfrom input. - Action: Delegate to Add Receivable Application with REV parameters.
- Logic:
- Execute only if
revAmount>= 0 andrevDetailIdis provided. - Total validation runs for the REV application.
- Execute only if
Step 2. Apply PAY Side
- Source:
payDetailIdandpayAmountfrom input. - Action: Delegate to Add Receivable Application with PAY parameters.
- Logic:
- Execute only if
payAmount>= 0 andpayDetailIdis provided. - Set
skipTotalValidation=truebecause the REV application in Step 1 already validated. Both REV and PAY are a single logical add.
- Execute only if
NOTE
Zero amounts are allowed to add an item to the worksheet without applying cash. This supports scenarios where the user wants to track a receivable on the worksheet before deciding on amounts.
Side-effects:
- None beyond the records created by the delegated Add Receivable Application calls.
Postconditions:
- Up to two
cash_receipt_applicationrecords exist (one REV, one PAY) for the billing item.
2.5 Update Receivable Application
Operation: updateApplication
Trigger: User changes the amount on an existing receivable application row in the worksheet.
Input Parameters:
cashReceiptApplicationId: Integer —cash_receipt_application.cash_receipt_application_idcashReceiptAmtApplied: Decimal(15,2) — new amount (transmitted as string)deductionAmtApplied: Decimal(15,2), optional — new deduction amountuserId: String — identifier for the authenticated userskipTotalValidation: Boolean, optional — bypass total validation during batch operations
Updates the applied amount on an existing cash_receipt_application record.
Step 1. Validate Application Exists
- Source:
cash_receipt_applicationwherecash_receipt_application_id= input. - Action: SELECT from
cash_receipt_application. - Logic:
- If no row found, abort.
Step 2. Check Lock Status
- Source:
participant_settlement→participant_settlement_item→payment_itemchain linked to the application. - Action: Evaluate
payment_item.payment_execution_status_cdfor all linked payment items. - Logic:
- If any linked
payment_item.payment_execution_status_cdis in['PROCESSING', 'SENT', 'PAID', 'ACKNOWLEDGED'], the application is locked. - If locked, abort.
- If any linked
Step 3. Validate Worksheet Is in Draft
- Source: Parent
cash_receipt_worksheet. - Action: SELECT
cash_receipt_worksheet_status_cd. - Logic:
cash_receipt_worksheet_status_cdmust be'D'. Otherwise abort.
Step 4. Validate Total Does Not Exceed Receipt Amount
- Source: Computed worksheet total (same as Add Receivable Application Step 4), accounting for the difference between old and new amounts.
- Action: Compare new projected total to
cash_receipt.net_receipt_amt. - Logic:
- Skip if
skipTotalValidation=true.
- Skip if
Step 5. Update Application
- Source: Validated
cashReceiptApplicationId. - Action: UPDATE
cash_receipt_application. - Logic:
- Set
cash_receipt_amt_applied= new amount. - Set
updated_by=userId,updated_dt= now.
- Set
Step 6. Update Deductions (Conditional)
- Source: Existing
cash_receipt_application_deductionrecords for this application. - Action: DELETE existing deductions; conditionally INSERT new ones.
- Logic:
- Delete all
cash_receipt_application_deductionwherecash_receipt_application_id= input. - If new
deductionAmtAppliedis non-zero:- Fetch
billing_item_deductionrecords for the application'sbilling_item_detail_id. - If a single deduction type: insert one
cash_receipt_application_deductionwith the full amount. - If multiple deduction types: prorate across types. For each type:
proportion = typeBalance / totalBalance,proratedAmount = deductionAmount * proportion. Insert one row per type.
- Fetch
- Delete all
Side-effects:
- All prior deductions for the application are deleted and replaced.
Postconditions:
cash_receipt_application.cash_receipt_amt_appliedreflects the new amount.cash_receipt_application_deductionrecords reflect the new deduction, if provided.
2.6 Remove Receivable Application
Operation: removeApplication
Trigger: User removes a receivable application row from the worksheet.
Input Parameters:
applicationId: Integer —cash_receipt_application.cash_receipt_application_iduserId: String — identifier for the authenticated user
Deletes a cash_receipt_application record and its dependent deductions.
Step 1. Validate Application Exists
- Source:
cash_receipt_applicationwherecash_receipt_application_id= input. - Action: SELECT from
cash_receipt_application. - Logic:
- If no row found, abort.
Step 2. Validate Worksheet Is in Draft
- Source: Parent
cash_receipt_worksheet. - Action: SELECT
cash_receipt_worksheet_status_cd. - Logic:
cash_receipt_worksheet_status_cdmust be'D'. Otherwise abort.
Step 3. Check Lock Status
- Source: Same lock check as Update Receivable Application Step 2.
- Action: Evaluate linked payment item statuses.
- Logic:
- If locked, abort.
Step 4. Check Bilateral Lock on REV Applications
- Source: Paired PAY application on the same
billing_item_idwith the sameparticipant_settlement_id. - Action: Evaluate
is_read_onlystate of the paired PAY application. - Logic:
- If this is a REV application and its positionally paired PAY application is locked (read-only), abort: cannot remove REV when its paired PAY is locked.
Step 5. Delete Deductions
- Source:
cash_receipt_application_deductionwherecash_receipt_application_id= input. - Action: DELETE from
cash_receipt_application_deduction. - Logic:
- Remove all child deduction records before deleting the parent.
Step 6. Delete Application
- Source:
cash_receipt_applicationwherecash_receipt_application_id= input. - Action: DELETE from
cash_receipt_application. - Logic:
- Remove the application record.
Side-effects:
- All associated
cash_receipt_application_deductionrecords are deleted.
Postconditions:
- The application and all its deductions no longer exist.
2.7 Add Client Ledger Application
Operation: addClientLedgerApplication
Trigger: User applies cash to a client on-account ledger entry rather than a specific receivable.
Input Parameters:
cashReceiptWorksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idclientLedgerId: Integer —client_ledger.client_ledger_iddealId: Integer, optional —deal.deal_idutaEntityId: Integer, optional —uta_entity.uta_entity_iddepartmentId: Integer, optional —department.department_idclientId: Integer, optional —party.party_idcashReceiptAmtApplied: Decimal(15,2) — amount applied (transmitted as string)userId: String — identifier for the authenticated user
Creates a cash_receipt_client_ledger record on a worksheet.
Step 1. Insert Client Ledger Application
- Source: Validated input parameters.
- Action: INSERT into
cash_receipt_client_ledger. - Logic:
- Set
cash_receipt_worksheet_id= input. - Set
client_ledger_id= input. - Set
deal_id= input (nullable). - Set
uta_entity_id= input (nullable). - Set
department_id= input (nullable). - Set
client_id= input (nullable). - Set
cash_receipt_amt_applied= input amount. - Set
created_by=userId,updated_by=userId.
- Set
Side-effects:
- None beyond the inserted record.
Postconditions:
- A new
cash_receipt_client_ledgerrecord exists linked to the worksheet and client ledger.
2.8 Create On-Account Client Ledger
Operation: createOnAccountClientLedger
Trigger: User creates a new on-account ledger entry and immediately links it to the worksheet.
Input Parameters:
clientId: Integer —party.party_idclientLedgerName: String — descriptive name for the ledger entryworksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_iddealId: Integer, optional —deal.deal_idbuyerId: Integer, optional —party.party_idutaEntityId: Integer, optional —uta_entity.uta_entity_iddepartmentId: Integer, optional —department.department_id
Creates a new client_ledger record and immediately adds a cash_receipt_client_ledger application for it.
Step 1. Create Client Ledger Entry
- Source: Input parameters.
- Action: INSERT into
client_ledger. - Logic:
- Set
client_id= input. - Set
contracted_party_id= inputclientId. - Set
client_ledger_type_cd='OA'(On-Account). - Set
client_ledger_status_cd='C'(Current/closed initial state). - Set
client_ledger_name= input name. - Set
client_ledger_amt='0.00'. - Set
client_ledger_currency_cd='USD'. - Set
client_ledger_open_item_ind=true. - Set
posting_status_cd='D'(Draft).
- Set
Step 2. Link to Worksheet
- Source: Newly created
client_ledger_idfrom Step 1. - Action: INSERT into
cash_receipt_client_ledger. - Logic:
- Set
cash_receipt_worksheet_id= inputworksheetId. - Set
client_ledger_id= newly created ledger ID. - Set
cash_receipt_amt_applied='0.00'. - Set all dimensional FKs (
deal_id,uta_entity_id,department_id,client_id) from input.
- Set
Side-effects:
- Creates a new
client_ledgerrecord.
Postconditions:
- A new
client_ledgerrecord exists withclient_ledger_open_item_ind=true. - A corresponding
cash_receipt_client_ledgerrecord links it to the worksheet with a zero amount.
2.9 Update Client Ledger Application
Operation: updateClientLedgerApplication
Trigger: User changes the amount on a client ledger application in the worksheet.
Input Parameters:
cashReceiptClientLedgerId: Integer —cash_receipt_client_ledger.cash_receipt_client_ledger_idcashReceiptAmtApplied: Decimal(15,2) — new amount (transmitted as string)userId: String — identifier for the authenticated user
Updates the amount on an existing cash_receipt_client_ledger record.
Step 1. Update Client Ledger Application
- Source:
cash_receipt_client_ledgerwherecash_receipt_client_ledger_id= input. - Action: UPDATE
cash_receipt_client_ledger. - Logic:
- Set
cash_receipt_amt_applied= new amount. - Set
updated_by=userId,updated_dt= now.
- Set
Side-effects:
- None beyond the updated record.
Postconditions:
cash_receipt_client_ledger.cash_receipt_amt_appliedreflects the new amount.
2.10 Remove Client Ledger Application
Operation: removeClientLedgerApplication
Trigger: User removes a client ledger application row from the worksheet.
Input Parameters:
cashReceiptClientLedgerId: Integer —cash_receipt_client_ledger.cash_receipt_client_ledger_iduserId: String — identifier for the authenticated user
Deletes a cash_receipt_client_ledger record from a worksheet.
Step 1. Delete Client Ledger Application
- Source:
cash_receipt_client_ledgerwherecash_receipt_client_ledger_id= input. - Action: DELETE from
cash_receipt_client_ledger. - Logic:
- Remove the record unconditionally.
Side-effects:
- None beyond the deleted record.
Postconditions:
- The
cash_receipt_client_ledgerrecord no longer exists.
2.11 Create Payout Record
Operation: createPayout
Trigger: User adds a passthrough, VAT pass-through, or loan payout line to the worksheet; or settlements service creates settlement payouts during the settlement process.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idpayoutPartyId: Integer —party.party_idpaymentPartyBankId: Integer, optional —bank_account.bank_account_idpaymentItemName: String — descriptionpaymentItemAmt: Decimal(15,2) — amount (transmitted as string)paymentItemTypeCd: String —'S','P','L','R', or'V'paymentItemCurrencyCd: String — ISO currency code, default'USD'paymentDate: Date, optional — target payment datedoNotSendInd: Boolean, optional — defaultfalsedealId,buyerId,utaEntityId,departmentId: Integer, optional — dimensional FKsuserId: String — identifier for the authenticated user
Creates a cash_receipt_payout record on a worksheet.
Step 1. Insert Payout
- Source: Validated input parameters.
- Action: INSERT into
cash_receipt_payout. - Logic:
- Map all input fields directly to corresponding columns.
- Set
payout_status_cd='PENDING'. - Set
created_by=userId,updated_by=userId.
NOTE
Settlement payouts (payment_item_type_cd = 'S') are excluded from the worksheet balance total calculation. Only non-settlement payouts (types 'P', 'L', 'R', 'V') contribute to the total applied.
Side-effects:
- None beyond the inserted record.
Postconditions:
- A new
cash_receipt_payoutrecord exists withpayout_status_cd='PENDING'.
2.12 Create VAT Pass-Through Payout
Operation: createVatPassThroughPayout
Trigger: System detects UK VAT applies to a billing item and creates the VAT pass-through payout. Idempotent — safe to call multiple times.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idbillingItemId: Integer —billing_item.billing_item_idclientPartyId: Integer —party.party_idvatAmt: Decimal(15,2) — VAT amount (transmitted as string)currencyCd: String — ISO currency codeuserId: String — identifier for the authenticated user
Creates a VAT pass-through payout for UK Artist Fee VAT, checking for idempotency before inserting.
Step 1. Check for Existing VAT Payout
- Source:
cash_receipt_payoutwherecash_receipt_worksheet_id= input andpayment_item_type_cd='V'. - Action: SELECT from
cash_receipt_payout. - Logic:
- If a record already exists, return immediately with no insert (idempotent behavior).
Step 2. Fetch Deal Context
- Source:
billing_itemwherebilling_item_id= input. - Action: SELECT
deal_id,buyer_id,uta_entity_id,department_idfrombilling_item. - Logic:
- Collect dimensional foreign keys for the payout record.
Step 3. Delegate to Create Payout
- Source: Validated parameters from Steps 1 and 2.
- Action: Delegate to Create Payout Record.
- Logic:
- Set
paymentItemTypeCd='V'. - Set
paymentItemName='UK VAT Pass-Through on Artist Fee'. - Set
paymentItemAmt= inputvatAmt. - Set
payoutPartyId= inputclientPartyId.
- Set
Side-effects:
- None if a VAT payout already exists (idempotent).
Postconditions:
- Exactly one
cash_receipt_payoutrecord withpayment_item_type_cd='V'exists for the worksheet.
2.13 Update Payout Record
Operation: updatePayout
Trigger: User changes the amount or do_not_send_ind flag on a payout row in the worksheet.
Input Parameters:
cashReceiptPayoutId: Integer —cash_receipt_payout.cash_receipt_payout_idpaymentItemAmt: Decimal(15,2), optional — new amount (transmitted as string)doNotSendInd: Boolean, optional — new flag valueuserId: String — identifier for the authenticated user
Updates amount and/or do_not_send_ind on a cash_receipt_payout record.
Step 1. Update Payout
- Source:
cash_receipt_payoutwherecash_receipt_payout_id= input. - Action: UPDATE
cash_receipt_payout. - Logic:
- Set provided fields (only those supplied in the update call).
- Set
updated_by=userId,updated_dt= now.
Side-effects:
- None beyond the updated record.
Postconditions:
cash_receipt_payoutreflects the new amount and/or flag value.
2.14 Remove Payout Record
Operation: removePayout
Trigger: User removes a payout row from the worksheet.
Input Parameters:
cashReceiptPayoutId: Integer —cash_receipt_payout.cash_receipt_payout_iduserId: String — identifier for the authenticated user
Deletes a cash_receipt_payout record.
Step 1. Delete Payout
- Source:
cash_receipt_payoutwherecash_receipt_payout_id= input. - Action: DELETE from
cash_receipt_payout. - Logic:
- Remove the record unconditionally.
Side-effects:
- None beyond the deleted record.
Postconditions:
- The
cash_receipt_payoutrecord no longer exists.
2.15 Manage Application Deductions
Operation: manageApplicationDeduction
Trigger: User adds, updates, or removes a deduction on an individual receivable application.
Input Parameters:
cashReceiptApplicationDeductionId: Integer, optional —cash_receipt_application_deduction.cash_receipt_application_deduction_id(required for update/delete)cashReceiptApplicationId: Integer —cash_receipt_application.cash_receipt_application_id(required for create)billingItemDeductionTypeCd: String, optional — deduction type codedeductionAmtApplied: Decimal(15,2) — amount (transmitted as string)userId: String — identifier for the authenticated user
Manages cash_receipt_application_deduction records independently of the parent application save flow. Supports create, update, and delete operations.
Step 1. Create Deduction
- Source: Validated
cashReceiptApplicationId. - Action: INSERT into
cash_receipt_application_deduction. - Logic:
- Set
cash_receipt_application_id= input. - Set
billing_item_deduction_type_cd= input (nullable). - Set
deduction_amt_applied= input amount. - Set
created_by=userId,updated_by=userId,created_dt= now,updated_dt= now.
- Set
Step 2. Update Deduction (alternative path)
- Source:
cash_receipt_application_deductionwherecash_receipt_application_deduction_id= input. - Action: UPDATE
cash_receipt_application_deduction. - Logic:
- Set
deduction_amt_appliedand/orbilling_item_deduction_type_cdas provided. - Set
updated_by=userId,updated_dt= now.
- Set
Step 3. Delete Deduction (alternative path)
- Source:
cash_receipt_application_deductionwherecash_receipt_application_deduction_id= input. - Action: DELETE from
cash_receipt_application_deduction. - Logic:
- Remove the record unconditionally.
Side-effects:
- None beyond the inserted, updated, or deleted record.
Postconditions:
- The
cash_receipt_application_deductionstate reflects the requested create, update, or delete operation.
2.16 Apply Worksheet (D to P)
Operation: applyWorksheet
Trigger: User with CASH_MANAGER or IT role clicks Apply on a Draft worksheet.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idcanApplyWorksheet: Boolean — permission flag for the calling useruserId: String — identifier for the authenticated user
Transitions a worksheet from Draft to Applied status. Finalizes cash applications and stages REV entries and client ledger entries for GL posting.
Step 1. Validate Preconditions
- Source:
cash_receipt_worksheetwherecash_receipt_worksheet_id= input. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'D'. Otherwise abort (APPLY-01).- At least one record must exist across
cash_receipt_application,cash_receipt_client_ledger, orcash_receipt_payoutfor this worksheet. Otherwise abort (APPLY-02). canApplyWorksheetmust betrue. Otherwise abort (APPLY-04).- Partial application is allowed — worksheet balance does not need to equal zero (APPLY-03).
Step 2. Update Worksheet Status
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='P'(Applied). - Set
posting_status_cd='U'(Unposted — ready for GL pickup). - Set
applied_dt= now. - Set
applied_by= user name. - Set
updated_dt= now,updated_by= user name.
- Set
IMPORTANT
posting_status_cd = 'U' signals to the accounting job that this worksheet's REV applications and client ledger entries are ready for GL posting. PAY applications do NOT post to GL at Apply time — they post only after bank confirmation of the payment.
Side-effects:
- The GL posting job will pick up this worksheet's REV applications and client ledger entries on its next run.
Postconditions:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd='P'.cash_receipt_worksheet.posting_status_cd='U'.
2.17 Settle Worksheet (P to T)
Operation: settleWorksheet
Trigger: User with CASH_PROCESSOR or IT role clicks Settle on an Applied worksheet.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idcanSettleWorksheet: Boolean — permission flag for the calling useruserId: String — identifier for the authenticated user
Transitions a worksheet from Applied to Settled status. All PAY applications must have settlements before this transition.
Step 1. Validate Preconditions
- Source:
cash_receipt_worksheetand linkedcash_receipt_applicationrecords. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'P'. Otherwise abort (SETTLE-01).- All PAY-type applications must have a non-null
participant_settlement_id. Otherwise abort (SETTLE-02). canSettleWorksheetmust betrue. Otherwise abort (SETTLE-03).
Step 2. Update Worksheet Status
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='T'(Settled). - Set
settled_dt= now. - Set
settled_by= user name. - Set
updated_dt= now,updated_by= user name.
- Set
Step 3. Update Linked Settlements
- Source: All
participant_settlementrecords linked to this worksheet's PAY applications. - Action: UPDATE
participant_settlement. - Logic:
- Set
participant_settlement_status_cd='T'(Settled) for each.
- Set
Side-effects:
- All linked
participant_settlementrecords are updated to Settled status.
Postconditions:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd='T'.- All linked
participant_settlement.participant_settlement_status_cd='T'.
2.18 Approve Worksheet (T/D/S to A)
Operation: approveWorksheet
Trigger: User with SETTLEMENT_APPROVER or IT role clicks Approve on a Settled (or Draft with elevated privilege) worksheet.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idhasApprovePrivilege: Boolean — permission flag; required to betruewhen approving from Draft statususerId: String — identifier for the authenticated user
Transitions a worksheet to Approved status. Creates payment items from settlement payouts, resets do_not_send_ind on unlocked payments, and closes fully paid billing items.
Step 1. Validate Preconditions
- Source:
cash_receipt_worksheetand linked applications. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'D','S'(legacy), or'T'. Otherwise abort.- If status is
'D',hasApprovePrivilegemust betrue. Otherwise abort. - At least one application must exist. Otherwise abort.
Step 2. Update Worksheet Status
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='A'(Approved). - Set
approved_dt= now. - Set
approved_by=userId. - Set
updated_dt= now,updated_by=userId.
- Set
Step 3. Release Receipt Lock
- Source: Parent
cash_receiptlinked to the worksheet. - Action: UPDATE
cash_receipt. - Logic:
- Set
locked_by_user_id=null.
- Set
Step 4. Submit Settlements (if Draft shortcut)
- Source: All
participant_settlementrecords linked to this worksheet. - Action: Delegate to settlement service.
- Logic:
- Only if worksheet was in Draft status (
'D'): call settlement service to submit settlements, which creates payouts from settlement items.
- Only if worksheet was in Draft status (
Step 5. Approve All Linked Settlements
- Source: All
participant_settlementrecords linked to this worksheet. - Action: UPDATE
participant_settlement. - Logic:
- Set
participant_settlement_status_cd='A'(Approved) for each.
- Set
Step 6. Create Payment Items from Payouts
- Source: All
cash_receipt_payoutrecords for this worksheet with a linkedparticipant_settlement_item. - Action: INSERT into
payment_item; UPDATEcash_receipt_payout. - Logic:
- For each
participant_settlement_item, create a correspondingpayment_itemrecord. - Update
cash_receipt_payout.payment_item_idto reference the new payment item.
- For each
Step 7. Reset doNotSendInd on Unlocked Payment Items
- Source: All
cash_receipt_payoutrecords with a linkedpayment_item_id. - Action: UPDATE
payment_itemandparticipant_settlement_item. - Logic:
- If the payout's
do_not_send_ind=true, keep the payment'sdo_not_send_ind=true(leave unchanged). - If the payment is locked (
payment_execution_status_cdin['PROCESSING', 'SENT', 'PAID', 'ACKNOWLEDGED']), leave unchanged. - Otherwise, set
payment_item.do_not_send_ind=falseandparticipant_settlement_item.do_not_send_ind=false.
- If the payout's
Step 8. Close Fully Paid Billing Items
- Source: All unique
billing_item_idvalues referenced by this worksheet's applications. - Action: UPDATE
billing_item. - Logic:
- For each billing item, calculate balance:
(revTotalAmt + payTotalAmt) - (revCash + payCash). - If
|balance| < 0.01, setbilling_item.open_item_ind=false.
- For each billing item, calculate balance:
Side-effects:
cash_receipt.locked_by_user_idis set tonull.- All linked
participant_settlementrecords are updated to Approved status. payment_itemrecords are created for each settlement payout.- Fully paid billing items have
open_item_ind=false.
Postconditions:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd='A'.payment_itemrecords exist for all settlement payouts.- Unlocked payment items have
do_not_send_ind=falseand are eligible for bank transmission.
2.19 Reject Worksheet from Applied (P to D)
Operation: rejectWorksheetFromApplied
Trigger: User with CASH_PROCESSOR or IT role rejects an Applied worksheet to allow further editing.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idcanSettleWorksheet: Boolean — permission flaguserId: String — identifier for the authenticated user
Moves a worksheet back from Applied to Draft status so receivable applications can be edited.
Step 1. Validate Preconditions
- Source:
cash_receipt_worksheet. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'P'. Otherwise abort.canSettleWorksheetmust betrue. Otherwise abort.
Step 2. Update Worksheet Status
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='D'(Draft). - Set
applied_dt=null,applied_by=null. - Set
posting_status_cd=null(no longer ready for GL). - Set
rejected_dt= now,rejected_by= user name.
- Set
WARNING
This is a backward status transition. It is distinct from the Return (reopen) process. No reversal transactions are created. This simply re-enables editing of the receivable applications.
Side-effects:
- None beyond the worksheet status update.
Postconditions:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd='D'.- GL staging is no longer active (
posting_status_cd=null).
2.20 Reject Worksheet from Settled (T to P)
Operation: rejectWorksheetFromSettled
Trigger: User with SETTLEMENT_APPROVER or IT role rejects a Settled worksheet to allow settlements to be edited.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idcanApproveWorksheet: Boolean — permission flaguserId: String — identifier for the authenticated user
Moves a worksheet back from Settled to Applied status so settlements can be edited.
Step 1. Validate Preconditions
- Source:
cash_receipt_worksheet. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'T'. Otherwise abort.canApproveWorksheetmust betrue. Otherwise abort.
Step 2. Update Worksheet Status
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='P'(Applied). - Set
settled_dt=null,settled_by=null. - Set
rejected_dt= now,rejected_by= user name.
- Set
Step 3. Revert Linked Settlements to Draft
- Source: All
participant_settlementrecords linked to this worksheet. - Action: UPDATE
participant_settlement. - Logic:
- Set
participant_settlement_status_cd='D'(Draft) for each.
- Set
Side-effects:
- All linked
participant_settlementrecords are reverted to Draft status.
Postconditions:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd='P'.- All linked
participant_settlement.participant_settlement_status_cd='D'.
2.21 Add Billing Items to Existing Worksheet
Operation: addBillingItemsToWorksheet
Trigger: User adds one or more billing items to a worksheet that may be in Draft, Applied, or Settled status.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_iditems: Array — each withbillingItemId(Integer), optionalrevAmtApplied(Decimal),payAmtApplied(Decimal)userId: String — identifier for the authenticated user
Adds one or more billing items to an existing worksheet, rolling back status to Draft if needed.
Step 1. Validate Worksheet Is Editable
- Source:
cash_receipt_worksheet. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'D','P', or'T'andcurrent_item_indmust betrue. Otherwise abort.
Step 2. Roll Back Settled Status (Conditional)
- Source:
cash_receipt_worksheetwithcash_receipt_worksheet_status_cd='T'. - Action: UPDATE
participant_settlementandcash_receipt_worksheet. - Logic:
- If status is
'T': reset all linkedparticipant_settlement.participant_settlement_status_cd='D'. - Update worksheet:
cash_receipt_worksheet_status_cd='P', clearsettled_dt,settled_by.
- If status is
Step 3. Roll Back Applied Status (Conditional)
- Source:
cash_receipt_worksheetwithcash_receipt_worksheet_status_cd='P'(or just reverted from'T'). - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
cash_receipt_worksheet_status_cd='D'. - Clear
applied_dt,applied_by,posting_status_cd.
- Set
Step 4. Add Each Billing Item
- Source: Input
itemsarray;cash_receipt_applicationto detect already-added items. - Action: Delegate to Add Receivable Application for each item not already on the worksheet.
- Logic:
- If explicit
revAmtApplied/payAmtAppliedprovided, use those amounts. - Otherwise, use auto-apply calculator: allocate remaining cash proportionally between REV and PAY based on
revPercent, accounting for deduction balances.
- If explicit
Side-effects:
- Worksheet may be rolled back from Settled to Applied and then to Draft.
- Linked settlements may be reverted to Draft status.
Postconditions:
- All specified billing items have
cash_receipt_applicationrecords on the worksheet. cash_receipt_worksheet.cash_receipt_worksheet_status_cd='D'.
2.22 Abandon Worksheet
Operation: abandonWorksheet
Trigger: User discards a Draft worksheet without deleting it (soft delete).
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_iduserId: String — identifier for the authenticated user
Soft-deletes a Draft worksheet by marking it as non-current, preserving it as an audit record.
Step 1. Validate Worksheet Is Draft
- Source:
cash_receipt_worksheet. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'D'. Otherwise abort.
Step 2. Mark as Non-Current
- Source: Validated
worksheetId. - Action: UPDATE
cash_receipt_worksheet. - Logic:
- Set
current_item_ind=false. - Set
updated_by=userId,updated_dt= now.
- Set
Step 3. Release Receipt Lock
- Source:
cash_receiptlinked to the worksheet. - Action: UPDATE
cash_receipt. - Logic:
- Set
locked_by_user_id=null.
- Set
Side-effects:
cash_receipt.locked_by_user_idis set tonull.
Postconditions:
cash_receipt_worksheet.current_item_ind=false.- The worksheet record is preserved for audit purposes.
- The parent
cash_receiptis unlocked.
2.23 Delete Worksheet
Operation: deleteWorksheet
Trigger: User permanently deletes a Draft worksheet and all its children.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_iduserId: String — identifier for the authenticated user
Permanently deletes a Draft worksheet and all dependent records in cascade order.
Step 1. Validate Worksheet Is Draft
- Source:
cash_receipt_worksheet. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'D'. Otherwise abort.
Step 2. Release Receipt Lock
- Source:
cash_receiptlinked to the worksheet. - Action: UPDATE
cash_receipt. - Logic:
- Set
locked_by_user_id=null.
- Set
Step 3. Delete Deductions
- Source: All
cash_receipt_application_deductionrecords wherecash_receipt_application_idis in the set of applications for this worksheet. - Action: DELETE from
cash_receipt_application_deduction. - Logic:
- First collect all
cash_receipt_application_idvalues for the worksheet. - Delete all associated deduction records.
- First collect all
Step 4. Delete Applications
- Source:
cash_receipt_applicationwherecash_receipt_worksheet_id= input. - Action: DELETE from
cash_receipt_application. - Logic:
- Remove all application records for the worksheet.
Step 5. Delete Client Ledger Applications
- Source:
cash_receipt_client_ledgerwherecash_receipt_worksheet_id= input. - Action: DELETE from
cash_receipt_client_ledger. - Logic:
- Remove all client ledger application records for the worksheet.
Step 6. Delete Payouts
- Source:
cash_receipt_payoutwherecash_receipt_worksheet_id= input. - Action: DELETE from
cash_receipt_payout. - Logic:
- Remove all payout records for the worksheet.
Step 7. Delete Worksheet
- Source:
cash_receipt_worksheetwherecash_receipt_worksheet_id= input. - Action: DELETE from
cash_receipt_worksheet. - Logic:
- Remove the worksheet header record.
IMPORTANT
Deletion order matters due to foreign key constraints. Child records must be deleted before parent records. All steps execute within a transaction.
Side-effects:
cash_receipt.locked_by_user_idis set tonull.- All child records are permanently deleted.
Postconditions:
- No records remain in
cash_receipt_worksheet,cash_receipt_application,cash_receipt_application_deduction,cash_receipt_client_ledger, orcash_receipt_payoutfor the givenworksheetId.
2.24 Return (Reopen) Worksheet
Operation: reopenWorksheet
Trigger: User with SETTLEMENT_APPROVER or IT role initiates a Return on an Approved worksheet.
Input Parameters:
worksheetId: Integer —cash_receipt_worksheet.cash_receipt_worksheet_idreopenReason: String — reason for returning the worksheetuserId: String — identifier for the authenticated user
The most complex procedure. Returns an Approved worksheet by producing three documents: (1) sealed original, (2) reversal worksheet with negative entries for all items, and (3) replacement draft. This is the only way to modify an Approved worksheet.
Step 1. Validate Reopen Eligibility
- Source:
cash_receipt_worksheetand parentcash_receipt. - Action: SELECT and validate.
- Logic:
cash_receipt_worksheet_status_cdmust be'A'. Otherwise abort.cash_receipt_split_idmust be non-null. Otherwise abort: "Worksheet has no split ID, cannot reopen".cash_receipt.receipt_type_cdmust not be'WRITE_OFF'. Otherwise abort: "Write-off worksheets cannot be reopened. Use the packet recovery process instead."
Step 2. Load All Worksheet Data
- Source:
cash_receipt_application,cash_receipt_client_ledger,cash_receipt_payoutfor the worksheet. - Action: SELECT all three data sets in parallel.
- Logic:
- Load all billing item applications (with detail type enrichment).
- Load all client ledger applications.
- Load all payout records (with payment item linkage).
Step 3. Classify Items by Lock Status
- Source:
participant_settlement_itemandpayment_itemrecords linked to the worksheet's PAY applications. - Action: Evaluate
payment_item.payment_execution_status_cdfor all linked payment items. - Logic:
- Collect all unique
participant_settlement_idvalues from PAY applications. - For each settlement, fetch all
participant_settlement_itemrecords. For each item, find linkedpayment_itemrecords excluding voided (payment_item_posting_status_cd='X'). - If any linked payment has
payment_execution_status_cdin['PROCESSING', 'SENT', 'PAID', 'ACKNOWLEDGED'], mark that payment item as locked. - If ANY settlement item within a settlement is locked, mark ALL items in that settlement as locked (settlement-level lock propagation). Lock all PAY applications belonging to that settlement.
- Apply bilateral lock for REV applications: group REV and PAY applications by
billing_item_id, sort each group bycash_receipt_application_idascending. If the positionally paired PAY is locked, the REV at the same position is also locked. - For payouts: settlement payouts are locked if their
participant_settlement_item_idis in the locked set. Passthrough payouts are independently checked via their ownpayment_item.payment_execution_status_cd.
- Collect all unique
Step 4. Create Reversal Worksheet
- Source: Original worksheet and classified data from Steps 2–3.
- Action: INSERT
cash_receipt_worksheet; INSERT reversal applications, settlements, client ledger entries, and payouts. - Logic:
- Insert
cash_receipt_worksheetwithcash_receipt_split_id= same as original,cash_receipt_worksheet_status_cd='R',current_item_ind=false,worksheet_type_cd='REVERSAL',previous_worksheet_id= original ID,approved_dt= now,approved_by=userId,posting_status_cd='U',return_reason='Reversal of worksheet #<id>: <reason>'. - Reverse ALL REV applications: for each, insert
cash_receipt_applicationwithcash_receipt_amt_applied= original * -1,reversal_of_application_id= original ID,reversal_reason_cd='WORKSHEET_REOPEN'. Copy all deductions with negated amounts. - Create reversal settlements: for each unique
participant_settlement_id, insertparticipant_settlementwithparticipant_settlement_status_cd='R'. For eachparticipant_settlement_item: set all linkedpayment_item.do_not_send_ind=true; for unlocked payments also setpayment_execution_status_cd='WAITING'; insert reversal item with negatedparticipant_settlement_commission_amt. Build mapping: original settlement ID → reversal settlement ID. - Reverse ALL PAY applications: same as REV reversal, linking to reversal settlement via mapping.
- Reverse ALL client ledger entries: insert with
cash_receipt_amt_applied= original * -1,reversal_of_ledger_id= original ID,reversal_reason_cd='WORKSHEET_REOPEN'. - Reverse ALL payouts: for passthrough payouts with a
payment_item_id, setpayment_item.do_not_send_ind=true(andpayment_execution_status_cd='WAITING'if unlocked). Insert reversal payout withpayment_item_amt= original * -1,payment_item_name='Reversal: <original name>',reversal_of_payout_id= original payout ID,payment_item_id=null.
- Insert
Step 5. Create Replacement Draft
- Source: Original worksheet data and classification from Steps 2–3.
- Action: INSERT
cash_receipt_worksheet; copy all applications, settlements, ledger entries, and payouts. - Logic:
- Insert
cash_receipt_worksheetwithcash_receipt_worksheet_status_cd='D',current_item_ind=true,cash_receipt_split_id= same as original,worksheet_type_cd='REPLACEMENT',previous_worksheet_id= original ID. - Copy ALL REV applications (excluding reversal records): insert
cash_receipt_applicationwith samebilling_item_detail_idandcash_receipt_amt_applied. Copy all deductions at same (positive) amounts. - Copy ALL PAY applications: same logic as REV copy.
- Copy ALL settlements: for each, insert new
participant_settlementwithparticipant_settlement_status_cd='D'. Link new PAY applications viaparticipant_settlement_id. For eachparticipant_settlement_item: insert new item withdo_not_send_ind=true; re-point all existingpayment_item.participant_settlement_item_idto the new item; for unlocked payments setpayment_execution_status_cd='WAITING'; all payments getdo_not_send_ind=true. Build settlement item ID mapping (original → new) for payout FK remapping. - Copy ALL client ledger entries (excluding reversal records): always editable;
cash_receipt_amt_appliedis copied at same (positive) amount. - Copy ALL payouts (excluding reversal records): set
do_not_send_ind=trueon all copied payouts; preservepayment_item_idlink; remapparticipant_settlement_item_idusing the settlement item mapping.
- Insert
Step 6. Seal Original Worksheet
- Source: Original
cash_receipt_worksheetrecord. - Action: UPDATE
cash_receipt_worksheet(original). - Logic:
- Set
cash_receipt_worksheet_status_cd='R'. - Set
current_item_ind=false. - Set
returned_dt= now,returned_by=userId. - Set
return_reason= input reason. - Set
worksheet_type_cd='ORIGINAL'. - Set
replaced_by_worksheet_id= replacement draft ID.
- Set
Step 7. Return Result
- Source: Replacement draft worksheet from Step 5.
- Action: Return the replacement draft with message indicating reversal and replacement IDs.
- Logic:
- Return
data= replacement draft worksheet. - Return
message='Worksheet reopened. Reversal #<reversalId>, replacement draft #<replacementId> created.'
- Return
Side-effects:
- Original worksheet is sealed as Returned (
current_item_ind=false,worksheet_type_cd='ORIGINAL'). - A new reversal worksheet exists with negative entries for ALL items and
posting_status_cd='U'. - A new replacement draft is the active worksheet (
current_item_ind=true). - All payment items have
do_not_send_ind=true(to prevent premature bank transmission). - Unlocked payment items have
payment_execution_status_cd='WAITING'.
Postconditions:
- Three worksheets now exist for the split: the sealed original (
worksheet_type_cd='ORIGINAL'), the reversal (worksheet_type_cd='REVERSAL'), and the replacement draft (worksheet_type_cd='REPLACEMENT'). - Only the replacement draft has
current_item_ind=true. - The original's
replaced_by_worksheet_idpoints to the replacement draft. - Both the reversal and replacement have
previous_worksheet_idpointing to the original.
2.25 Save Settlement
Operation: saveSettlement
Trigger: User on the Applied worksheet selects PAY receivables and saves a settlement specifying how PAY is divided among the client's party.
Input Parameters:
dto: Object — settlement data includingitems[](settlement items) andapplicationIds[](linked PAY application IDs)settlementId: Integer, optional —participant_settlement.participant_settlement_id(for updates)userId: String — identifier for the authenticated user
Creates or updates a settlement for selected PAY applications, then immediately creates draft payouts from the settlement items.
Step 1. Validate Settlement Total
- Source:
cash_receipt_applicationfor each ID indto.applicationIds;dto.itemsamounts. - Action: Compare sums.
- Logic:
- Sum all
items[].participantSettlementCommissionAmt. - Sum all PAY
cash_receipt_application.cash_receipt_amt_appliedfor the given application IDs. - If
|settlementTotal - payApplied| > 0.01, abort: settlement total does not match PAY applied.
- Sum all
Step 2. Create or Update Settlement
- Source: Validated
dtoand optionalsettlementId. - Action: Delegate to settlement service
saveSettlement. - Logic:
- If
settlementIdis null, INSERT newparticipant_settlementandparticipant_settlement_itemrecords. - If
settlementIdis provided, UPDATE existing records. - Link each PAY application in
dto.applicationIdsby settingcash_receipt_application.participant_settlement_id= new/updated settlement ID.
- If
Step 3. Create Draft Payouts
- Source: Newly saved
participant_settlement_itemrecords. - Action: INSERT into
cash_receipt_payoutviacreatePayoutsForWorksheetInDraft(idempotent). - Logic:
- For each
participant_settlement_itemwithout an existing payout, insert acash_receipt_payoutwithpayment_item_type_cd='S'. - Skip items that already have a corresponding payout (idempotent behavior).
- For each
Side-effects:
- PAY applications are linked to the settlement via
participant_settlement_id. - Settlement-derived payouts are immediately created as draft records.
Postconditions:
- A
participant_settlementrecord exists (created or updated). - All specified PAY applications have
participant_settlement_idpopulated. cash_receipt_payoutrecords withpayment_item_type_cd='S'exist for each settlement item.
2.26 Delete Settlement
Operation: deleteSettlement
Trigger: User deletes a settlement from the Applied worksheet.
Input Parameters:
settlementId: Integer —participant_settlement.participant_settlement_iduserId: String — identifier for the authenticated user
Removes a settlement and its items, voids unlocked payment items, and unlinks PAY applications.
Step 1. Check for Locked Payment Items
- Source:
participant_settlement_itemjoined topayment_itemfor the settlement. - Action: SELECT and evaluate lock status.
- Logic:
- If any linked
payment_item.payment_execution_status_cdis in['PROCESSING', 'SENT', 'PAID', 'ACKNOWLEDGED'], abort: settlement cannot be deleted because a payment has been sent.
- If any linked
Step 2. Void Unlocked Payment Items
- Source:
payment_itemrecords linked to settlement items, excluding locked ones. - Action: UPDATE
payment_item. - Logic:
- Set
payment_item_posting_status_cd='X'(Skipped/Voided). - Set
payment_execution_status_cd='CANCELLED'. - Set
return_reason_cd='SETTLEMENT_DELETE'.
- Set
Step 3. Delete Linked Payouts
- Source:
cash_receipt_payoutrecords linked to settlement items. - Action: DELETE from
cash_receipt_payout. - Logic:
- Remove all payout records that reference any
participant_settlement_item_idbelonging to this settlement.
- Remove all payout records that reference any
Step 4. Unlink Applications
- Source:
cash_receipt_applicationwhereparticipant_settlement_id= input settlement ID. - Action: UPDATE
cash_receipt_application. - Logic:
- Set
participant_settlement_id=nullfor all linked applications.
- Set
Step 5. Delete Settlement Items
- Source:
participant_settlement_itemwhereparticipant_settlement_id= input. - Action: DELETE from
participant_settlement_item. - Logic:
- Remove all settlement item records.
Step 6. Delete Settlement Header
- Source:
participant_settlementwhereparticipant_settlement_id= input. - Action: DELETE from
participant_settlement. - Logic:
- Remove the settlement header record.
Side-effects:
- Unlocked
payment_itemrecords are voided (payment_item_posting_status_cd='X'). - All linked
cash_receipt_payoutrecords are deleted. - PAY applications have
participant_settlement_idset tonull.
Postconditions:
- No
participant_settlement,participant_settlement_item, or linkedcash_receipt_payoutrecords remain for the given settlement. - PAY applications that were linked to the settlement are unlinked and available to be added to a new settlement.
3. Business Rules & Logic
3.1 Worksheet Status Lifecycle
Business rule: A worksheet follows a strict forward-only lifecycle through five statuses. Corrections to Approved worksheets are handled through the return mechanism, not backward transitions.
Data-level enforcement:
Draft (D) → Applied (P) → Settled (T) → Approved (A) → Returned (R)| Transition | Direction | Creates Reversal? | Permission |
|---|---|---|---|
D → P | Forward | No | canApplyWorksheet |
P → T | Forward | No | canSettleWorksheet |
T → A | Forward | No | canApproveWorksheet |
A → R | Forward (return) | Yes (three documents) | canApproveWorksheet |
P → D | Backward (reject) | No | canSettleWorksheet |
T → P | Backward (reject) | No | canApproveWorksheet |
- Read:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd - Guard: Each transition validates the current status before allowing the update.
- Write: Update
cash_receipt_worksheet.cash_receipt_worksheet_status_cdto the new status code.
IMPORTANT
No worksheet ever moves backward from Approved. A return from Approved always produces three documents (original sealed, reversal, replacement draft). Backward transitions (reject) are only available for P → D and T → P.
3.2 Locked Payment Rule
Business rule: A payment item is locked once money has begun leaving the building. Locked payment items cannot be voided or reversed; their associated applications are copied as read-only to the replacement draft.
Data-level enforcement:
- Read:
payment_item.payment_execution_status_cd - Guard: If
payment_execution_status_cd∈['PROCESSING', 'SENT', 'PAID', 'ACKNOWLEDGED'], the payment is locked. Ifpayment_item_posting_status_cd='X'(voided), exclude from lock checks entirely. - Write: Locked items:
do_not_send_ind=true(status preserved). Unlocked items:payment_execution_status_cd='WAITING',do_not_send_ind=true.
3.3 Bilateral Lock Rule
Business rule: A locked PAY application also locks its paired REV application for the same billing item. REV and PAY are a matched pair — you cannot reverse one without the other.
Data-level enforcement:
- Read: Group
cash_receipt_applicationbybilling_item_id, separate bybilling_item_detail_type_cd(REV vs. PAY). Sort each group bycash_receipt_application_idascending. - Guard: Pair REV[0] with PAY[0], REV[1] with PAY[1], etc. If PAY at position N is locked, REV at position N is also locked.
- Write: Add REV application ID to
lockedApplicationIdsset. When copying to replacement draft, both locked REV and PAY are copied as read-only.
3.4 Partial Application Rule
Business rule: Worksheets can be applied without using the full split balance. This allows unused funds to be transferred to other splits after approval.
Data-level enforcement:
- Read:
cash_receipt_worksheet.cash_receipt_worksheet_status_cd - Guard: No balance-equals-zero check is performed at any status transition. Only the total-exceeds-receipt check (
Total Applied <= net_receipt_amt + 0.005) is enforced. - Write: N/A — this rule removes a constraint rather than adding one.
3.5 Total Applied Calculation
Business rule: The worksheet total applied is the sum of receivable applications, client ledger applications, non-settlement payouts, and deductions. Settlement payouts are excluded because they represent the division of PAY among parties, not additional cash allocation.
Data-level enforcement:
- Read: Four sources:
cash_receipt_application.cash_receipt_amt_applied,cash_receipt_client_ledger.cash_receipt_amt_applied,cash_receipt_payout.payment_item_amt(wherepayment_item_type_cd!='S'),cash_receipt_application_deduction.deduction_amt_applied.
Total Applied = SUM(cash_receipt_application.cash_receipt_amt_applied)
+ SUM(cash_receipt_client_ledger.cash_receipt_amt_applied)
+ SUM(cash_receipt_payout.payment_item_amt WHERE payment_item_type_cd != 'S')
+ SUM(cash_receipt_application_deduction.deduction_amt_applied)- Guard:
Total Applied <= cash_receipt.net_receipt_amt + 0.005
3.6 Over-Application to Individual Receivables
Business rule: Over-application to an individual billing item detail is permitted. The system only enforces that the total worksheet applied amount does not exceed the receipt amount.
Data-level enforcement:
- Read:
cash_receipt_application.cash_receipt_amt_appliedperbilling_item_detail_id - Guard: No per-receivable limit is enforced. Only the worksheet-level total is checked.
- Write: N/A — this rule removes a constraint rather than adding one.
3.7 Currency Match Rule
Business rule: A receivable application can only be added if the billing item's currency matches the cash receipt's currency. Mismatched currency pairs are rejected.
Data-level enforcement:
- Read:
billing_item.billing_item_currency_cdandcash_receipt.currency_cd - Guard: If
billing_item_currency_cd!=cash_receipt.currency_cd, reject the application with a currency mismatch error. - Write: N/A — this is a guard only.
3.8 Single Active Worksheet Per Split
Business rule: At any point in time, only one worksheet per cash receipt split may be active (current). The return process enforces this by deactivating the original and activating the replacement.
Data-level enforcement:
- Read:
cash_receipt_worksheet.current_item_indwherecash_receipt_split_id= target split - Guard: On worksheet creation, if a row with
current_item_ind=truealready exists for the split, abort. - Write: On return: set original
current_item_ind=false; set replacementcurrent_item_ind=true.
3.9 GL Posting Rules
Business rule: REV applications and client ledger entries are staged for GL posting at Apply time. PAY applications are not posted to GL until the bank confirms payment completion. You cannot reverse a GL entry that was never posted.
Data-level enforcement:
| Record Type | GL Staged at Apply? | GL Staged at Approval? | GL Staged on Return? |
|---|---|---|---|
| REV application | Yes (posting_status_cd = 'U') | N/A | Yes (reversal worksheet posting_status_cd = 'U') |
| Client ledger | Yes | N/A | Yes (reversal) |
| PAY application | No | No (waits for bank confirmation) | Depends on payment status |
| Payment item | N/A | Only after bank confirms (Stage 2) | Only if original was posted |
- Read:
cash_receipt_worksheet.posting_status_cd - Guard: The GL posting job only picks up worksheets where
posting_status_cd='U'. - Write: Set
posting_status_cd='U'at Apply. Reversal worksheets always getposting_status_cd='U'. Setposting_status_cd='P'after posting. Setposting_status_cd='X'to skip.
3.10 Write-Off Worksheet Restriction
Business rule: Worksheets created from write-off receipts cannot be returned or reopened through the normal return mechanism. The packet recovery process must be used instead.
Data-level enforcement:
- Read:
cash_receipt.receipt_type_cdvia the worksheet's split chain - Guard: If
receipt_type_cd='WRITE_OFF', reject the return with: "Write-off worksheets cannot be reopened. Use the packet recovery process instead." - Write: N/A — this is a guard only.
3.11 Settlement Total Validation
Business rule: The sum of settlement item amounts must equal the sum of PAY applied amounts for the linked applications. Settlements cannot be saved if the totals are mismatched.
Data-level enforcement:
- Read:
participant_settlement_item.participant_settlement_commission_amt(sum);cash_receipt_application.cash_receipt_amt_appliedwherebilling_item_detail_type_cd='PAY'(sum) - Guard: If
|settlementTotal - payApplied| > 0.01, abort. - Write: N/A — this is a guard only.
3.12 Deduction Proration Rule
Business rule: When a billing item detail has multiple deduction types and the user enters a lump-sum deduction, the amount is prorated across types proportionally based on each type's remaining balance.
Data-level enforcement:
- Read:
billing_item_deduction.billing_item_deduction_type_cdand balance per type for thebilling_item_detail_id - Guard: N/A — this is a calculation, not a restriction.
- Write: For each deduction type:
proportion = typeBalance / totalRemainingBalance;proratedAmount = deductionAmount * proportion. Insert onecash_receipt_application_deductionrow per type.
For each deduction type:
typeBalance = billedAmount - previouslyAppliedAmount
proportion = typeBalance / totalRemainingBalance
prorated = deductionAmount * proportion4. Field Mapping & Transformation
4.1 Original Worksheet → Reversal Worksheet
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
cash_receipt_worksheet.cash_receipt_split_id | cash_receipt_worksheet.cash_receipt_split_id | Copied as-is |
| — | cash_receipt_worksheet.cash_receipt_worksheet_status_cd | Defaulted to 'R' |
| — | cash_receipt_worksheet.current_item_ind | Defaulted to false |
| — | cash_receipt_worksheet.worksheet_type_cd | Defaulted to 'REVERSAL' |
cash_receipt_worksheet.cash_receipt_worksheet_id | cash_receipt_worksheet.previous_worksheet_id | Links back to original |
| — | cash_receipt_worksheet.approved_dt | System-generated (now) |
| — | cash_receipt_worksheet.approved_by | Current userId |
| — | cash_receipt_worksheet.posting_status_cd | Defaulted to 'U' (ready for GL pickup) |
Input reopenReason | cash_receipt_worksheet.return_reason | 'Reversal of worksheet #<id>: <reason>' |
4.2 Original Worksheet → Replacement Draft
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
cash_receipt_worksheet.cash_receipt_split_id | cash_receipt_worksheet.cash_receipt_split_id | Copied as-is |
cash_receipt_worksheet.worksheet_sequence | cash_receipt_worksheet.worksheet_sequence | Copied as-is |
| — | cash_receipt_worksheet.cash_receipt_worksheet_status_cd | Defaulted to 'D' (Draft) |
| — | cash_receipt_worksheet.current_item_ind | Defaulted to true |
| — | cash_receipt_worksheet.worksheet_type_cd | Defaulted to 'REPLACEMENT' |
cash_receipt_worksheet.cash_receipt_worksheet_id | cash_receipt_worksheet.previous_worksheet_id | Links back to original |
4.3 Original Worksheet → Sealed Original
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| — | cash_receipt_worksheet.cash_receipt_worksheet_status_cd | Set to 'R' (Returned) |
| — | cash_receipt_worksheet.current_item_ind | Set to false |
| — | cash_receipt_worksheet.returned_dt | System-generated (now) |
| — | cash_receipt_worksheet.returned_by | Current userId |
Input reopenReason | cash_receipt_worksheet.return_reason | Copied as-is |
| — | cash_receipt_worksheet.worksheet_type_cd | Set to 'ORIGINAL' |
| Replacement draft ID | cash_receipt_worksheet.replaced_by_worksheet_id | Forward link to replacement |
4.4 Application Records: Original → Reversal
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Reversal worksheet ID | cash_receipt_application.cash_receipt_worksheet_id | New reversal worksheet |
cash_receipt_application.billing_item_detail_id | cash_receipt_application.billing_item_detail_id | Copied as-is |
cash_receipt_application.cash_receipt_amt_applied | cash_receipt_application.cash_receipt_amt_applied | Negated (-1 * value) |
| Reversal settlement ID (via mapping) | cash_receipt_application.participant_settlement_id | Mapped from original settlement |
cash_receipt_application.cash_receipt_application_id | cash_receipt_application.reversal_of_application_id | Links to original |
| — | cash_receipt_application.reversal_reason_cd | Defaulted to 'WORKSHEET_REOPEN' |
4.5 Application Records: Original → Replacement Draft
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Replacement draft ID | cash_receipt_application.cash_receipt_worksheet_id | New replacement worksheet |
cash_receipt_application.billing_item_detail_id | cash_receipt_application.billing_item_detail_id | Copied as-is |
cash_receipt_application.cash_receipt_amt_applied | cash_receipt_application.cash_receipt_amt_applied | Copied as-is (positive, not negated) |
| New settlement ID (via mapping) | cash_receipt_application.participant_settlement_id | Mapped to new settlement |
| — | cash_receipt_application.reversal_of_application_id | null |
| — | cash_receipt_application.reversal_reason_cd | null |
4.6 Application Deductions: Original → Reversal
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Reversal application ID | cash_receipt_application_deduction.cash_receipt_application_id | New reversal application |
cash_receipt_application_deduction.billing_item_deduction_type_cd | cash_receipt_application_deduction.billing_item_deduction_type_cd | Copied as-is |
cash_receipt_application_deduction.deduction_amt_applied | cash_receipt_application_deduction.deduction_amt_applied | Negated (-1 * value) |
4.7 Application Deductions: Original → Replacement Draft
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Replacement application ID | cash_receipt_application_deduction.cash_receipt_application_id | New replacement application |
cash_receipt_application_deduction.billing_item_deduction_type_cd | cash_receipt_application_deduction.billing_item_deduction_type_cd | Copied as-is |
cash_receipt_application_deduction.deduction_amt_applied | cash_receipt_application_deduction.deduction_amt_applied | Copied as-is (positive, not negated) |
4.8 Client Ledger Entries: Original → Reversal
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Reversal worksheet ID | cash_receipt_client_ledger.cash_receipt_worksheet_id | New reversal worksheet |
cash_receipt_client_ledger.client_ledger_id | cash_receipt_client_ledger.client_ledger_id | Copied as-is |
cash_receipt_client_ledger.deal_id | cash_receipt_client_ledger.deal_id | Copied as-is |
cash_receipt_client_ledger.uta_entity_id | cash_receipt_client_ledger.uta_entity_id | Copied as-is |
cash_receipt_client_ledger.department_id | cash_receipt_client_ledger.department_id | Copied as-is |
cash_receipt_client_ledger.client_id | cash_receipt_client_ledger.client_id | Copied as-is |
cash_receipt_client_ledger.cash_receipt_amt_applied | cash_receipt_client_ledger.cash_receipt_amt_applied | Negated (-1 * value) |
cash_receipt_client_ledger.cash_receipt_client_ledger_id | cash_receipt_client_ledger.reversal_of_ledger_id | Links to original |
| — | cash_receipt_client_ledger.reversal_reason_cd | Defaulted to 'WORKSHEET_REOPEN' |
4.9 Client Ledger Entries: Original → Replacement Draft
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Replacement draft ID | cash_receipt_client_ledger.cash_receipt_worksheet_id | New replacement worksheet |
cash_receipt_client_ledger.client_ledger_id | cash_receipt_client_ledger.client_ledger_id | Copied as-is |
cash_receipt_client_ledger.deal_id | cash_receipt_client_ledger.deal_id | Copied as-is |
cash_receipt_client_ledger.uta_entity_id | cash_receipt_client_ledger.uta_entity_id | Copied as-is |
cash_receipt_client_ledger.department_id | cash_receipt_client_ledger.department_id | Copied as-is |
cash_receipt_client_ledger.client_id | cash_receipt_client_ledger.client_id | Copied as-is |
cash_receipt_client_ledger.cash_receipt_amt_applied | cash_receipt_client_ledger.cash_receipt_amt_applied | Copied as-is (positive) |
| — | cash_receipt_client_ledger.reversal_of_ledger_id | null |
| — | cash_receipt_client_ledger.reversal_reason_cd | null |
4.10 Payouts: Original → Reversal
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Reversal worksheet ID | cash_receipt_payout.cash_receipt_worksheet_id | New reversal worksheet |
| — | cash_receipt_payout.payment_item_id | null |
| — | cash_receipt_payout.participant_settlement_item_id | null |
cash_receipt_payout.payout_party_id | cash_receipt_payout.payout_party_id | Copied as-is |
cash_receipt_payout.payment_item_name | cash_receipt_payout.payment_item_name | Prefixed with 'Reversal: ' |
cash_receipt_payout.payment_item_type_cd | cash_receipt_payout.payment_item_type_cd | Copied as-is |
cash_receipt_payout.payment_item_amt | cash_receipt_payout.payment_item_amt | Negated (-1 * value) |
cash_receipt_payout.payment_item_currency_cd | cash_receipt_payout.payment_item_currency_cd | Copied as-is |
cash_receipt_payout.cash_receipt_payout_id | cash_receipt_payout.reversal_of_payout_id | Links to original |
| — | cash_receipt_payout.reversal_reason_cd | Defaulted to 'WORKSHEET_REOPEN' |
4.11 Payouts: Original → Replacement Draft
| Source Table.Field | Target Table.Field | Transform |
|---|---|---|
| Replacement draft ID | cash_receipt_payout.cash_receipt_worksheet_id | New replacement worksheet |
cash_receipt_payout.payment_item_id | cash_receipt_payout.payment_item_id | Preserved (link maintained) |
| Remapped via settlement item mapping | cash_receipt_payout.participant_settlement_item_id | Remapped to new settlement item ID |
| All other fields | All other fields | Copied as-is |
| — | cash_receipt_payout.do_not_send_ind | Defaulted to true (all payouts held) |
4.12 Payment Items: Effects of Return Process
| Payment Lock Status | Reversal Effect | Replacement Effect |
|---|---|---|
| Unlocked | do_not_send_ind = true; payment_execution_status_cd = 'WAITING' | Re-pointed to new settlement item; do_not_send_ind = true; payment_execution_status_cd = 'WAITING' |
| Locked | do_not_send_ind = true (execution status preserved) | Re-pointed to new settlement item; do_not_send_ind = true (execution status preserved) |
NOTE
On worksheet approval, do_not_send_ind is reset to false on unlocked payment items (unless the payout itself has do_not_send_ind = true), allowing the bank job to pick them up.
5. Cross-References
| Document | Relationship |
|---|---|
| Worksheets Data Model | Table definitions, columns, types, and ER diagram for all tables mutated by these procedures. |
| Worksheets Queries | Read queries, search patterns, and balance calculations used to validate and display worksheet state. |
| Settlements Data Model | participant_settlement and participant_settlement_item tables created and managed during the Settle and Approve transitions. |
| Cash Receipts Data Model | cash_receipt_split.cash_receipt_split_id → parent of worksheet creation. cash_receipt.posting_status_cd and locked_by_user_id gated by worksheet lifecycle. |
| Billing Items Data Model | billing_item_detail.billing_item_detail_id — the target of each cash_receipt_application. billing_item.open_item_ind is set to false at approval when fully paid. |
| Settlements Procedures | Payment item lifecycle, bank transmission, and how payment_execution_status_cd drives the locking logic during returns. |
| Tax Withholding Data Model | Tax withholding deductions recorded as cash_receipt_application_deduction entries during application. |
| Write-Offs Data Model | Write-off worksheets (receipt_type_cd = 'WRITE_OFF') cannot be returned; uses separate packet recovery process. |
| Accounting Data Model | GL posting job picks up worksheets where posting_status_cd = 'U' (set at Apply for REV entries and client ledger; set on reversal worksheets). |