2026-08-29 21:06:30 +03:30
|
|
|
generator client {
|
|
|
|
|
provider = "prisma-client-js"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
datasource db {
|
|
|
|
|
provider = "postgresql"
|
|
|
|
|
url = env("DATABASE_URL")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum UserRole {
|
|
|
|
|
owner
|
|
|
|
|
admin
|
|
|
|
|
sales
|
|
|
|
|
support
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum DealStatus {
|
|
|
|
|
open
|
|
|
|
|
won
|
|
|
|
|
lost
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ActivityType {
|
|
|
|
|
call
|
|
|
|
|
meeting
|
|
|
|
|
task
|
|
|
|
|
note
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum ActivityStatus {
|
|
|
|
|
open
|
|
|
|
|
done
|
|
|
|
|
canceled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum CustomFieldEntity {
|
|
|
|
|
person
|
|
|
|
|
company
|
|
|
|
|
deal
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum CustomFieldType {
|
|
|
|
|
text
|
|
|
|
|
number
|
|
|
|
|
date
|
|
|
|
|
boolean
|
|
|
|
|
select
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum QuoteStatus {
|
|
|
|
|
draft
|
|
|
|
|
sent
|
|
|
|
|
accepted
|
|
|
|
|
rejected
|
|
|
|
|
expired
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum InvoiceStatus {
|
|
|
|
|
draft
|
|
|
|
|
issued
|
|
|
|
|
partially_paid
|
|
|
|
|
paid
|
|
|
|
|
canceled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum PaymentMethod {
|
|
|
|
|
cash
|
|
|
|
|
transfer
|
|
|
|
|
card
|
|
|
|
|
check
|
|
|
|
|
other
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum InstallmentStatus {
|
|
|
|
|
pending
|
|
|
|
|
paid
|
|
|
|
|
canceled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum TicketStatus {
|
|
|
|
|
open
|
|
|
|
|
in_progress
|
|
|
|
|
waiting
|
|
|
|
|
resolved
|
|
|
|
|
closed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum TicketPriority {
|
|
|
|
|
low
|
|
|
|
|
normal
|
|
|
|
|
high
|
|
|
|
|
urgent
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-30 09:42:07 +03:30
|
|
|
enum AutomationTrigger {
|
|
|
|
|
deal_won
|
|
|
|
|
ticket_resolved
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum AutomationAction {
|
|
|
|
|
create_activity
|
|
|
|
|
create_notification
|
|
|
|
|
add_loyalty_points
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-01 14:29:34 +03:30
|
|
|
enum NoteAiSuggestionStatus {
|
|
|
|
|
pending
|
|
|
|
|
applied
|
|
|
|
|
dismissed
|
|
|
|
|
failed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum MemorySourceType {
|
|
|
|
|
note
|
|
|
|
|
manual
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-29 21:06:30 +03:30
|
|
|
model Organization {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
name String
|
|
|
|
|
slug String @unique
|
|
|
|
|
baseCurrency String @default("IRR")
|
|
|
|
|
enabledCurrencies String[] @default(["IRR", "USD", "EUR"])
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
users User[]
|
|
|
|
|
companies Company[]
|
|
|
|
|
people Person[]
|
|
|
|
|
pipelines Pipeline[]
|
|
|
|
|
deals Deal[]
|
|
|
|
|
activities Activity[]
|
|
|
|
|
notes Note[]
|
|
|
|
|
customFields CustomFieldDefinition[]
|
|
|
|
|
products Product[]
|
|
|
|
|
notifications Notification[]
|
|
|
|
|
noteAttachments NoteAttachment[]
|
|
|
|
|
leadForms LeadForm[]
|
|
|
|
|
quotes Quote[]
|
|
|
|
|
invoices Invoice[]
|
|
|
|
|
salesGoals SalesGoal[]
|
|
|
|
|
exchangeRates ExchangeRate[]
|
|
|
|
|
tickets Ticket[]
|
|
|
|
|
faqArticles FaqArticle[]
|
|
|
|
|
portalOtps PortalOtp[]
|
2026-08-30 09:42:07 +03:30
|
|
|
projectBoards ProjectBoard[]
|
|
|
|
|
projectCards ProjectCard[]
|
|
|
|
|
loyaltyTiers LoyaltyTier[]
|
|
|
|
|
automationRules AutomationRule[]
|
2026-09-01 14:29:34 +03:30
|
|
|
memoryItems MemoryItem[]
|
|
|
|
|
noteAiSuggestions NoteAiSuggestion[]
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model User {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
email String
|
|
|
|
|
passwordHash String
|
|
|
|
|
fullName String
|
|
|
|
|
role UserRole @default(sales)
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
ownedDeals Deal[] @relation("DealOwner")
|
|
|
|
|
ownedQuotes Quote[] @relation("QuoteOwner")
|
|
|
|
|
ownedInvoices Invoice[] @relation("InvoiceOwner")
|
|
|
|
|
ownedPeople Person[] @relation("PersonOwner")
|
|
|
|
|
ownedCompanies Company[] @relation("CompanyOwner")
|
2026-08-30 09:42:07 +03:30
|
|
|
ownedProjectCards ProjectCard[] @relation("ProjectCardOwner")
|
2026-08-29 21:06:30 +03:30
|
|
|
activities Activity[] @relation("ActivityAssignee")
|
|
|
|
|
notes Note[] @relation("NoteAuthor")
|
|
|
|
|
noteAttachments NoteAttachment[] @relation("NoteAttachmentUploader")
|
|
|
|
|
notifications Notification[]
|
|
|
|
|
salesGoals SalesGoal[] @relation("SalesGoalUser")
|
|
|
|
|
assignedTickets Ticket[] @relation("TicketAssignee")
|
|
|
|
|
reportedTickets Ticket[] @relation("TicketReporter")
|
|
|
|
|
ticketMessages TicketMessage[] @relation("TicketMessageAuthor")
|
2026-09-01 14:29:34 +03:30
|
|
|
confirmedMemories MemoryItem[] @relation("MemoryConfirmedBy")
|
2026-08-29 21:06:30 +03:30
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, email])
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Company {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
nationalId String?
|
|
|
|
|
phone String?
|
|
|
|
|
email String?
|
|
|
|
|
website String?
|
|
|
|
|
address String?
|
|
|
|
|
notes String?
|
|
|
|
|
customFields Json @default("{}")
|
|
|
|
|
people Person[]
|
|
|
|
|
deals Deal[]
|
|
|
|
|
activities Activity[]
|
|
|
|
|
smartNotes Note[]
|
|
|
|
|
quotes Quote[]
|
|
|
|
|
invoices Invoice[]
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("CompanyOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
tickets Ticket[]
|
2026-08-30 09:42:07 +03:30
|
|
|
projectCards ProjectCard[]
|
2026-08-29 21:06:30 +03:30
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([organizationId, name])
|
|
|
|
|
@@index([organizationId, email])
|
|
|
|
|
@@index([organizationId, phone])
|
|
|
|
|
@@index([ownerId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Person {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
firstName String
|
|
|
|
|
lastName String
|
|
|
|
|
email String?
|
|
|
|
|
phone String?
|
|
|
|
|
mobile String?
|
|
|
|
|
position String?
|
|
|
|
|
notes String?
|
|
|
|
|
customFields Json @default("{}")
|
2026-08-30 09:42:07 +03:30
|
|
|
loyaltyPoints Int @default(0)
|
|
|
|
|
loyaltyTierId String?
|
|
|
|
|
loyaltyTier LoyaltyTier? @relation(fields: [loyaltyTierId], references: [id], onDelete: SetNull)
|
2026-08-29 21:06:30 +03:30
|
|
|
deals Deal[]
|
|
|
|
|
activities Activity[]
|
|
|
|
|
smartNotes Note[]
|
|
|
|
|
quotes Quote[]
|
|
|
|
|
invoices Invoice[]
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("PersonOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
tickets Ticket[]
|
2026-08-30 09:42:07 +03:30
|
|
|
projectCards ProjectCard[]
|
2026-09-01 14:29:34 +03:30
|
|
|
memoryItems MemoryItem[]
|
2026-08-29 21:06:30 +03:30
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([organizationId, email])
|
|
|
|
|
@@index([organizationId, mobile])
|
|
|
|
|
@@index([organizationId, lastName, firstName])
|
2026-08-30 09:42:07 +03:30
|
|
|
@@index([organizationId, loyaltyPoints])
|
2026-08-29 21:06:30 +03:30
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([ownerId])
|
2026-08-30 09:42:07 +03:30
|
|
|
@@index([loyaltyTierId])
|
2026-08-29 21:06:30 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Pipeline {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
isDefault Boolean @default(false)
|
|
|
|
|
stages PipelineStage[]
|
|
|
|
|
deals Deal[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([organizationId, isDefault])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model PipelineStage {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
pipelineId String
|
|
|
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
position Int
|
|
|
|
|
isWon Boolean @default(false)
|
|
|
|
|
isLost Boolean @default(false)
|
|
|
|
|
deals Deal[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([pipelineId, position])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Deal {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
pipelineId String
|
|
|
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
|
|
|
stageId String
|
|
|
|
|
stage PipelineStage @relation(fields: [stageId], references: [id], onDelete: Restrict)
|
|
|
|
|
title String
|
|
|
|
|
amount Decimal? @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
status DealStatus @default(open)
|
|
|
|
|
source String?
|
|
|
|
|
lostReason String?
|
|
|
|
|
notes String?
|
|
|
|
|
tags String[] @default([])
|
|
|
|
|
isStale Boolean @default(false)
|
|
|
|
|
isRotten Boolean @default(false)
|
|
|
|
|
customFields Json @default("{}")
|
|
|
|
|
expectedCloseAt DateTime?
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("DealOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
activities Activity[]
|
|
|
|
|
smartNotes Note[]
|
|
|
|
|
lineItems DealLineItem[]
|
|
|
|
|
quotes Quote[]
|
|
|
|
|
invoices Invoice[]
|
|
|
|
|
tickets Ticket[]
|
2026-08-30 09:42:07 +03:30
|
|
|
projectCards ProjectCard[]
|
2026-08-29 21:06:30 +03:30
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([pipelineId, stageId])
|
|
|
|
|
@@index([stageId, position])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([ownerId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Activity {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
type ActivityType @default(task)
|
|
|
|
|
status ActivityStatus @default(open)
|
|
|
|
|
title String
|
|
|
|
|
description String?
|
|
|
|
|
dueAt DateTime?
|
|
|
|
|
completedAt DateTime?
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
assigneeId String?
|
|
|
|
|
assignee User? @relation("ActivityAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, status, dueAt])
|
|
|
|
|
@@index([organizationId, assigneeId])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Note {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
title String?
|
|
|
|
|
body String
|
|
|
|
|
noteType String @default("general")
|
|
|
|
|
pinned Boolean @default(false)
|
|
|
|
|
color String? @default("default")
|
|
|
|
|
tags String[] @default([])
|
|
|
|
|
reminderAt DateTime?
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
authorId String?
|
|
|
|
|
author User? @relation("NoteAuthor", fields: [authorId], references: [id], onDelete: SetNull)
|
|
|
|
|
attachments NoteAttachment[]
|
2026-09-01 14:29:34 +03:30
|
|
|
aiSuggestion NoteAiSuggestion?
|
2026-08-29 21:06:30 +03:30
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, pinned, updatedAt])
|
|
|
|
|
@@index([organizationId, noteType, updatedAt])
|
|
|
|
|
@@index([organizationId, reminderAt])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
@@index([authorId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model NoteAttachment {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
noteId String
|
|
|
|
|
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
|
|
|
|
fileName String
|
|
|
|
|
mimeType String
|
|
|
|
|
sizeBytes Int
|
|
|
|
|
storageKey String
|
|
|
|
|
uploadedById String?
|
|
|
|
|
uploadedBy User? @relation("NoteAttachmentUploader", fields: [uploadedById], references: [id], onDelete: SetNull)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@index([noteId, createdAt])
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([uploadedById])
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-01 14:29:34 +03:30
|
|
|
model NoteAiSuggestion {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
noteId String @unique
|
|
|
|
|
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
|
|
|
|
status NoteAiSuggestionStatus @default(pending)
|
|
|
|
|
payload Json?
|
|
|
|
|
errorMessage String?
|
|
|
|
|
analyzedAt DateTime?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, status])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model MemoryItem {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
personId String
|
|
|
|
|
person Person @relation(fields: [personId], references: [id], onDelete: Cascade)
|
|
|
|
|
content String
|
|
|
|
|
sourceType MemorySourceType @default(manual)
|
|
|
|
|
sourceId String?
|
|
|
|
|
confirmedById String?
|
|
|
|
|
confirmedBy User? @relation("MemoryConfirmedBy", fields: [confirmedById], references: [id], onDelete: SetNull)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, personId, updatedAt])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([confirmedById])
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-29 21:06:30 +03:30
|
|
|
model CustomFieldDefinition {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
entityType CustomFieldEntity
|
|
|
|
|
key String
|
|
|
|
|
label String
|
|
|
|
|
fieldType CustomFieldType @default(text)
|
|
|
|
|
options String[] @default([])
|
|
|
|
|
required Boolean @default(false)
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
isActive Boolean @default(true)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, entityType, key])
|
|
|
|
|
@@index([organizationId, entityType, position])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Product {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
sku String?
|
|
|
|
|
description String?
|
|
|
|
|
unitPrice Decimal? @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
isActive Boolean @default(true)
|
|
|
|
|
lineItems DealLineItem[]
|
|
|
|
|
quoteLineItems QuoteLineItem[]
|
|
|
|
|
invoiceLineItems InvoiceLineItem[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, name])
|
|
|
|
|
@@index([organizationId, isActive])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model DealLineItem {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
dealId String
|
|
|
|
|
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
|
|
|
|
|
productId String?
|
|
|
|
|
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
|
|
|
|
name String
|
|
|
|
|
quantity Decimal @default(1) @db.Decimal(18, 2)
|
|
|
|
|
unitPrice Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([dealId, position])
|
|
|
|
|
@@index([productId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Notification {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
userId String
|
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
type String
|
|
|
|
|
title String
|
|
|
|
|
body String?
|
|
|
|
|
link String?
|
|
|
|
|
entityType String?
|
|
|
|
|
entityId String?
|
|
|
|
|
readAt DateTime?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@index([userId, readAt, createdAt])
|
|
|
|
|
@@index([organizationId, createdAt])
|
|
|
|
|
@@index([userId, type, entityId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model LeadForm {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
publicToken String @unique @default(cuid())
|
|
|
|
|
isActive Boolean @default(true)
|
|
|
|
|
createPerson Boolean @default(true)
|
|
|
|
|
createDeal Boolean @default(true)
|
|
|
|
|
pipelineId String?
|
|
|
|
|
source String?
|
|
|
|
|
thankYouMessage String?
|
|
|
|
|
redirectUrl String?
|
|
|
|
|
assigneeIds String[] @default([])
|
|
|
|
|
roundRobinIndex Int @default(0)
|
|
|
|
|
fields LeadFormField[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, updatedAt])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model LeadFormField {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
formId String
|
|
|
|
|
form LeadForm @relation(fields: [formId], references: [id], onDelete: Cascade)
|
|
|
|
|
key String
|
|
|
|
|
label String
|
|
|
|
|
fieldType String @default("text")
|
|
|
|
|
required Boolean @default(false)
|
|
|
|
|
mapTo String
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
|
|
|
|
|
@@unique([formId, key])
|
|
|
|
|
@@index([formId, position])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Quote {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
number String
|
|
|
|
|
title String
|
|
|
|
|
status QuoteStatus @default(draft)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
notes String?
|
|
|
|
|
validUntil DateTime?
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("QuoteOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
lineItems QuoteLineItem[]
|
|
|
|
|
invoices Invoice[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, number])
|
|
|
|
|
@@index([organizationId, status, updatedAt])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
@@index([ownerId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model QuoteLineItem {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
quoteId String
|
|
|
|
|
quote Quote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
|
|
|
|
|
productId String?
|
|
|
|
|
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
|
|
|
|
name String
|
|
|
|
|
quantity Decimal @default(1) @db.Decimal(18, 2)
|
|
|
|
|
unitPrice Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([quoteId, position])
|
|
|
|
|
@@index([productId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Invoice {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
number String
|
|
|
|
|
title String
|
|
|
|
|
status InvoiceStatus @default(draft)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
notes String?
|
|
|
|
|
issuedAt DateTime?
|
|
|
|
|
dueDate DateTime?
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
quoteId String?
|
|
|
|
|
quote Quote? @relation(fields: [quoteId], references: [id], onDelete: SetNull)
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("InvoiceOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
lineItems InvoiceLineItem[]
|
|
|
|
|
payments Payment[]
|
|
|
|
|
installments InvoiceInstallment[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, number])
|
|
|
|
|
@@index([organizationId, status, updatedAt])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
@@index([quoteId])
|
|
|
|
|
@@index([ownerId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model InvoiceLineItem {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
invoiceId String
|
|
|
|
|
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
|
|
|
productId String?
|
|
|
|
|
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
|
|
|
|
name String
|
|
|
|
|
quantity Decimal @default(1) @db.Decimal(18, 2)
|
|
|
|
|
unitPrice Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([invoiceId, position])
|
|
|
|
|
@@index([productId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Payment {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
invoiceId String
|
|
|
|
|
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
|
|
|
amount Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
method PaymentMethod @default(transfer)
|
|
|
|
|
paidAt DateTime @default(now())
|
|
|
|
|
notes String?
|
|
|
|
|
installmentId String? @unique
|
|
|
|
|
installment InvoiceInstallment? @relation(fields: [installmentId], references: [id], onDelete: SetNull)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([invoiceId, paidAt])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model InvoiceInstallment {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
invoiceId String
|
|
|
|
|
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
dueDate DateTime
|
|
|
|
|
amount Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
status InstallmentStatus @default(pending)
|
|
|
|
|
paidAt DateTime?
|
|
|
|
|
payment Payment?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([invoiceId, position])
|
|
|
|
|
@@index([invoiceId, dueDate])
|
|
|
|
|
@@index([status, dueDate])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model SalesGoal {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
/// null = هدف سازمانی / تیمی
|
|
|
|
|
userId String?
|
|
|
|
|
user User? @relation("SalesGoalUser", fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
|
title String
|
|
|
|
|
periodStart DateTime
|
|
|
|
|
periodEnd DateTime
|
|
|
|
|
targetAmount Decimal @db.Decimal(18, 2)
|
|
|
|
|
currency String @default("IRR")
|
|
|
|
|
notes String?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, periodStart, periodEnd])
|
|
|
|
|
@@index([userId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model ExchangeRate {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
/// ارز مبدأ؛ ۱ واحد این ارز = rateToBase واحد ارز پایه
|
|
|
|
|
currency String
|
|
|
|
|
rateToBase Decimal @db.Decimal(24, 6)
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, currency])
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model Ticket {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
number String
|
|
|
|
|
subject String
|
|
|
|
|
description String?
|
|
|
|
|
status TicketStatus @default(open)
|
|
|
|
|
priority TicketPriority @default(normal)
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
assigneeId String?
|
|
|
|
|
assignee User? @relation("TicketAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
|
|
|
|
|
reporterId String?
|
|
|
|
|
reporter User? @relation("TicketReporter", fields: [reporterId], references: [id], onDelete: SetNull)
|
|
|
|
|
resolvedAt DateTime?
|
|
|
|
|
/// مهلت پاسخ اول بر اساس اولویت
|
|
|
|
|
slaDueAt DateTime?
|
|
|
|
|
firstRespondedAt DateTime?
|
|
|
|
|
csatScore Int?
|
|
|
|
|
csatComment String?
|
|
|
|
|
csatAt DateTime?
|
|
|
|
|
messages TicketMessage[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([organizationId, number])
|
|
|
|
|
@@index([organizationId, status, updatedAt])
|
|
|
|
|
@@index([organizationId, slaDueAt])
|
|
|
|
|
@@index([assigneeId])
|
|
|
|
|
@@index([reporterId])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model TicketMessage {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
ticketId String
|
|
|
|
|
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
|
|
|
|
authorId String?
|
|
|
|
|
author User? @relation("TicketMessageAuthor", fields: [authorId], references: [id], onDelete: SetNull)
|
|
|
|
|
body String
|
|
|
|
|
isInternal Boolean @default(false)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@index([ticketId, createdAt])
|
|
|
|
|
@@index([authorId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model FaqArticle {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
question String
|
|
|
|
|
answer String
|
|
|
|
|
category String?
|
|
|
|
|
isPublished Boolean @default(true)
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, isPublished, position])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// کد یکبارمصرف ورود پرتال مشتری (موبایل)
|
|
|
|
|
model PortalOtp {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
mobile String
|
|
|
|
|
code String
|
|
|
|
|
expiresAt DateTime
|
|
|
|
|
consumedAt DateTime?
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, mobile, createdAt])
|
|
|
|
|
@@index([expiresAt])
|
|
|
|
|
}
|
2026-08-30 09:42:07 +03:30
|
|
|
|
|
|
|
|
/// برد کانبان برای کارهای داخلی / پسازفروش (جدا از کاریز فروش)
|
|
|
|
|
model ProjectBoard {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
isDefault Boolean @default(false)
|
|
|
|
|
stages ProjectBoardStage[]
|
|
|
|
|
cards ProjectCard[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([organizationId, isDefault])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model ProjectBoardStage {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
boardId String
|
|
|
|
|
board ProjectBoard @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
position Int
|
|
|
|
|
cards ProjectCard[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([boardId, position])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model ProjectCard {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
boardId String
|
|
|
|
|
board ProjectBoard @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
|
|
|
|
stageId String
|
|
|
|
|
stage ProjectBoardStage @relation(fields: [stageId], references: [id], onDelete: Restrict)
|
|
|
|
|
title String
|
|
|
|
|
notes String?
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
personId String?
|
|
|
|
|
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
|
|
|
|
companyId String?
|
|
|
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
|
|
|
dealId String?
|
|
|
|
|
deal Deal? @relation(fields: [dealId], references: [id], onDelete: SetNull)
|
|
|
|
|
ownerId String?
|
|
|
|
|
owner User? @relation("ProjectCardOwner", fields: [ownerId], references: [id], onDelete: SetNull)
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId])
|
|
|
|
|
@@index([boardId, stageId])
|
|
|
|
|
@@index([stageId, position])
|
|
|
|
|
@@index([personId])
|
|
|
|
|
@@index([companyId])
|
|
|
|
|
@@index([dealId])
|
|
|
|
|
@@index([ownerId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model LoyaltyTier {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
minPoints Int @default(0)
|
|
|
|
|
position Int @default(0)
|
|
|
|
|
color String?
|
|
|
|
|
people Person[]
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, position])
|
|
|
|
|
@@index([organizationId, minPoints])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model AutomationRule {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
organizationId String
|
|
|
|
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
|
|
|
name String
|
|
|
|
|
isActive Boolean @default(true)
|
|
|
|
|
trigger AutomationTrigger
|
|
|
|
|
action AutomationAction
|
|
|
|
|
/// عنوان فعالیت/اعلان، assigneeId، notifyUserId، points، activityType
|
|
|
|
|
config Json @default("{}")
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@index([organizationId, isActive, trigger])
|
|
|
|
|
}
|