feat: payments module, notification templates, WA float, route fixes

- Add PaymentsModule: POST /payments/intent, POST /:id/confirm, GET /payments, GET /payments/package/:id, GET /payments/track/:trackingId
- Add Payment model to Prisma schema (PaymentStatus enum, Payment table)
- Add NotificationTemplate model + NotificationsController (GET/PUT /notification-templates, POST /notification-templates/seed)
- Update NotificationsService: DB-backed templates with variable interpolation {{trackingId}} {{firstName}} {{status}} {{suiteCode}}
- Fix /bodega/paquetes: replace 11 wrong status strings with correct §08 enum values
- Fix /admin/reportes: replace EN_CAMINO_A_ECUADOR with correct §08 statuses, rewrite report page with proper KPIs and bar charts
- Fix /portal/mis-paquetes: correct §08 statuses, add 'Pagar envío' button for VERIFICADO/DECLARACION_ADUANERA packages
- Add WhatsApp float component (_components/whatsapp-float.tsx, 2 contacts: NJ ops + Cuenca aduana)
- Add /casillero/calculadora and /casillero/registro redirects (§20)
- Add /portal/pago payment page with cost breakdown (§09/§14/§15)
- Add /admin/notificaciones page: view/edit/toggle templates per event×channel
- Admin nav: add Notificaciones link
- api.ts: add notificationTemplates.* and payments.* client methods
- schema.prisma v0.4: PaymentStatus enum, Payment model, NotificationTemplate model
- db push applied to remote DB (46.202.93.92)
- All builds pass (API nest build + Next.js build)
This commit is contained in:
Lizandro Guarnizo
2026-06-01 17:09:05 -05:00
parent b2b292c50a
commit 5565eef554
20 changed files with 1326 additions and 97 deletions
+60
View File
@@ -11,6 +11,14 @@ datasource db {
url = env("DATABASE_URL")
}
enum PaymentStatus {
PENDIENTE
PROCESANDO
COMPLETADO
FALLIDO
REEMBOLSADO
}
// ─── Enums ───────────────────────────────────────────────────
enum UserRole {
@@ -92,6 +100,8 @@ model Tenant {
b2bRequests B2BRequest[]
warehouses Warehouse[]
integrations Integration[]
notificationTemplates NotificationTemplate[]
payments Payment[]
}
// ─── Usuarios ────────────────────────────────────────────────
@@ -196,6 +206,7 @@ model Package {
statusHistory PackageStatusHistory[]
preAlert PreAlert?
notifications Notification[]
payment Payment?
@@index([tenantId, status])
@@index([userId])
@@ -376,6 +387,55 @@ model Warehouse {
@@index([tenantId])
}
// ─── Pagos (§09 paso 8 / §14 paso 5) ─────────────────────────
/// Registro de pagos vinculados a un paquete.
/// El `providerRef` es el PaymentIntent ID de Stripe (o equivalente).
model Payment {
id String @id @default(cuid())
tenantId String
packageId String @unique
userId String
amount Decimal @db.Decimal(10, 2)
currency String @default("USD")
/// "stripe" | "payphone" | "paypal"
provider String @default("stripe")
/// PaymentIntent ID de Stripe u equivalente
providerRef String?
status PaymentStatus @default(PENDIENTE)
paidAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
package Package @relation(fields: [packageId], references: [id], onDelete: Cascade)
@@index([tenantId, status])
@@index([userId])
}
// ─── Plantillas de notificación (§12) ────────────────────────
/// Plantillas de mensajes para cada evento del ciclo de vida del paquete.
/// Soporta variables: {{trackingId}}, {{firstName}}, {{status}}, {{suiteCode}}
model NotificationTemplate {
id String @id @default(cuid())
tenantId String
/// Evento que dispara la notificación — coincide con PackageStatus
event String // ej: "REGISTRADO", "ENTREGADO"
channel NotificationChannel
subject String? // Solo relevante para EMAIL
body String
isActive Boolean @default(true)
updatedAt DateTime @updatedAt
updatedBy String?
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
@@unique([tenantId, event, channel])
@@index([tenantId, event])
}
// ─── Integraciones (API keys por tenant) ─────────────────────
/// Configuración de integraciones externas (API keys, endpoints, webhooks).