--- id: "ET-SAAS-020" title: "Especificacion Tecnica Commissions" type: "TechnicalSpec" status: "Implemented" priority: "P1" module: "commissions" version: "1.0.0" created_date: "2026-02-03" updated_date: "2026-02-03" story_points: 8 --- # ET-SAAS-020: Especificacion Tecnica - Sistema de Comisiones ## Metadata - **Codigo:** ET-SAAS-020 - **Modulo:** Commissions - **Version:** 1.0.0 - **Estado:** Implementado - **Fecha:** 2026-02-03 - **Basado en:** SAAS-020 --- ## 1. Resumen Ejecutivo ### 1.1 Estado Actual Sistema de comisiones completamente implementado. | Capacidad | Estado | Notas | |-----------|--------|-------| | Schemes | SI | Esquemas configurables | | Assignments | SI | Asignacion usuario-esquema | | Entries | SI | Entradas de comision | | Periods | SI | Periodos de pago | | Dashboard | SI | Metricas y reportes | | RLS | SI | Row Level Security | ### 1.2 Funcionalidades v1.0 Sistema completo con: - **4 Entidades**: Schemes, Assignments, Entries, Periods - **3 Tipos de esquema**: percentage, fixed, tiered - **Workflow completo**: pending → approved → paid - **Periodos de pago**: Ciclos configurables - **Dashboard**: Metricas por usuario, periodo, esquema --- ## 2. Modelo de Datos ### 2.1 Schema: commissions #### Tabla: schemes | Campo | Tipo | Descripcion | |-------|------|-------------| | id | UUID | PK | | tenant_id | UUID | FK tenants | | name | VARCHAR(100) | Nombre del esquema | | description | TEXT | Descripcion | | type | ENUM | percentage, fixed, tiered | | rate | DECIMAL(5,2) | Tasa porcentual (0-100) | | fixed_amount | DECIMAL(15,2) | Monto fijo | | tiers | JSONB | [{from, to, rate}] | | applies_to | ENUM | all, products, categories | | product_ids | UUID[] | IDs de productos | | category_ids | UUID[] | IDs de categorias | | min_amount | DECIMAL(15,2) | Monto minimo para calificar | | max_amount | DECIMAL(15,2) | Cap maximo por comision | | is_active | BOOLEAN | Estado | **Ejemplo tiers:** ```json [ {"from": 0, "to": 1000, "rate": 5}, {"from": 1001, "to": 5000, "rate": 7}, {"from": 5001, "to": null, "rate": 10} ] ``` #### Tabla: assignments | Campo | Tipo | Descripcion | |-------|------|-------------| | id | UUID | PK | | tenant_id | UUID | FK tenants | | user_id | UUID | FK users | | scheme_id | UUID | FK schemes | | starts_at | TIMESTAMPTZ | Inicio de vigencia | | ends_at | TIMESTAMPTZ | Fin de vigencia (null = sin fin) | | custom_rate | DECIMAL(5,2) | Override de tasa para este usuario | | is_active | BOOLEAN | Estado | #### Tabla: entries | Campo | Tipo | Descripcion | |-------|------|-------------| | id | UUID | PK | | tenant_id | UUID | FK tenants | | user_id | UUID | FK users (quien gana) | | scheme_id | UUID | FK schemes | | assignment_id | UUID | FK assignments | | reference_type | VARCHAR(50) | sale, opportunity, order | | reference_id | UUID | ID del registro origen | | base_amount | DECIMAL(15,2) | Monto base de la venta | | rate_applied | DECIMAL(5,2) | Tasa aplicada | | commission_amount | DECIMAL(15,2) | Comision calculada | | currency | VARCHAR(3) | Moneda | | status | ENUM | pending, approved, rejected, paid, cancelled | | period_id | UUID | FK periods | | paid_at | TIMESTAMPTZ | Fecha de pago | | payment_reference | VARCHAR(255) | Referencia externa | | notes | TEXT | Notas | | metadata | JSONB | Datos adicionales | | approved_by | UUID | FK users | | approved_at | TIMESTAMPTZ | Fecha aprobacion | #### Tabla: periods | Campo | Tipo | Descripcion | |-------|------|-------------| | id | UUID | PK | | tenant_id | UUID | FK tenants | | name | VARCHAR(100) | "January 2026" | | starts_at | TIMESTAMPTZ | Inicio del periodo | | ends_at | TIMESTAMPTZ | Fin del periodo | | total_entries | INT | Total de entradas | | total_amount | DECIMAL(15,2) | Monto total | | currency | VARCHAR(3) | Moneda | | status | ENUM | open, closed, processing, paid | | closed_at | TIMESTAMPTZ | Fecha cierre | | closed_by | UUID | FK users | | paid_at | TIMESTAMPTZ | Fecha pago | | paid_by | UUID | FK users | | payment_reference | VARCHAR(255) | Referencia | | payment_notes | TEXT | Notas de pago | ### 2.2 Enums ```sql commissions.scheme_type: percentage, fixed, tiered commissions.applies_to: all, products, categories commissions.entry_status: pending, approved, rejected, paid, cancelled commissions.period_status: open, closed, processing, paid ``` --- ## 3. Arquitectura Backend ### 3.1 Estructura de Archivos ``` backend/src/modules/commissions/ ├── commissions.module.ts ├── controllers/ │ ├── schemes.controller.ts │ ├── assignments.controller.ts │ ├── entries.controller.ts │ ├── periods.controller.ts │ └── dashboard.controller.ts ├── services/ │ ├── schemes.service.ts │ ├── assignments.service.ts │ ├── entries.service.ts │ ├── periods.service.ts │ ├── calculation.service.ts │ └── dashboard.service.ts ├── entities/ │ ├── scheme.entity.ts │ ├── assignment.entity.ts │ ├── entry.entity.ts │ └── period.entity.ts └── dto/ ``` ### 3.2 Endpoints API #### Schemes | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | /commissions/schemes | Listar esquemas | | GET | /commissions/schemes/active | Solo activos | | GET | /commissions/schemes/:id | Obtener | | POST | /commissions/schemes | Crear | | PUT | /commissions/schemes/:id | Actualizar | | DELETE | /commissions/schemes/:id | Eliminar | | POST | /commissions/schemes/:id/duplicate | Duplicar | | POST | /commissions/schemes/:id/toggle | Activar/desactivar | #### Assignments | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | /commissions/assignments | Listar | | GET | /commissions/assignments/user/:userId | Por usuario | | GET | /commissions/assignments/user/:userId/active | Esquema activo | | GET | /commissions/assignments/scheme/:schemeId | Por esquema | | POST | /commissions/assignments | Asignar | | PUT | /commissions/assignments/:id | Actualizar | | DELETE | /commissions/assignments/:id | Remover | | POST | /commissions/assignments/:id/deactivate | Desactivar | #### Entries | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | /commissions/entries | Listar | | GET | /commissions/entries/pending | Pendientes | | GET | /commissions/entries/:id | Obtener | | GET | /commissions/entries/user/:userId | Por usuario | | GET | /commissions/entries/period/:periodId | Por periodo | | POST | /commissions/entries/calculate | Calcular comision | | POST | /commissions/entries/simulate | Simular (sin guardar) | | PATCH | /commissions/entries/:id/status | Cambiar status | | POST | /commissions/entries/bulk-approve | Aprobar multiples | | POST | /commissions/entries/bulk-reject | Rechazar multiples | #### Periods | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | /commissions/periods | Listar | | GET | /commissions/periods/open | Periodo abierto | | GET | /commissions/periods/:id | Obtener | | GET | /commissions/periods/:id/summary | Resumen | | POST | /commissions/periods | Crear | | POST | /commissions/periods/:id/close | Cerrar | | POST | /commissions/periods/:id/reopen | Reabrir | | POST | /commissions/periods/:id/mark-paid | Marcar pagado | #### Dashboard | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | /commissions/dashboard | Resumen general | | GET | /commissions/dashboard/by-user | Por usuario | | GET | /commissions/dashboard/by-period | Por periodo | | GET | /commissions/dashboard/top-earners | Top ganadores | | GET | /commissions/dashboard/me | Mis ganancias | | GET | /commissions/dashboard/user/:userId | Ganancias de usuario | | GET | /commissions/dashboard/scheme/:schemeId | Performance de esquema | --- ## 4. Logica de Calculo ### 4.1 Algoritmo de Calculo ```typescript async calculateCommission(dto: CalculateCommissionDto): Promise { // 1. Obtener asignacion activa del usuario const assignment = await this.getActiveAssignment(dto.userId); // 2. Obtener esquema const scheme = await this.getScheme(assignment.schemeId); // 3. Verificar monto minimo if (dto.amount < scheme.minAmount) { throw new Error('Amount below minimum threshold'); } // 4. Calcular tasa segun tipo let rate: number; switch (scheme.type) { case 'percentage': rate = assignment.customRate ?? scheme.rate; break; case 'fixed': return this.createEntry({ ...dto, rateApplied: 0, commissionAmount: scheme.fixedAmount }); case 'tiered': rate = this.getTieredRate(scheme.tiers, dto.amount); break; } // 5. Calcular comision let commissionAmount = dto.amount * (rate / 100); // 6. Aplicar cap si existe if (scheme.maxAmount && commissionAmount > scheme.maxAmount) { commissionAmount = scheme.maxAmount; } // 7. Crear entrada return this.createEntry({ ...dto, schemeId: scheme.id, assignmentId: assignment.id, rateApplied: rate, commissionAmount }); } ``` ### 4.2 Ejemplo Tiered ``` Tiers: [{from:0, to:1000, rate:5}, {from:1001, to:5000, rate:7}, {from:5001, to:null, rate:10}] Venta: $3,500 Calculo: - Primeros $1,000: $1,000 × 5% = $50 - Siguientes $2,500: $2,500 × 7% = $175 - Total comision: $225 ``` --- ## 5. Frontend ### 5.1 Paginas | Ruta | Componente | Estado | |------|------------|--------| | /dashboard/commissions | CommissionsDashboard | Pendiente | | /dashboard/commissions/schemes | SchemesPage | Pendiente | | /dashboard/commissions/entries | EntriesPage | Pendiente | | /dashboard/commissions/periods | PeriodsPage | Pendiente | | /dashboard/commissions/my-earnings | MyEarningsPage | Pendiente | ### 5.2 Hooks ```typescript // frontend/src/hooks/useCommissions.ts useSchemes, useScheme, useCreateScheme, useUpdateScheme, useDeleteScheme useAssignments, useUserAssignments, useCreateAssignment useEntries, usePendingEntries, useCalculateCommission, useUpdateEntryStatus usePeriods, useOpenPeriod, useClosePeriod, useMarkPeriodPaid useCommissionsDashboard, useMyEarnings, useTopEarners ``` --- ## 6. Seguridad ### 6.1 RLS ```sql CREATE POLICY schemes_tenant_isolation ON commissions.schemes USING (tenant_id = current_setting('app.tenant_id')::uuid); CREATE POLICY entries_tenant_isolation ON commissions.entries USING (tenant_id = current_setting('app.tenant_id')::uuid); ``` ### 6.2 Permisos RBAC | Permiso | Descripcion | |---------|-------------| | commissions:read | Ver comisiones | | commissions:write | Crear/editar esquemas | | commissions:approve | Aprobar comisiones | | commissions:pay | Marcar como pagadas | | commissions:manage | Administrar todo | --- ## 7. Integraciones | Modulo | Integracion | |--------|-------------| | sales | Trigger en OpportunityWon | | goals | Tracking de metas de comision | | mlm | Comisiones MLM | | notifications | Alertas de aprobacion/pago | | audit | Log de cambios | --- ## 8. Referencias - DDL: `database/ddl/schemas/commissions/` - Backend: `backend/src/modules/commissions/` - Frontend: `frontend/src/services/commissions/` - Hooks: `frontend/src/hooks/useCommissions.ts`