mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Fare and route-coach, production checklist updates
This commit is contained in:
@@ -2,12 +2,20 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { PrismaService } from '../../common/prisma.service';
|
||||
import { SmsClientService } from '../notifications/sms-client.service';
|
||||
import { CurrencyService } from '../currency/currency.service';
|
||||
|
||||
/** Maximum time (hours) a passenger has to pay after booking. */
|
||||
const MAX_PAYMENT_HOURS = 2;
|
||||
/** Minutes before departure: cutoff for new bookings and payment deadline. */
|
||||
const CUTOFF_MINUTES = 30;
|
||||
|
||||
// Retention windows
|
||||
const OTP_RETENTION_HOURS = 1;
|
||||
const FAYDA_SESSION_RETENTION_HOURS = 1;
|
||||
const AUDIT_LOG_RETENTION_DAYS = 365;
|
||||
const WEBHOOK_EVENT_RETENTION_DAYS = 90;
|
||||
const GATE_LOG_RETENTION_DAYS = 180;
|
||||
|
||||
/**
|
||||
* payment_deadline = MIN(booking_time + 2h, departure_time - 30min)
|
||||
*/
|
||||
@@ -32,6 +40,7 @@ export class TasksService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly sms: SmsClientService,
|
||||
private readonly currencyService: CurrencyService,
|
||||
) {}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@@ -243,4 +252,47 @@ export class TasksService {
|
||||
this.logger.log(`Auto-cancelled ${cancelledCount} expired pending booking(s)`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Daily at 01:00 EAT: fetch mid-market rates from central bank API.
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@Cron('0 1 * * *', { timeZone: 'Africa/Addis_Ababa' })
|
||||
async syncExchangeRates() {
|
||||
try {
|
||||
await this.currencyService.syncExchangeRates();
|
||||
} catch (err) {
|
||||
this.logger.error(`Exchange rate sync failed: ${(err as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Daily at 02:00 EAT: purge expired/stale records to enforce data retention.
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
@Cron('0 2 * * *')
|
||||
async purgeExpiredData() {
|
||||
const now = new Date();
|
||||
|
||||
const otpCutoff = new Date(now.getTime() - OTP_RETENTION_HOURS * 60 * 60 * 1000);
|
||||
const faydaCutoff = new Date(now.getTime() - FAYDA_SESSION_RETENTION_HOURS * 60 * 60 * 1000);
|
||||
const auditCutoff = new Date(now.getTime() - AUDIT_LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000);
|
||||
const webhookCutoff = new Date(now.getTime() - WEBHOOK_EVENT_RETENTION_DAYS * 24 * 60 * 60 * 1000);
|
||||
const gateCutoff = new Date(now.getTime() - GATE_LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000);
|
||||
|
||||
const [otps, faydaSessions, auditLogs, webhookEvents, gateLogs] = await Promise.all([
|
||||
this.prisma.otpCode.deleteMany({
|
||||
where: { OR: [{ expiresAt: { lte: otpCutoff } }, { verified: true, createdAt: { lte: otpCutoff } }] },
|
||||
}),
|
||||
this.prisma.faydaVerificationSession.deleteMany({
|
||||
where: { OR: [{ expiresAt: { lte: faydaCutoff } }, { status: { in: ['COMPLETED', 'FAILED'] }, createdAt: { lte: faydaCutoff } }] },
|
||||
}),
|
||||
this.prisma.auditLog.deleteMany({ where: { createdAt: { lte: auditCutoff } } }),
|
||||
this.prisma.paymentWebhookEvent.deleteMany({ where: { receivedAt: { lte: webhookCutoff } } }),
|
||||
this.prisma.gateValidationLog.deleteMany({ where: { validatedAt: { lte: gateCutoff } } }),
|
||||
]);
|
||||
|
||||
this.logger.log(
|
||||
`Data retention purge: ${otps.count} OTPs, ${faydaSessions.count} Fayda sessions, ` +
|
||||
`${auditLogs.count} audit logs, ${webhookEvents.count} webhook events, ${gateLogs.count} gate logs deleted`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user