# Phase 5 Implementation & Settlement Design Document

**Variable Remuneration, Compensation, and Commissions System - Hoteles Estelar**

---

This document outlines the detailed architectural decisions, logical workflows, API specifications, UI mockups, and E2E verification plans for **Phase 5: Settlement Engine & Approvals**.

## 1. Architectural Strategy & Logic Flows

### 1.1. Core Settlement Calculation Engine (US-COM-006)
The system calculates commissions automatically based on defined rules. For a target period (`YYYY-MM`), the calculation steps are:
1. **Fetch Active Plans**: Resolve the active version of each `CompensationPlan` for target collaborators.
2. **Fetch Goals**: Resolve the goal amount for target users from the `Goal` table for the matching period.
3. **Fetch Sales Results**: Retrieve and sum the total `amount` and `salesCount` of `SalesResult` records generated by each collaborator in the period.
4. **Determine Achievement**:
   $$\text{Achievement \%} = \frac{\text{Sum of Sales Amount}}{\text{Goal Amount}}$$
5. **Apply Rules**:
   - Compare the Achievement % against boundaries in the plan's `CalculationRule` list.
   - For `TIER` rules: Payout is calculated as:
     $$\text{Commission} = \text{Sum of Sales Amount} \times \text{Rule Rate}$$
   - For `BONUS` rules: Payout is the fixed `payoutAmount` configured.
6. **Enforce Cap Limit**: If the sum of calculated payouts exceeds the plan's `maxCap`, the payout is capped at `maxCap`.

### 1.2. Retroactive Adjustments & PMS Clawbacks
Hotel booking modifications, refunds, or cancellations frequently occur after past commissions have been paid. The engine processes retroactive adjustments as follows:

```mermaid
graph TD
    A[Start Calculation for Month M] --> B[Retrieve Month M-1 and M-2 Sales Results]
    B --> C[Fetch Original Settlements for Month M-1 and M-2]
    C --> D{Any sales discrepancy found?}
    D -->|No| E[Continue with normal month M calculation]
    D -->|Yes| F[Recalculate past commission with live sales data]
    F --> G[Calculate Delta: Corrected Payout - Previously Paid Payout]
    G --> H[Create Pending Adjustment Settlement record in DB linked to Original ID]
    H --> I[Add Delta to Month M Total Payout: Total = Commission + Bonus + Sum(Deltas)]
```

- If $\Delta \text{Payout} < 0$, it is treated as a **Clawback** (reduction).
- If $\Delta \text{Payout} > 0$, it is treated as an **Adjustment Credit** (addition).
- A self-referencing relationship is stored in the `Settlement` table via `originalSettlementId` to preserve the historical audit trail.

### 1.3. Webhook Branching & Environment Isolation
To prevent test calculation suites from polluting production records, the n8n workflows implement a strict routing architecture:
1. **Conditional Branching**: The n8n webhook endpoint evaluates the request URI path.
2. **Test/Staging calls**: Webhooks routed via `/webhook-test/calculate-settlements` route to `http://app-dev:3001` (running development stack, connected to `TEST_DATABASE_URL`) and validate signatures using `N8N_WEBHOOK_SECRET_DEV`.
3. **Production calls**: Webhooks routed via `/webhook/calculate-settlements` route to `http://app-prod:3000` and validate signatures using `N8N_WEBHOOK_SECRET`.

### 1.4. SOC 2 Log Redaction
All Next.js API routes run console outputs through a filtering proxy that redacts base salaries, passwords, and custom compensation parameters before writing to standard streams:
- Intercepts logs on settlement mutations.
- Replaces values for keys: `password`, `passwordHash`, `baseSalary`, `bankAccount`, and `salary` with `[REDACTED]`.

---

## 2. API Specifications

### 2.1. `POST /api/settlements/calculate` (Process Settlements)
- **Role Restriction**: `admin` | `analyst`
- **Request Body**:
  ```json
  {
    "period": "2026-06",
    "simulateOnly": false
  }
  ```
- **Response**:
  - `201 Created` (Direct commit mode):
    ```json
    {
      "success": true,
      "code": "SETTLEMENTS_CALCULATED",
      "metadata": {
        "count": 14,
        "totalCommission": 85000.00,
        "totalAdjustment": -3500.00
      }
    }
    ```

### 2.2. `POST /api/settlements/[id]/approve` (Approve Payout)
- **Role Restriction**: `commercial_leader`
- **Logic**: Enforces RLS. A leader can only approve settlements belonging to collaborators of hotels in their region. Sets status to `APPROVED`, logs `approvedBy`, and triggers a callback notification.
- **Response**: `200 OK`.

### 2.3. `POST /api/settlements/[id]/reject` (Reject Payout)
- **Role Restriction**: `commercial_leader`
- **Request Body**:
  ```json
  {
    "reason": "Venta reportada del colaborador no coincide con el cierre del hotel"
  }
  ```
- **Logic**: Sets status to `REJECTED`, stores the mandatory reason in the database, and sets the state to allow correction and recalculation.
- **Response**: `200 OK`.

---

## 3. UI Design Specifications

### 3.1. Simulation Dashboard (`/sales/simulation`)
Provides analysts with a dry-run environment:
1. **Period Selector**: Dropdown to select the target payout month.
2. **Comparison Matrix**: Grid displaying:
   - Collaborator | Plan Version | Goal | Confirmed Sales | Achievement % | Proposed Commission | Retroactive Adjustments | Total Payout (Simulated)
3. **Dry-Run Mode Toggle**: Execute calculations without writing data or triggering final callbacks.

### 3.2. Approvals Panel (`/settlements/approvals`)
Allows leaders to sign off on payouts:
1. **Segregated List**: Displays pending settlements, restricted to the leader's region.
2. **Reason Modal**: Appears when selecting "Rechazar", requiring a text entry.
3. **Status Badges**: Shows simulated vs finalized payout progress.

---

## 4. Headless Puppeteer Verification Plan

We will create a verification script `prisma/test-phase5-ui.js` that tests:
1. **Engine Accuracy**: Seed sales/goals, run calculation, verify output against expected mathematical tiers.
2. **Clawback Delta Logic**: Update a past month's sale amount, run the calculation again, and verify that the current month's proposed settlement contains a negative adjustment equal to the commission delta.
3. **Leader Isolation**: Confirm `lider_ctg` is blocked from approving a settlement for a collaborator in Antioquia (`EST-MDE`).
4. **Rejection Constraint**: Ensure a rejection request fails (400) if the reason is omitted.
