fix notifications
Build & Push / Pipeline Tests (push) Failing after 1m8s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 52s
Test / Homepage Unit Tests (push) Successful in 46s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 43s
Test / Dashboard Unit Tests (push) Successful in 46s
Test / API Integration Tests (push) Successful in 1m7s
Build & Push / Pipeline Tests (push) Failing after 1m8s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 52s
Test / Homepage Unit Tests (push) Successful in 46s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 43s
Test / Dashboard Unit Tests (push) Successful in 46s
Test / API Integration Tests (push) Successful in 1m7s
This commit is contained in:
+19
-30
@@ -159,7 +159,6 @@ cron.schedule('0 9 * * *', async () => {
|
||||
cron.schedule('0 8 * * *', async () => {
|
||||
const now = new Date()
|
||||
const in30Days = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000)
|
||||
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000)
|
||||
|
||||
// Fetch all candidate logs (date-due or has an odometer target), ordered newest-first per vehicle+type.
|
||||
// We keep only the LATEST log per vehicle+type so that once the owner logs a new service the
|
||||
@@ -213,17 +212,6 @@ cron.schedule('0 8 * * *', async () => {
|
||||
const isDueSoon = !isOverdue && (dueSoonByDate || dueSoonByOdometer)
|
||||
if (!isOverdue && !isDueSoon) continue
|
||||
|
||||
// Dedup: don't send more than once per day for the same log
|
||||
const alreadySent = await prisma.notification.findFirst({
|
||||
where: {
|
||||
type: 'VEHICLE_MAINTENANCE_DUE',
|
||||
companyId: company.id,
|
||||
createdAt: { gte: oneDayAgo },
|
||||
data: { path: ['maintenanceLogId'], equals: log.id },
|
||||
},
|
||||
})
|
||||
if (alreadySent) continue
|
||||
|
||||
// Build human-readable description
|
||||
const dueParts: string[] = []
|
||||
if (isOverdueByDate) dueParts.push(`overdue since ${log.nextDueAt!.toLocaleDateString()}`)
|
||||
@@ -236,26 +224,27 @@ cron.schedule('0 8 * * *', async () => {
|
||||
: `${log.type} due soon — ${vehicle.make} ${vehicle.model}`
|
||||
const body = `${log.type} for ${vehicle.make} ${vehicle.model} (${vehicle.licensePlate}): ${dueParts.join('; ')}. Please log the service to dismiss this reminder.`
|
||||
|
||||
await prisma.notification.create({
|
||||
const reminderDate = now.toISOString().slice(0, 10)
|
||||
await sendNotification({
|
||||
type: 'VEHICLE_MAINTENANCE_DUE',
|
||||
title,
|
||||
body,
|
||||
data: {
|
||||
type: 'VEHICLE_MAINTENANCE_DUE',
|
||||
title,
|
||||
body,
|
||||
data: {
|
||||
vehicleId: vehicle.id,
|
||||
maintenanceLogId: log.id,
|
||||
maintenanceType: log.type,
|
||||
isOverdue,
|
||||
daysLeft,
|
||||
kmLeft,
|
||||
isOverdueByDate,
|
||||
isOverdueByOdometer,
|
||||
},
|
||||
companyId: company.id,
|
||||
employeeId: recipient.id,
|
||||
channel: 'IN_APP',
|
||||
status: 'DELIVERED',
|
||||
vehicleId: vehicle.id,
|
||||
maintenanceLogId: log.id,
|
||||
maintenanceType: log.type,
|
||||
isOverdue,
|
||||
daysLeft,
|
||||
kmLeft,
|
||||
isOverdueByDate,
|
||||
isOverdueByOdometer,
|
||||
},
|
||||
companyId: company.id,
|
||||
employeeId: recipient.id,
|
||||
channels: ['IN_APP'],
|
||||
sourceType: 'maintenance_log',
|
||||
sourceId: log.id,
|
||||
idempotencyKey: `maintenance:${log.id}:${recipient.id}:${reminderDate}`,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user