This commit is contained in:
2026-10-10 10:35:56 +03:30
parent 7779101fb4
commit 7481ac5243
17 changed files with 3505 additions and 41 deletions
@@ -0,0 +1,144 @@
-- CreateEnum
CREATE TYPE "SalesPipelineStage" AS ENUM ('negotiation', 'awaiting_catalog', 'awaiting_price', 'ready_to_order');
-- CreateEnum
CREATE TYPE "OpportunityOutcome" AS ENUM ('open', 'won', 'lost');
-- CreateEnum
CREATE TYPE "LostReason" AS ENUM ('price', 'product', 'supply_time', 'customer_decision', 'other');
-- CreateEnum
CREATE TYPE "TimelineEventSource" AS ENUM ('manual', 'system');
-- CreateEnum
CREATE TYPE "TimelineEventKind" AS ENUM ('meeting', 'call', 'note', 'reminder', 'next_action', 'order_created', 'price_announced', 'price_confirmed', 'catalog_requested');
-- CreateEnum
CREATE TYPE "AssignmentRequestStatus" AS ENUM ('pending', 'approved', 'rejected');
-- CreateTable
CREATE TABLE "SalesOpportunity" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"stage" "SalesPipelineStage" NOT NULL DEFAULT 'negotiation',
"outcome" "OpportunityOutcome" NOT NULL DEFAULT 'open',
"lostReason" "LostReason",
"lostNote" TEXT,
"lostAt" TIMESTAMP(3),
"wonOrderId" TEXT,
"wonAt" TIMESTAMP(3),
"assignedAgentId" TEXT,
"ownerAdminId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "SalesOpportunity_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "CustomerTimelineEvent" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"kind" "TimelineEventKind" NOT NULL,
"source" "TimelineEventSource" NOT NULL DEFAULT 'manual',
"title" TEXT NOT NULL,
"body" TEXT,
"occurredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"actorAdminId" TEXT,
"actorCustomerId" TEXT,
"relatedOrderId" TEXT,
"relatedMeetingId" TEXT,
"relatedActionId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "CustomerTimelineEvent_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "CrmNextAction" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"opportunityId" TEXT,
"title" TEXT NOT NULL,
"description" TEXT,
"dueAt" TIMESTAMP(3) NOT NULL,
"completed" BOOLEAN NOT NULL DEFAULT false,
"completedAt" TIMESTAMP(3),
"assigneeAdminId" TEXT,
"assigneeAgentId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "CrmNextAction_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "CustomerAssignmentRequest" (
"id" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"fromAgentId" TEXT,
"toAgentId" TEXT NOT NULL,
"requestedByAgentId" TEXT NOT NULL,
"status" "AssignmentRequestStatus" NOT NULL DEFAULT 'pending',
"reviewNote" TEXT,
"reviewedByAdminId" TEXT,
"reviewedAt" TIMESTAMP(3),
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "CustomerAssignmentRequest_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "SalesOpportunity_customerId_idx" ON "SalesOpportunity"("customerId");
-- CreateIndex
CREATE INDEX "SalesOpportunity_stage_outcome_idx" ON "SalesOpportunity"("stage", "outcome");
-- CreateIndex
CREATE INDEX "SalesOpportunity_assignedAgentId_idx" ON "SalesOpportunity"("assignedAgentId");
-- CreateIndex
CREATE INDEX "CustomerTimelineEvent_customerId_occurredAt_idx" ON "CustomerTimelineEvent"("customerId", "occurredAt");
-- CreateIndex
CREATE INDEX "CrmNextAction_customerId_completed_idx" ON "CrmNextAction"("customerId", "completed");
-- CreateIndex
CREATE INDEX "CrmNextAction_dueAt_idx" ON "CrmNextAction"("dueAt");
-- CreateIndex
CREATE INDEX "CustomerAssignmentRequest_status_idx" ON "CustomerAssignmentRequest"("status");
-- CreateIndex
CREATE INDEX "CustomerAssignmentRequest_customerId_idx" ON "CustomerAssignmentRequest"("customerId");
-- AddForeignKey
ALTER TABLE "SalesOpportunity" ADD CONSTRAINT "SalesOpportunity_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "SalesOpportunity" ADD CONSTRAINT "SalesOpportunity_assignedAgentId_fkey" FOREIGN KEY ("assignedAgentId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "SalesOpportunity" ADD CONSTRAINT "SalesOpportunity_wonOrderId_fkey" FOREIGN KEY ("wonOrderId") REFERENCES "Order"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerTimelineEvent" ADD CONSTRAINT "CustomerTimelineEvent_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CrmNextAction" ADD CONSTRAINT "CrmNextAction_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CrmNextAction" ADD CONSTRAINT "CrmNextAction_opportunityId_fkey" FOREIGN KEY ("opportunityId") REFERENCES "SalesOpportunity"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerAssignmentRequest" ADD CONSTRAINT "CustomerAssignmentRequest_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerAssignmentRequest" ADD CONSTRAINT "CustomerAssignmentRequest_fromAgentId_fkey" FOREIGN KEY ("fromAgentId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerAssignmentRequest" ADD CONSTRAINT "CustomerAssignmentRequest_toAgentId_fkey" FOREIGN KEY ("toAgentId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "CustomerAssignmentRequest" ADD CONSTRAINT "CustomerAssignmentRequest_requestedByAgentId_fkey" FOREIGN KEY ("requestedByAgentId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+164 -23
View File
@@ -85,6 +85,50 @@ enum InteractionType {
note
}
enum SalesPipelineStage {
negotiation
awaiting_catalog
awaiting_price
ready_to_order
}
enum OpportunityOutcome {
open
won
lost
}
enum LostReason {
price
product
supply_time
customer_decision
other
}
enum TimelineEventSource {
manual
system
}
enum TimelineEventKind {
meeting
call
note
reminder
next_action
order_created
price_announced
price_confirmed
catalog_requested
}
enum AssignmentRequestStatus {
pending
approved
rejected
}
enum ProductSeason {
summer
winter
@@ -240,21 +284,29 @@ model Customer {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
levelDef CustomerLevelDef? @relation(fields: [levelDefId], references: [id], onDelete: SetNull)
assignedAgent Customer? @relation("AgentCustomers", fields: [assignedAgentId], references: [id], onDelete: SetNull)
agentCustomers Customer[] @relation("AgentCustomers")
carts Cart[]
orders Order[]
notifications CustomerNotification[]
meetings MeetingInteraction[] @relation("MeetingCustomer")
meetingsAsAgent MeetingInteraction[] @relation("MeetingAgent")
reminders Reminder[] @relation("ReminderOwner")
remindersAbout Reminder[] @relation("ReminderCustomer")
favorites ProductFavorite[]
catalogRequests CatalogRequest[]
productSuggestions ProductSuggestion[]
addresses CustomerAddress[]
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
levelDef CustomerLevelDef? @relation(fields: [levelDefId], references: [id], onDelete: SetNull)
assignedAgent Customer? @relation("AgentCustomers", fields: [assignedAgentId], references: [id], onDelete: SetNull)
agentCustomers Customer[] @relation("AgentCustomers")
carts Cart[]
orders Order[]
notifications CustomerNotification[]
meetings MeetingInteraction[] @relation("MeetingCustomer")
meetingsAsAgent MeetingInteraction[] @relation("MeetingAgent")
reminders Reminder[] @relation("ReminderOwner")
remindersAbout Reminder[] @relation("ReminderCustomer")
favorites ProductFavorite[]
catalogRequests CatalogRequest[]
productSuggestions ProductSuggestion[]
addresses CustomerAddress[]
salesOpportunities SalesOpportunity[]
timelineEvents CustomerTimelineEvent[]
crmNextActions CrmNextAction[]
assignmentRequests CustomerAssignmentRequest[] @relation("AssignmentCustomer")
assignmentFrom CustomerAssignmentRequest[] @relation("AssignmentFromAgent")
assignmentTo CustomerAssignmentRequest[] @relation("AssignmentToAgent")
assignmentRequested CustomerAssignmentRequest[] @relation("AssignmentRequestedBy")
opportunitiesOwned SalesOpportunity[] @relation("OpportunityAgent")
@@index([companyId])
@@index([appRole])
@@ -363,14 +415,15 @@ model Order {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user Customer @relation(fields: [userId], references: [id], onDelete: Restrict)
company Company @relation(fields: [companyId], references: [id], onDelete: Restrict)
items OrderItem[]
checks Check[]
cashReceipt CashPaymentReceipt?
shipment Shipment?
statusHistory OrderStatusHistory[]
notifications CustomerNotification[]
user Customer @relation(fields: [userId], references: [id], onDelete: Restrict)
company Company @relation(fields: [companyId], references: [id], onDelete: Restrict)
items OrderItem[]
checks Check[]
cashReceipt CashPaymentReceipt?
shipment Shipment?
statusHistory OrderStatusHistory[]
notifications CustomerNotification[]
wonOpportunities SalesOpportunity[]
@@index([userId])
@@index([companyId])
@@ -620,6 +673,94 @@ model Reminder {
@@index([date])
}
model SalesOpportunity {
id String @id @default(cuid())
customerId String
stage SalesPipelineStage @default(negotiation)
outcome OpportunityOutcome @default(open)
lostReason LostReason?
lostNote String?
lostAt DateTime?
wonOrderId String?
wonAt DateTime?
assignedAgentId String?
ownerAdminId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
assignedAgent Customer? @relation("OpportunityAgent", fields: [assignedAgentId], references: [id], onDelete: SetNull)
wonOrder Order? @relation(fields: [wonOrderId], references: [id], onDelete: SetNull)
nextActions CrmNextAction[]
@@index([customerId])
@@index([stage, outcome])
@@index([assignedAgentId])
}
model CustomerTimelineEvent {
id String @id @default(cuid())
customerId String
kind TimelineEventKind
source TimelineEventSource @default(manual)
title String
body String?
occurredAt DateTime @default(now())
actorAdminId String?
actorCustomerId String?
relatedOrderId String?
relatedMeetingId String?
relatedActionId String?
createdAt DateTime @default(now())
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
@@index([customerId, occurredAt])
}
model CrmNextAction {
id String @id @default(cuid())
customerId String
opportunityId String?
title String
description String?
dueAt DateTime
completed Boolean @default(false)
completedAt DateTime?
assigneeAdminId String?
assigneeAgentId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
opportunity SalesOpportunity? @relation(fields: [opportunityId], references: [id], onDelete: SetNull)
@@index([customerId, completed])
@@index([dueAt])
}
model CustomerAssignmentRequest {
id String @id @default(cuid())
customerId String
fromAgentId String?
toAgentId String
requestedByAgentId String
status AssignmentRequestStatus @default(pending)
reviewNote String?
reviewedByAdminId String?
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation("AssignmentCustomer", fields: [customerId], references: [id], onDelete: Cascade)
fromAgent Customer? @relation("AssignmentFromAgent", fields: [fromAgentId], references: [id], onDelete: SetNull)
toAgent Customer @relation("AssignmentToAgent", fields: [toAgentId], references: [id], onDelete: Cascade)
requestedByAgent Customer @relation("AssignmentRequestedBy", fields: [requestedByAgentId], references: [id], onDelete: Cascade)
@@index([status])
@@index([customerId])
}
model ProductFavorite {
id String @id @default(cuid())
customerId String
+102 -3
View File
File diff suppressed because one or more lines are too long
+1508 -10
View File
File diff suppressed because one or more lines are too long