feat(notificaciones): one send log across servicios and pólizas
Renewal avisos left behind only a `RenewalNotice` row, whose sole job is gating: a row with `sentAt` drops the policy off the pending list. It cannot represent a failed send or a customer with no address, so the Pólizas tab had no "Registro de envíos" to show and a sent notice simply vanished from the list. Renewals now write `email_notification_log` — the same table the four bulk jobs write — as `RENEWAL_NOTICE` / `POLICIES`, with rows for failures and no-email skips too. `RenewalNotice` keeps its gating role unchanged; the two are complementary, not redundant. - extend `EmailNotificationType` (+RENEWAL_NOTICE) and `EmailNotificationServicio` (+POLICIES); `level` now carries the aviso generation on renewal rows, so every reader must branch on the type first (`notificationLevelLabel()` is the one place that lives) - backfill emailed notices (`channel = 'EMAIL'`) into the log; MAIL-channel rows are legacy printed letters and are deliberately left out - extract `NotificationLogService`/`NotificationLogModule` as the single writer, so a feature that sends mail records it without pulling the bulk-job pipelines into its module - `GET /notifications/log` and `/stats` take a comma-separated `servicio` list; each tab reads its own slice. This also fixes the "Omitidos" view, which mapped to no filter at all and showed every row - share one `NotificationLogPanel` between both tabs - pass SES_* / NOTIFICATION_ADMIN_EMAILS through the galactus compose, which was missing them entirely — mail is runtime config, not a CI secret, and the prod image sets NODE_ENV=production so a blank config fails loudly instead of falling back to stdout Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -944,20 +944,31 @@ model EmailLog {
|
||||
/// red and yellow; the threshold is in the
|
||||
/// `level` column, 0=yellow / 1=red)
|
||||
/// - TRUST_PAYMENT_CONFIRMATION → sendConfirmTrustPayment.php (TRUSTHFEE)
|
||||
///
|
||||
/// RENEWAL_NOTICE has no PHP ancestor — it is the insurance renewal aviso
|
||||
/// (`RenewalsService`), logged here so every outbound email the platform
|
||||
/// sends lands in one table. `RenewalNotice` remains the per-policy
|
||||
/// "already notified" record that drives the pending list; this log is the
|
||||
/// send history, including the failures and skips `RenewalNotice` cannot
|
||||
/// represent.
|
||||
enum EmailNotificationType {
|
||||
OUTSTANDING_PAYMENT
|
||||
PAYMENT_CONFIRMATION
|
||||
ACCOUNT_STATUS
|
||||
TRUST_PAYMENT_CONFIRMATION
|
||||
RENEWAL_NOTICE
|
||||
}
|
||||
|
||||
/// Which "servicio" (line of business) the notification draws its recipients
|
||||
/// from. CUSTOMERS = the unified customers ledger (replaces `datosfreak`);
|
||||
/// TRUST = the trust-fee account table (replaces `TRUSTHFEE`). Keeping the
|
||||
/// two services tagged makes a per-line report trivial.
|
||||
/// TRUST = the trust-fee account table (replaces `TRUSTHFEE`);
|
||||
/// POLICIES = the insurance book (renewal avisos). Keeping the services
|
||||
/// tagged makes a per-line report trivial — and lets the /notificaciones
|
||||
/// tabs each show their own slice of the one log.
|
||||
enum EmailNotificationServicio {
|
||||
CUSTOMERS
|
||||
TRUST
|
||||
POLICIES
|
||||
}
|
||||
|
||||
/// Outcome of a single send attempt. SENT / FAILED are the meaningful ones;
|
||||
@@ -982,11 +993,17 @@ model EmailNotificationLog {
|
||||
id String @id @default(uuid())
|
||||
sendDate DateTime @default(now())
|
||||
notificationType EmailNotificationType
|
||||
/// 0 = yellow ("DEBAJO DEL TIPO"), 1 = red ("EN ROJO"). Only set on
|
||||
/// ACCOUNT_STATUS rows; null on the other three jobs.
|
||||
/// Per-type discriminator, null where the type has none:
|
||||
/// ACCOUNT_STATUS → 0 = yellow ("DEBAJO DEL TIPO"), 1 = red ("EN ROJO")
|
||||
/// RENEWAL_NOTICE → the aviso generation (1 = 30d before, 2 = 15d
|
||||
/// before, 3 = 7d after expiry)
|
||||
/// Null on the remaining jobs. Readers MUST branch on notificationType
|
||||
/// before interpreting it.
|
||||
level Int?
|
||||
/// Which servicio sourced the recipient list. CUSTOMERS for jobs 1/2/3,
|
||||
/// TRUST for job 4. Tagged here so a per-line audit doesn't need to join.
|
||||
/// TRUST for job 4, POLICIES for renewal avisos. Tagged here so a per-line
|
||||
/// audit doesn't need to join — and so the /notificaciones Servicios tab
|
||||
/// (CUSTOMERS + TRUST) and Pólizas tab (POLICIES) can filter one log.
|
||||
servicio EmailNotificationServicio
|
||||
/// FK to the customer that triggered the send. Trust-account notifications
|
||||
/// resolve the owner through `Property.customerId`, so this stays set on
|
||||
|
||||
Reference in New Issue
Block a user