feat: consolidations, aduanero portal, payments admin, bug fixes, tests

## Bugs corregidos
- bodega/page.tsx: estados correctos §08 (RECIBIDO_BODEGA, EN_VERIFICACION, EN_TRANSITO_ECUADOR)
- admin/page.tsx: carga paquetes reales, alertas de incidencias/B2B/cobros pendientes, barras de estado

## Nuevos portales y páginas
- /aduanero/ — portal propio para AGENTE_ADUANERO (layout + dashboard §11 + declaraciones DSI)
- /aduanero/declaraciones — cola de declaraciones con formulario DSI y detección DAI automática
- /admin/pagos — gestión de cobros: KPIs, filtros por estado, tabla con breakdown
- /portal/consolidacion — cliente crea/gestiona consolidaciones §21
- /bodega/consolidacion — operador cierra y despacha consolidaciones (→ EN_TRANSITO_ECUADOR)

## API nueva (ConsolidationsModule)
- GET/POST /consolidations
- GET /consolidations/:id
- POST /consolidations/:id/packages
- DELETE /consolidations/:id/packages/:packageId
- POST /consolidations/:id/close
- POST /consolidations/:id/dispatch (→ actualiza paquetes a EN_TRANSITO_ECUADOR)

## Prisma schema v0.5
- ConsolidationStatus enum (ABIERTA, CERRADA, DESPACHADA, ENTREGADA, CANCELADA)
- Consolidation model con totales calculados (totalWeightLb, totalValue)
- ConsolidationPackage (tabla intermedia, un paquete = una consolidación)
- db push aplicado a remote DB (46.202.93.92)

## Navegación
- Login: AGENTE_ADUANERO → /aduanero (ya no /bodega)
- Bodega nav: añadido Consolidaciones
- Portal nav: añadido Consolidar
- Admin nav: añadido Cobros

## Tests (104 total, 8 suites)
- payments.service.spec.ts: 16 tests (createIntent, confirm, list, findByPackageForUser)
- notifications.service.spec.ts: 12 tests (getTemplates, updateTemplate, seedDefaultTemplates, notifyStatusChange, findByUser)

## Legal §21
- Registro: aviso LOPDP Ecuador + normativa NJ en footer del formulario
- Landing footer: aviso detallado de protección de datos LOPDP/NJ

## api.ts: consolidations.* client methods
This commit is contained in:
Lizandro Guarnizo
2026-06-01 18:29:26 -05:00
parent 5565eef554
commit 7682b11dff
23 changed files with 2158 additions and 95 deletions
+54 -1
View File
@@ -1,4 +1,4 @@
// Moraworld Imports — Schema v0.3 (Fase 2Bodegas + Integraciones)
// Moraworld Imports — Schema v0.5 (Fase 3Consolidación + Pagos + Plantillas)
// Multi-tenant por tenant_id en todas las tablas de negocio
// Sincronizado con documentacion.html v1.1
@@ -11,6 +11,14 @@ datasource db {
url = env("DATABASE_URL")
}
enum ConsolidationStatus {
ABIERTA // Recibiendo paquetes
CERRADA // Lista para despacho
DESPACHADA // Enviada al courier internacional
ENTREGADA // Entregada en Ecuador
CANCELADA
}
enum PaymentStatus {
PENDIENTE
PROCESANDO
@@ -102,6 +110,7 @@ model Tenant {
integrations Integration[]
notificationTemplates NotificationTemplate[]
payments Payment[]
consolidations Consolidation[]
}
// ─── Usuarios ────────────────────────────────────────────────
@@ -207,6 +216,7 @@ model Package {
preAlert PreAlert?
notifications Notification[]
payment Payment?
consolidation ConsolidationPackage?
@@index([tenantId, status])
@@index([userId])
@@ -387,6 +397,49 @@ model Warehouse {
@@index([tenantId])
}
// ─── Consolidaciones (§21) ────────────────────────────────────
/// Agrupa múltiples paquetes del mismo cliente en un solo envío.
/// Optimiza costos de flete y reduce declaraciones aduaneras.
model Consolidation {
id String @id @default(cuid())
tenantId String
userId String // cliente dueño de los paquetes
/// Código de consolidación: CON-YYYYMMDD-XXXXXX
code String @unique
status ConsolidationStatus @default(ABIERTA)
/// Peso total real en libras (suma de paquetes)
totalWeightLb Decimal? @db.Decimal(8, 2)
/// Valor declarado total en USD
totalValue Decimal? @db.Decimal(10, 2)
/// Notas del operador
notes String?
/// Número de seguimiento del courier internacional (FedEx / DHL / UPS)
courierTracking String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy String?
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
packages ConsolidationPackage[]
@@index([tenantId, status])
@@index([userId])
}
/// Tabla intermedia — paquetes incluidos en una consolidación
model ConsolidationPackage {
id String @id @default(cuid())
consolidationId String
packageId String @unique // un paquete solo puede estar en una consolidación
addedAt DateTime @default(now())
consolidation Consolidation @relation(fields: [consolidationId], references: [id], onDelete: Cascade)
package Package @relation(fields: [packageId], references: [id], onDelete: Cascade)
@@index([consolidationId])
}
// ─── Pagos (§09 paso 8 / §14 paso 5) ─────────────────────────
/// Registro de pagos vinculados a un paquete.