docs: add Phase 5 Implementation and Settlement Design Document
This commit is contained in:
parent
acd139cf0d
commit
24d54f8bed
1 changed files with 123 additions and 0 deletions
123
docs/PHASE_5_IMPLEMENTATION.md
Normal file
123
docs/PHASE_5_IMPLEMENTATION.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# 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.
|
||||
Loading…
Reference in a new issue