6.2 KiB
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:
- Fetch Active Plans: Resolve the active version of each
CompensationPlanfor target collaborators. - Fetch Goals: Resolve the goal amount for target users from the
Goaltable for the matching period. - Fetch Sales Results: Retrieve and sum the total
amountandsalesCountofSalesResultrecords generated by each collaborator in the period. - Determine Achievement:
\text{Achievement \%} = \frac{\text{Sum of Sales Amount}}{\text{Goal Amount}} - Apply Rules:
- Compare the Achievement % against boundaries in the plan's
CalculationRulelist. - For
TIERrules: Payout is calculated as:\text{Commission} = \text{Sum of Sales Amount} \times \text{Rule Rate} - For
BONUSrules: Payout is the fixedpayoutAmountconfigured.
- Compare the Achievement % against boundaries in the plan's
- Enforce Cap Limit: If the sum of calculated payouts exceeds the plan's
maxCap, the payout is capped atmaxCap.
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:
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
Settlementtable viaoriginalSettlementIdto 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:
- Conditional Branching: The n8n webhook endpoint evaluates the request URI path.
- Test/Staging calls: Webhooks routed via
/webhook-test/calculate-settlementsroute tohttp://app-dev:3001(running development stack, connected toTEST_DATABASE_URL) and validate signatures usingN8N_WEBHOOK_SECRET_DEV. - Production calls: Webhooks routed via
/webhook/calculate-settlementsroute tohttp://app-prod:3000and validate signatures usingN8N_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, andsalarywith[REDACTED].
2. API Specifications
2.1. POST /api/settlements/calculate (Process Settlements)
- Role Restriction:
admin|analyst - Request Body:
{ "period": "2026-06", "simulateOnly": false } - Response:
201 Created(Direct commit mode):{ "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, logsapprovedBy, and triggers a callback notification. - Response:
200 OK.
2.3. POST /api/settlements/[id]/reject (Reject Payout)
- Role Restriction:
commercial_leader - Request Body:
{ "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:
- Period Selector: Dropdown to select the target payout month.
- Comparison Matrix: Grid displaying:
- Collaborator | Plan Version | Goal | Confirmed Sales | Achievement % | Proposed Commission | Retroactive Adjustments | Total Payout (Simulated)
- 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:
- Segregated List: Displays pending settlements, restricted to the leader's region.
- Reason Modal: Appears when selecting "Rechazar", requiring a text entry.
- 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:
- Engine Accuracy: Seed sales/goals, run calculation, verify output against expected mathematical tiers.
- 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.
- Leader Isolation: Confirm
lider_ctgis blocked from approving a settlement for a collaborator in Antioquia (EST-MDE). - Rejection Constraint: Ensure a rejection request fails (400) if the reason is omitted.