Add standalone Leads module for prospect outreach before customers.
Import large Excel lists with duplicate checks, assign and kanban follow-up, convert to Person when ready; also fix OTP mobile mask order and SMS brand name to منتکت. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -203,6 +203,10 @@ model Organization {
|
||||
voipConnections VoipConnection[]
|
||||
reservationServices ReservationService[]
|
||||
reservationAppointments ReservationAppointment[]
|
||||
leads Lead[]
|
||||
leadStages LeadStage[]
|
||||
leadEvents LeadEvent[]
|
||||
leadImportJobs LeadImportJob[]
|
||||
}
|
||||
|
||||
model User {
|
||||
@@ -251,6 +255,8 @@ model User {
|
||||
assignedProjectCards ProjectCard[] @relation("ProjectCardAssignees")
|
||||
teamMemberships TeamMember[]
|
||||
reservationAssignments ReservationAppointment[] @relation("ReservationAssignee")
|
||||
assignedLeads Lead[] @relation("LeadAssignee")
|
||||
createdLeads Lead[] @relation("LeadCreator")
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -1922,3 +1928,116 @@ model ReservationAppointment {
|
||||
@@index([personId])
|
||||
@@index([assigneeId, startsAt])
|
||||
}
|
||||
|
||||
/// مرحله/وضعیت لید — هم لیست وضعیت و هم ستون Kanban
|
||||
model LeadStage {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
position Int @default(0)
|
||||
color String @default("teal")
|
||||
/// نمایش در تخته Kanban
|
||||
showOnBoard Boolean @default(true)
|
||||
isConverted Boolean @default(false)
|
||||
isLost Boolean @default(false)
|
||||
isUnqualified Boolean @default(false)
|
||||
leads Lead[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, position])
|
||||
@@unique([organizationId, name])
|
||||
}
|
||||
|
||||
/// مخاطب بالقوه — جدا از Person/مشتری
|
||||
model Lead {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
/// نام فروشگاه / شخص / عنوان نمایشی
|
||||
title String
|
||||
/// نام مالک یا مسئول
|
||||
contactName String?
|
||||
mobile String
|
||||
phone String?
|
||||
city String?
|
||||
region String?
|
||||
/// صنف
|
||||
trade String?
|
||||
source String?
|
||||
notes String?
|
||||
estimatedValue Decimal? @db.Decimal(18, 2)
|
||||
stageId String
|
||||
stage LeadStage @relation(fields: [stageId], references: [id], onDelete: Restrict)
|
||||
position Int @default(0)
|
||||
assigneeId String?
|
||||
assignee User? @relation("LeadAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
||||
createdById String?
|
||||
createdBy User? @relation("LeadCreator", fields: [createdById], references: [id], onDelete: SetNull)
|
||||
lastContactAt DateTime?
|
||||
nextFollowUpAt DateTime?
|
||||
/// شخص مشتری پس از تبدیل
|
||||
convertedPersonId String?
|
||||
convertedAt DateTime?
|
||||
archivedAt DateTime?
|
||||
events LeadEvent[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, mobile])
|
||||
@@index([organizationId, stageId, position])
|
||||
@@index([organizationId, assigneeId])
|
||||
@@index([organizationId, nextFollowUpAt])
|
||||
@@index([organizationId, lastContactAt])
|
||||
@@index([organizationId, archivedAt])
|
||||
@@index([organizationId, createdAt])
|
||||
@@index([organizationId, city])
|
||||
@@index([organizationId, trade])
|
||||
@@index([organizationId, source])
|
||||
}
|
||||
|
||||
model LeadEvent {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
leadId String
|
||||
lead Lead @relation(fields: [leadId], references: [id], onDelete: Cascade)
|
||||
/// created | assigned | stage_changed | call | note | task | follow_up | converted | archived | import
|
||||
type String
|
||||
title String
|
||||
body String?
|
||||
meta Json?
|
||||
actorId String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([leadId, createdAt])
|
||||
@@index([organizationId, createdAt])
|
||||
}
|
||||
|
||||
/// ایمپورت پسزمینه فایل اکسل لید
|
||||
model LeadImportJob {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
createdById String?
|
||||
fileName String?
|
||||
/// pending | processing | done | failed
|
||||
status String @default("pending")
|
||||
totalCount Int @default(0)
|
||||
processedCount Int @default(0)
|
||||
successCount Int @default(0)
|
||||
duplicateCount Int @default(0)
|
||||
errorCount Int @default(0)
|
||||
/// ردیفهای خام [{...}]
|
||||
rows Json @default("[]")
|
||||
/// خلاصه خطاها
|
||||
errorSamples Json @default("[]")
|
||||
startedAt DateTime?
|
||||
finishedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, status, createdAt])
|
||||
@@index([status, createdAt])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user