Fix Shape import: resolve policyId/policyGroupId when creating new tasks
- Add resolvePolicyLink() to find closest policy group or policy by effectiveDate window - Include template level in DbTemplate interface and loadDbState query - New tasks created by import now carry correct policyId or policyGroupId - Delete all 492 orphaned POLICY/RENEWAL_GROUP tasks (no policy link)
This commit is contained in:
parent
00b5fab1ba
commit
02afceb0c5
1 changed files with 46 additions and 5 deletions
|
|
@ -50,6 +50,7 @@ interface DbTemplate {
|
||||||
name: string
|
name: string
|
||||||
daysOffset: number
|
daysOffset: number
|
||||||
designationId: string | null
|
designationId: string | null
|
||||||
|
level: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DbClient {
|
interface DbClient {
|
||||||
|
|
@ -511,6 +512,7 @@ async function loadDbState(log: (l: string) => Promise<void>): Promise<DbState>
|
||||||
|
|
||||||
const allTemplates = await prisma.taskTemplate.findMany({
|
const allTemplates = await prisma.taskTemplate.findMany({
|
||||||
where: { designationId: { in: [shapeDes.id, shape2Des.id] }, isActive: true },
|
where: { designationId: { in: [shapeDes.id, shape2Des.id] }, isActive: true },
|
||||||
|
select: { id: true, name: true, daysOffset: true, designationId: true, level: true },
|
||||||
})
|
})
|
||||||
const shapeTemplates = allTemplates.filter((t) => t.designationId === shapeDes.id)
|
const shapeTemplates = allTemplates.filter((t) => t.designationId === shapeDes.id)
|
||||||
const shape2Templates = allTemplates.filter((t) => t.designationId === shape2Des.id)
|
const shape2Templates = allTemplates.filter((t) => t.designationId === shape2Des.id)
|
||||||
|
|
@ -532,8 +534,8 @@ async function loadDbState(log: (l: string) => Promise<void>): Promise<DbState>
|
||||||
return {
|
return {
|
||||||
clientsByNormalizedName,
|
clientsByNormalizedName,
|
||||||
allClients: clients.map((c) => ({ id: c.id, name: c.name, claimsAdvocateId: c.claimsAdvocateId })),
|
allClients: clients.map((c) => ({ id: c.id, name: c.name, claimsAdvocateId: c.claimsAdvocateId })),
|
||||||
shapeTemplates: shapeTemplates.map((t) => ({ id: t.id, name: t.name, daysOffset: t.daysOffset, designationId: t.designationId })),
|
shapeTemplates: shapeTemplates.map((t) => ({ id: t.id, name: t.name, daysOffset: t.daysOffset, designationId: t.designationId, level: t.level })),
|
||||||
shape2Templates: shape2Templates.map((t) => ({ id: t.id, name: t.name, daysOffset: t.daysOffset, designationId: t.designationId })),
|
shape2Templates: shape2Templates.map((t) => ({ id: t.id, name: t.name, daysOffset: t.daysOffset, designationId: t.designationId, level: t.level })),
|
||||||
shapeDesignationId: shapeDes.id,
|
shapeDesignationId: shapeDes.id,
|
||||||
shape2DesignationId: shape2Des.id,
|
shape2DesignationId: shape2Des.id,
|
||||||
}
|
}
|
||||||
|
|
@ -594,7 +596,45 @@ async function ensureTaskAssignment(taskId: string, userId: string, stats: Impor
|
||||||
} catch { /* already exists */ }
|
} catch { /* already exists */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processTaskRow(clientId: string, row: ParsedRow, template: DbTemplate, effectiveDate: Date, advocateUserId: string, stats: ImportStats, dryRun: boolean): Promise<void> {
|
async function resolvePolicyLink(clientId: string, effectiveDate: Date, templateLevel: string): Promise<{ policyId?: string; policyGroupId?: string }> {
|
||||||
|
if (templateLevel === 'CLIENT') return {}
|
||||||
|
const windowMs = 40 * 86400 * 1000
|
||||||
|
const from = new Date(effectiveDate.getTime() - windowMs)
|
||||||
|
const to = new Date(effectiveDate.getTime() + windowMs)
|
||||||
|
|
||||||
|
if (templateLevel === 'RENEWAL_GROUP' || templateLevel === 'BOTH') {
|
||||||
|
const group = await prisma.policyGroup.findFirst({
|
||||||
|
where: { clientId, renewalDate: { gte: from, lte: to } },
|
||||||
|
orderBy: { renewalDate: 'asc' },
|
||||||
|
select: { id: true, renewalDate: true },
|
||||||
|
})
|
||||||
|
if (group) return { policyGroupId: group.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateLevel === 'POLICY' || templateLevel === 'BOTH') {
|
||||||
|
const policies = await prisma.policy.findMany({
|
||||||
|
where: {
|
||||||
|
clientId,
|
||||||
|
expirationDate: { gte: new Date(from.getTime() - 86400 * 1000), lte: new Date(to.getTime() - 86400 * 1000) },
|
||||||
|
status: { notIn: ['Cancelled', 'Non-Renewed', 'Rewritten', 'Not taken'] as any[] },
|
||||||
|
},
|
||||||
|
select: { id: true, expirationDate: true, policyGroupId: true },
|
||||||
|
orderBy: { expirationDate: 'asc' },
|
||||||
|
})
|
||||||
|
if (policies.length > 0) {
|
||||||
|
const best = policies.reduce((a, b) => {
|
||||||
|
const aRenewal = new Date(a.expirationDate).getTime() + 86400 * 1000
|
||||||
|
const bRenewal = new Date(b.expirationDate).getTime() + 86400 * 1000
|
||||||
|
return Math.abs(aRenewal - effectiveDate.getTime()) <= Math.abs(bRenewal - effectiveDate.getTime()) ? a : b
|
||||||
|
})
|
||||||
|
if (best.policyGroupId) return { policyGroupId: best.policyGroupId }
|
||||||
|
return { policyId: best.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processTaskRow(clientId: string, row: ParsedRow, template: DbTemplate & { level?: string }, effectiveDate: Date, advocateUserId: string, stats: ImportStats, dryRun: boolean): Promise<void> {
|
||||||
const dueDate = new Date(effectiveDate)
|
const dueDate = new Date(effectiveDate)
|
||||||
dueDate.setDate(dueDate.getDate() + Math.round(row.daysAfterRenewal))
|
dueDate.setDate(dueDate.getDate() + Math.round(row.daysAfterRenewal))
|
||||||
const { status, completedAt, naReason } = interpretDateCompleted(row.dateCompleted)
|
const { status, completedAt, naReason } = interpretDateCompleted(row.dateCompleted)
|
||||||
|
|
@ -617,15 +657,16 @@ async function processTaskRow(clientId: string, row: ParsedRow, template: DbTemp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
const link = dryRun ? {} : await resolvePolicyLink(clientId, effectiveDate, template.level ?? 'CLIENT')
|
||||||
if (status === 'COMPLETED' || status === 'NA') {
|
if (status === 'COMPLETED' || status === 'NA') {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
const newTask = await prisma.task.create({ data: { title: template.name, department: 'CLAIMS', timing: 'PRE_RENEWAL', daysOffset: template.daysOffset, dueDate, status, priority: 'MEDIUM', clientId, templateId: template.id, completedAt: completedAt ?? undefined, completedBy: status === 'COMPLETED' ? advocateUserId : undefined, naReason: naReason ?? undefined, notes: row.notes || undefined, isAdHoc: false, createdBy: advocateUserId } })
|
const newTask = await prisma.task.create({ data: { title: template.name, department: 'CLAIMS', timing: 'PRE_RENEWAL', daysOffset: template.daysOffset, dueDate, status, priority: 'MEDIUM', clientId, templateId: template.id, ...link, completedAt: completedAt ?? undefined, completedBy: status === 'COMPLETED' ? advocateUserId : undefined, naReason: naReason ?? undefined, notes: row.notes || undefined, isAdHoc: false, createdBy: advocateUserId } })
|
||||||
await ensureTaskAssignment(newTask.id, advocateUserId, stats, dryRun)
|
await ensureTaskAssignment(newTask.id, advocateUserId, stats, dryRun)
|
||||||
} else { stats.tasksAssigned++ }
|
} else { stats.tasksAssigned++ }
|
||||||
stats.tasksCreated++
|
stats.tasksCreated++
|
||||||
} else {
|
} else {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
const newTask = await prisma.task.create({ data: { title: template.name, department: 'CLAIMS', timing: 'PRE_RENEWAL', daysOffset: template.daysOffset, dueDate, status: 'NOT_STARTED', priority: 'MEDIUM', clientId, templateId: template.id, notes: row.notes || undefined, isAdHoc: false, createdBy: advocateUserId } })
|
const newTask = await prisma.task.create({ data: { title: template.name, department: 'CLAIMS', timing: 'PRE_RENEWAL', daysOffset: template.daysOffset, dueDate, status: 'NOT_STARTED', priority: 'MEDIUM', clientId, templateId: template.id, ...link, notes: row.notes || undefined, isAdHoc: false, createdBy: advocateUserId } })
|
||||||
await ensureTaskAssignment(newTask.id, advocateUserId, stats, dryRun)
|
await ensureTaskAssignment(newTask.id, advocateUserId, stats, dryRun)
|
||||||
} else { stats.tasksAssigned++ }
|
} else { stats.tasksAssigned++ }
|
||||||
stats.tasksCreated++
|
stats.tasksCreated++
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue