# **Product Proposal**

### **Background**

Currently, the transfer of earnings is handled as a manual process outside ABACUS. It supports workflows like:

* **Cross-recoupment** \- moving surplus from recouped contracts to unrecouped contracts
* **Paying third parties** \- directing funds to collaborators, partners, or commission recipients
* Transferring balances from one account/contract to another

Different business units use different terminology ("reclass" vs. "overrides"), but all point to the same core action: moving money from one contract to another.

A transfer can be based on different financial metrics such as balance, net revenue, or gross revenue depending on the transfer type. Each transfer type has defined trigger points that determine when and whether a transfer can occur.

In simpler terms:

* Transfer types represent what kind of workflow it is (e.g., balance transfer, override, or reclass)
* Trigger points define when and under what conditions the transfer can be executed (e.g., once a contract is recouped, etc.)

**Why do we need to set up transfers of earnings?**
Across business lines, ToE is needed to:

* Pay collaborators, partners, or third parties
* Move revenue/balances from old → new deals (novations / superseded deals)
* Facilitate cross-recoupment for related contracts

Today this is done via manual spreadsheets \+ adjustments, which creates scale, audit, and consistency issues.

**Current Workflow**

* Teams identify values to move using Looker reports and spreadsheets.
* They upload manual adjustments: negative line on “from” contract, positive line on “to” contract.
* For more complex scenarios (cross-recoupment), allocation logic is handled in spreadsheets and varies client-by-client.

### **Definitions**

1. **Transfer of Earnings:** A set of workflows that move an amount between contracts (and in some cases accounts/schedules) to support business needs like third-party payments, deal migrations/novations, and cross-recoupment. ToE is executed today primarily through manual adjustment uploads (spreadsheet-driven).
   * ToE can be calculated from different “values”:
     * Closing Balance (often the post-tax/payable balance; may implicitly include opening balance \+ net revenue \+ expenses/adjustments depending on entity)
     * Gross revenue
     * Net revenue (less common; sometimes schedule-level)
2. **Reclass:** A to/from transfer (“directional transfer”) where the user defines a source contract (“from”), destination contract (“to”), and amount rule (full or percentage).
   1. Two variants:
      1. Balance Reclass: move a contract’s calculated balance (or % of it) from Contract A → Contract B via debit/credit adjustments.
      2. Revenue Reclass: reduce/remove transaction amounts on one ledger and add them on the other to preserve transaction-level metadata, needed for tax accuracy (notably US/Germany).
3. **Override:** A directional transfer frequently described by Accounting as “paying out” or shifting funds to:
   1. a collaborator/partner/third party (commission shares)
      2. a new/updated deal (novations, superseded contracts)
      3. operationally enable cross-recoupment (manual equivalents today)
   2. Overrides can be recurring monthly/quarterly, and may include edge-cases where the recipient is not an Abacus payee.
4. **Cross-Recoupment:** A group-based transfer model where direction is not configured by users each period. Instead:
   1. Users define a Cross-Recoupment Group of contracts and constraints (cap rates).
   2. Each statement period, the system determines contributors vs receivers dynamically using post-Flowthrough (or post-VAT) projected balances, then allocates amounts based on deterministic rules.
5. **Deterministic allocation rules:**
   1. Pay receivers closest to zero first (maximize recouped contracts/minimize adjustment lines)
   2. Pull from contributors with largest available surplus after cap rate applied (exhaust highest-ranked contributor before next)
   3. Execution occurs after Flowthrough/VAT locks, and will need recalculation if FT/VAT changes
6. **Post-Flowthrough Projected Balance**: balance after Flowthrough is applied for the statement period (or post-VAT where relevant).
7. **Contributor**: post-FT projected balance \> 0
8. **Receiver**: post-FT projected balance \< 0
9. **Neutral**: balance \= 0 (recouped, but nothing to allocate)

### **Problem**

**Core Problems (Shared Across Business Entities)**
Manual spreadsheets drive:

* High time cost each accounting cycle
* Human error risk in calculations, data entry, and formula maintenance
* Inconsistent outcomes across business units

Manual spreadsheet management:

* Transfer intent (why, between whom, what rate/cadence) is often not stored in ABACUS
* Reconstruction of "from/to/%" structure required each cycle

Reporting risk:

* Adjustments are relied upon widely; changes must reconcile and remain auditable
* No consolidated transfer history since transfers appear only as generic adjustments

Hard to scale and validate:

* Especially challenging for recurring monthly/quarterly transfers
* Complex exceptions handled ad-hoc (negative balance scenarios, multi-to-one relationships, conditional execution)

**Transfer Type-Specific Problems**
Directional transfers (Overrides/Reclasses):

* Data capture gaps requiring manual tracking


**Cross-recoupment**:

* Transfer-line mental model breaks down when direction isn't predetermined
* Contributors/receivers may change month-to-month based on balances
* Many-to-many allocations produce ambiguity and non-determinism without clear governance
* Edge cases handled inconsistently client-by-client
* Dependency on post-Flowthrough/post-VAT balances requires recalculation if those values change

### **Goals**

1. Reduce manual effort to eliminate spreadsheet management, reduce checks and manual uploads
2. Create consistent, repeatable Transfer of Earnings outputs across all business lines
3. Ensure deterministic results that support auditing, reversals, recalculations, and reporting
4. Integrate ToE cleanly into the accounting workflow with clear dependencies (Flowthrough/VAT/Adjustments)

### **Calculation Engine Rules**

#### EarningsTransfer Record Fields

| Field | Type | Description |
| :---- | :---- | :---- |
| `from_contract_id` | medumint unsigned | ID of Contract to debit from |
| `to_contract_id` | medumint unsigned | ID of Contract to credit the transfer to |
| `rate_type` | enum('percent','flat_rate') | Determines how `transfer_amount` is interpreted. |
| `transfer_amount` | decimal(20,12) | The rate or amount of the transfer. For `percent`: must be between 0-1 inclusive. For `flat_rate`: any positive value (may exceed 100). |
| `input` | enum('net_revenue','gross_revenue','closing_balance') | Which balance field from the from-contract is used as the basis for calculation. |
| `negative` | tinyint(1) | For `percent`: controls whether a negative closing balance blocks the transfer (the selected-balance gate always applies regardless). For `flat_rate`: controls whether a negative balance blocks the transfer entirely. See rate-type sections below. |
| `active` | tinyint(1) | Only records where `active` is truthy are loaded and processed. Inactive records are skipped entirely. |

#### Rate Type Calculation

**percent**

`transfer_amount` is a decimal between 0 and 1. It's multiplied with the eligible balance of the from-contract to get the percentage of the balance to determine the calculated transfer amount:

- eligible_balance = the balance field of the from-contract named by the earnings_transfer's input (closing_balance, net_revenue, gross_revenue)
- Two gates must pass before the transfer is calculated:
  1. **Closing-balance gate** (`negative=False` only): if the from-contract's closing balance is negative, the transfer is blocked — regardless of which input source is selected. When `negative=True` this gate is skipped.
  2. **Selected-balance gate** (always): if the eligible balance is non-positive (≤ 0), the transfer is blocked. This applies regardless of the `negative` flag.
- transfer = eligible_balance × transfer_amount

**Percent allocation validation:** When multiple percent transfers share the same FROM contract, their `transfer_amount` values are summed. If the total exceeds 1.0 (100%), all percent records in that group are zeroed out and flagged with an error. Flat-rate records from the same FROM contract are unaffected.

**flat_rate**

`transfer_amount` is a fixed dollar amount transferred directly. When `negative=True` always allow the transfer regardless of balance in the from-contract. When `negative=False` only allow the transfer if the from-contract has a postive balance.

| `negative` | Condition | Result |
| :---- | :---- | :---- |
| `false` (default) | balance < 0 (already negative) | Transfer blocked |
| `false` (default) | balance ≥ 0 but transfer_amount > balance (would go negative) | Transfer allowed |
| `false` (default) | balance ≥ 0 and transfer_amount ≤ balance | Transfer allowed |
| `true` | any balance | Transfer always proceeds — full flat amount regardless of current balance or deficit |

The `negative=true` flag is intended for legal or contractual obligations where the from-contract must pay a fixed amount even if its balance is already in deficit.

#### Record Filtering

Before calculation, the parser filters the raw API response to only include records where `active` is truthy. Records with `active=0` or `active=null` are discarded and do not appear in output.

### **Phase Strategy**

#### **Phase 1: Proof of Concept (PoC) of Linear Transfer Types (Orchard / AWAL)**

*What this includes*: Linear transfer types using closing balance.

**Types Included:**

1. **Transfer of Income** \- Splitting ownership revenue
2. **Override Royalty** \- Paying third parties
3. **Reclass Between Labels** \- Label consolidation

**What makes these "simple":**

* Direction NEVER flips
* User controls if a transfer is active
* User chooses the input field (eligible balance)
* Straightforward calculation: Eligible Balance × Percentage (or + Flat Rate)
* No complex trigger logic (just active and negative rules)

**Why we need this:**

* Some contracts are structured so partners only share NEW earnings
* Prevents double-transferring the same money month over month
* Common in cross-recoupment scenarios (Phase 2\) but also exists in simple transfers

**What’s EXCLUDED from PoC:**

* Pre-flowthrough transfers (dependency on flowthrough)
* Schedule/product level
* Any transfer that can flip direction (cross-recoupment transfers)

**Volume Coverage:**

* **Transfer of Income (closing balance only):** \~20-30 transfers/month
* **Override Royalty (closing balance only):** \~20-30 transfers/month
* **Reclass:** \~10-15 transfers/month
* **TOTAL PoC:** \~50-75 transfers/month (\~15% of total volume)

**PoC Success Criteria:**

* Lambda generates adjustments file correctly
* Users can review line-by-line transfers to adjustments
* Upload to ABACUS via adjustments workflow
* Calculation matches manual spreadsheet

| Edge Cases | Priority  | Effort | Impact | Notes |
| :---- | :---- | :---- | :---- | :---- |
| Negative balance transfers (Putting contracts in debt intentionally as legal requirements) |  |  |  |  |
| Schedule/product level transfers |  |  |  |  |

#### **Phase 2: Transfer Data Capture UI**

*What this includes*: Build the UI for contract admins to set up transfers

**Why this is separate from PoC:**

* PoC proves the calculation logic works
* Once proven, we need a way for users to actually configure transfers
* Contract admin needs to be able to add/edit/remove transfers

**What we're building:**

* Transfer Setup Screen
* Transfer Section in the Contract Page
  * User is able to view transfers in a list view
*

#### **Phase 3: Full Automation**

*What this includes*: Remove manual Looker upload step

**Current state (Phases 1-3):**

1. User inputs transfer data
2. System generates Looker report
3. User downloads adjustment file
4. User reviews
5. User uploads to ABACUS manually

**Future state (Phase 4):**

1. User inputs transfer data
2. System generates adjustments
3. System applies automatically (no manual upload)
4. User reviews via dashboard/QC workflow
5. User can approve/reject/adjust

**Prerequisites for automation:**

* All transfer types working correctly
* QC/validation workflows built
* Error handling robust
* Stakeholder trust earned

## Architecture

app.py exposes a processor that handles being invoked in AWS Lambda.

This Lambda will load EarningsTransfer records from an API call to ows-royalties. The parser filters out records whose `active` property is falsy and skips cross-recoupment records (not yet supported in Phase 1). If any remaining records fail validation (unknown transfer_type, rate_type, out-of-range transfer_amount, etc.), all errors are collected and raised together in a single InputValidationError.

The parser will then enrich valid records with contract metadata from Snowflake (account name and ID, contract name, closing_balance, net_revenue, and gross_revenue).

The contract object pairs referenced by these EarningsTransfers are then processed by the calculator to determine the calculated transfer amount that will be debited from the from-contract, and credited to the to-contract. These debits/credits and client facing comments will be output to an xlsx file and uploaded to S3.
