Task templates: add level field (Policy/Renewal Group/Both) with schema migration, UI selector, and generation logic
This commit is contained in:
parent
cfefc255b1
commit
c1a836d5d8
5 changed files with 54 additions and 7 deletions
|
|
@ -271,6 +271,12 @@ enum TaskTiming {
|
|||
POST_RENEWAL
|
||||
}
|
||||
|
||||
enum TaskLevel {
|
||||
POLICY
|
||||
RENEWAL_GROUP
|
||||
BOTH
|
||||
}
|
||||
|
||||
enum DepartmentType {
|
||||
PERSONAL_LINES
|
||||
COMMERCIAL_LINES
|
||||
|
|
@ -290,6 +296,7 @@ model TaskTemplate {
|
|||
taskGroup String? @map("task_group")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
displayOrder Int? @map("display_order")
|
||||
level TaskLevel @default(BOTH)
|
||||
designationId String? @map("designation_id")
|
||||
createdBy String? @map("created_by")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ export async function POST(request: NextRequest) {
|
|||
const templates = await prisma.taskTemplate.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
level: { in: ['BOTH', 'RENEWAL_GROUP'] },
|
||||
OR: [
|
||||
{ designationId: null },
|
||||
...(designationIds.length > 0 ? [{ designationId: { in: designationIds } }] : []),
|
||||
|
|
@ -159,6 +160,7 @@ export async function POST(request: NextRequest) {
|
|||
const templates = await prisma.taskTemplate.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
level: { in: ['BOTH', 'POLICY'] },
|
||||
OR: [
|
||||
{ designationId: null },
|
||||
...(designationIds.length > 0 ? [{ designationId: { in: designationIds } }] : []),
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ export async function POST(
|
|||
where: {
|
||||
isActive: true,
|
||||
id: { notIn: alreadyGeneratedTemplateIds },
|
||||
level: { in: ['BOTH', 'RENEWAL_GROUP'] },
|
||||
OR: [
|
||||
{ designationId: null },
|
||||
...(designationIds.length > 0
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export async function POST(request: NextRequest) {
|
|||
|
||||
const clientIds = clients.map((c) => c.id)
|
||||
|
||||
const templates = await prisma.taskTemplate.findMany({
|
||||
const allTemplates = await prisma.taskTemplate.findMany({
|
||||
where: {
|
||||
isActive: true,
|
||||
OR: [{ designationId: null }, { designationId }],
|
||||
|
|
@ -69,7 +69,7 @@ export async function POST(request: NextRequest) {
|
|||
orderBy: [{ department: 'asc' }, { daysOffset: 'asc' }],
|
||||
})
|
||||
|
||||
if (templates.length === 0) {
|
||||
if (allTemplates.length === 0) {
|
||||
return NextResponse.json({
|
||||
tasksCreated: 0,
|
||||
tasksAssigned: 0,
|
||||
|
|
@ -80,7 +80,8 @@ export async function POST(request: NextRequest) {
|
|||
})
|
||||
}
|
||||
|
||||
const templateIds = templates.map((t) => t.id)
|
||||
const groupTemplates = allTemplates.filter((t: any) => t.level === 'BOTH' || t.level === 'RENEWAL_GROUP')
|
||||
const policyTemplates = allTemplates.filter((t: any) => t.level === 'BOTH' || t.level === 'POLICY')
|
||||
let tasksCreated = 0
|
||||
let tasksAssigned = 0
|
||||
let groupsProcessed = 0
|
||||
|
|
@ -95,7 +96,7 @@ export async function POST(request: NextRequest) {
|
|||
|
||||
for (const group of groups) {
|
||||
const renewalDate = new Date(group.renewalDate)
|
||||
const tasksToCreate = templates.map((template) => {
|
||||
const tasksToCreate = groupTemplates.map((template) => {
|
||||
const dueDate = new Date(renewalDate)
|
||||
dueDate.setDate(dueDate.getDate() + template.daysOffset)
|
||||
return {
|
||||
|
|
@ -119,7 +120,7 @@ export async function POST(request: NextRequest) {
|
|||
|
||||
if (created.count > 0) {
|
||||
const newTasks = await prisma.task.findMany({
|
||||
where: { policyGroupId: group.id, templateId: { in: templateIds } },
|
||||
where: { policyGroupId: group.id, templateId: { in: groupTemplates.map((t) => t.id) } },
|
||||
select: { id: true },
|
||||
})
|
||||
if (newTasks.length > 0) {
|
||||
|
|
@ -144,7 +145,7 @@ export async function POST(request: NextRequest) {
|
|||
|
||||
for (const policy of policies) {
|
||||
const anchorDate = new Date(policy.expirationDate)
|
||||
const tasksToCreate = templates.map((template) => {
|
||||
const tasksToCreate = policyTemplates.map((template) => {
|
||||
const dueDate = new Date(anchorDate)
|
||||
dueDate.setDate(dueDate.getDate() + template.daysOffset)
|
||||
return {
|
||||
|
|
@ -168,7 +169,7 @@ export async function POST(request: NextRequest) {
|
|||
|
||||
if (created.count > 0) {
|
||||
const newTasks = await prisma.task.findMany({
|
||||
where: { policyId: policy.id, templateId: { in: templateIds } },
|
||||
where: { policyId: policy.id, templateId: { in: policyTemplates.map((t) => t.id) } },
|
||||
select: { id: true },
|
||||
})
|
||||
if (newTasks.length > 0) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import { Label } from '@/components/ui/label'
|
|||
type DepartmentType = 'PERSONAL_LINES' | 'COMMERCIAL_LINES' | 'CLAIMS' | 'BENEFITS' | 'OTHER'
|
||||
type TaskTiming = 'PRE_RENEWAL' | 'POST_RENEWAL'
|
||||
type TaskPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT'
|
||||
type TaskLevel = 'POLICY' | 'RENEWAL_GROUP' | 'BOTH'
|
||||
|
||||
interface Designation {
|
||||
id: string
|
||||
|
|
@ -63,6 +64,7 @@ interface TaskTemplate {
|
|||
taskGroup: string | null
|
||||
isActive: boolean
|
||||
displayOrder: number | null
|
||||
level: TaskLevel
|
||||
designationId: string | null
|
||||
designation: Designation | null
|
||||
_count: { tasks: number }
|
||||
|
|
@ -93,6 +95,12 @@ const PRIORITIES: { value: TaskPriority; label: string; color: string }[] = [
|
|||
{ value: 'URGENT', label: 'Urgent', color: 'bg-red-100 text-red-700' },
|
||||
]
|
||||
|
||||
const LEVELS: { value: TaskLevel; label: string }[] = [
|
||||
{ value: 'BOTH', label: 'Both (Policy & Group)' },
|
||||
{ value: 'RENEWAL_GROUP', label: 'Renewal Group only' },
|
||||
{ value: 'POLICY', label: 'Policy only' },
|
||||
]
|
||||
|
||||
const emptyTemplate = {
|
||||
name: '',
|
||||
description: '',
|
||||
|
|
@ -103,6 +111,7 @@ const emptyTemplate = {
|
|||
taskGroup: '',
|
||||
isActive: true,
|
||||
displayOrder: null as number | null,
|
||||
level: 'BOTH' as TaskLevel,
|
||||
designationId: null as string | null,
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +163,7 @@ export function TaskTemplateManager({
|
|||
taskGroup: template.taskGroup || '',
|
||||
isActive: template.isActive,
|
||||
displayOrder: template.displayOrder,
|
||||
level: template.level,
|
||||
designationId: template.designationId,
|
||||
})
|
||||
setIsDialogOpen(true)
|
||||
|
|
@ -446,6 +456,26 @@ export function TaskTemplateManager({
|
|||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label>Level</Label>
|
||||
<Select
|
||||
value={formData.level}
|
||||
onValueChange={(value: TaskLevel) =>
|
||||
setFormData((prev) => ({ ...prev, level: value }))
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{LEVELS.map((lvl) => (
|
||||
<SelectItem key={lvl.value} value={lvl.value}>
|
||||
{lvl.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label>Designation</Label>
|
||||
<Select
|
||||
|
|
@ -546,6 +576,7 @@ export function TaskTemplateManager({
|
|||
<TableHead>Name</TableHead>
|
||||
<TableHead>Department</TableHead>
|
||||
<TableHead>Timing</TableHead>
|
||||
<TableHead>Level</TableHead>
|
||||
<TableHead>Designation</TableHead>
|
||||
<TableHead>Priority</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
|
|
@ -583,6 +614,11 @@ export function TaskTemplateManager({
|
|||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<span className="text-sm">
|
||||
{LEVELS.find((l) => l.value === template.level)?.label || template.level}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{template.designation ? (
|
||||
<Badge variant="outline" className="flex items-center gap-1 w-fit">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue