Implement sales CRM workflow foundation

This commit is contained in:
Admin
2026-05-10 20:54:01 +05:00
parent dad4ab115a
commit 8577d97356
22 changed files with 5625 additions and 242 deletions
+101 -3
View File
@@ -38,9 +38,10 @@ SalesDocumentStatus = Literal["draft", "sent", "under_review", "confirmed", "sig
SalesInvoiceStatus = Literal["draft", "issued", "sent", "partially_paid", "paid", "overdue", "canceled"]
SalesPaymentStatus = Literal["pending", "success", "failed", "canceled", "partial"]
SalesEscalationSeverity = Literal["low", "medium", "high", "critical"]
SalesEscalationStatus = Literal["open", "in_progress", "resolved"]
SalesEscalationStatus = Literal["open", "assigned", "in_progress", "resolved", "canceled"]
SalesAutomationStatus = Literal["pending", "running", "completed", "failed", "canceled"]
SalesPipelineStageCategory = Literal["entry", "communication", "commercial", "paperwork", "finance", "closing"]
SalesSwitchChannel = Literal["text", "voice"]
class SalesStageRefOut(BaseModel):
@@ -222,7 +223,11 @@ class SalesDealUpdate(BaseModel):
class SalesDealStageChangeIn(BaseModel):
stage_id: str | None = Field(default=None, min_length=2)
stage_code: str | None = Field(default=None, min_length=2)
target_stage_id: str | None = Field(default=None, min_length=2)
target_stage_code: str | None = Field(default=None, min_length=2)
reason: str | None = None
metadata: dict = Field(default_factory=dict)
force: bool = False
class SalesDealScenarioIn(BaseModel):
@@ -295,8 +300,16 @@ class SalesCommunicationSummaryIn(BaseModel):
class SalesCommunicationSwitchChannelIn(BaseModel):
to_channel: SalesPreferredChannel
reason_for_channel_switch: str = Field(min_length=3)
to_channel: SalesSwitchChannel
reason_code: str = "human_decision"
reason_text: str | None = None
reason_for_channel_switch: str | None = None
create_session: bool = False
scheduled_at: str | None = None
metadata: dict = Field(default_factory=dict)
source_type: str | None = None
source_id: str | None = None
recommended_by_task_id: str | None = None
class SalesCommunicationBindExternalIn(BaseModel):
@@ -315,6 +328,7 @@ class SalesCommunicationOut(BaseModel):
lead_id: str | None = None
customer_id: str | None = None
channel_type: SalesChannelType
channel_provider: str | None = None
direction: SalesDirection
agent_type: SalesAgentType
started_at: str
@@ -580,7 +594,11 @@ class SalesPaymentWebhookIn(BaseModel):
deal_id: str
invoice_id: str | None = None
payment_provider: str = "manual"
provider_account_id: str | None = None
external_event_id: str | None = None
external_payment_id: str | None = None
event_type: str | None = None
provider_status: str | None = None
amount: float = Field(ge=0)
currency: str = "KZT"
status: SalesPaymentStatus = "success"
@@ -618,6 +636,10 @@ class SalesEscalationCreateIn(BaseModel):
reason: str = Field(min_length=3)
severity: SalesEscalationSeverity = "medium"
assigned_to_user_id: str | None = None
source_channel: str | None = None
source_communication_session_id: str | None = None
source_automation_task_id: str | None = None
sla_due_at: str | None = None
class SalesEscalationOut(BaseModel):
@@ -628,8 +650,35 @@ class SalesEscalationOut(BaseModel):
severity: SalesEscalationSeverity
status: SalesEscalationStatus
assigned_to_user_id: str | None = None
assigned_at: str | None = None
started_at: str | None = None
created_at: str
resolved_at: str | None = None
canceled_at: str | None = None
resolution_code: str | None = None
resolution_summary: str | None = None
sla_due_at: str | None = None
source_channel: str | None = None
source_communication_session_id: str | None = None
source_automation_task_id: str | None = None
updated_at: str | None = None
class SalesEscalationAssignIn(BaseModel):
assigned_to_user_id: str = Field(min_length=1)
class SalesEscalationResolveIn(BaseModel):
resolution_code: str = Field(min_length=2)
resolution_summary: str | None = None
target_stage_code: str | None = None
metadata: dict = Field(default_factory=dict)
class SalesEscalationCancelIn(BaseModel):
resolution_code: str = "canceled"
resolution_summary: str | None = None
metadata: dict = Field(default_factory=dict)
class SalesAutomationTaskOut(BaseModel):
@@ -640,6 +689,11 @@ class SalesAutomationTaskOut(BaseModel):
run_at: str
status: SalesAutomationStatus
retry_count: int = 0
max_retries: int = 3
locked_at: str | None = None
locked_by: str | None = None
completed_at: str | None = None
failed_at: str | None = None
last_error: str | None = None
created_at: str
updated_at: str
@@ -662,10 +716,50 @@ class SalesChannelSwitchOut(BaseModel):
switch_id: str
deal_id: str
communication_id: str | None = None
communication_session_id: str | None = None
previous_communication_session_id: str | None = None
new_communication_session_id: str | None = None
from_channel: str
to_channel: str
reason_code: str
reason_text: str | None = None
reason_for_channel_switch: str
initiated_by_type: str
initiated_by_id: str | None = None
source_type: str | None = None
source_id: str | None = None
recommended_by_task_id: str | None = None
switched_at: str
created_at: str
new_communication: SalesCommunicationOut | None = None
class SalesNoteCreateIn(BaseModel):
note_type: str = "general"
content: str = Field(min_length=1)
source_type: str | None = None
source_id: str | None = None
class SalesNoteUpdateIn(BaseModel):
note_type: str | None = None
content: str | None = Field(default=None, min_length=1)
source_type: str | None = None
source_id: str | None = None
class SalesNoteOut(BaseModel):
note_id: str
deal_id: str
author_type: str
author_id: str | None = None
note_type: str
content: str
source_type: str | None = None
source_id: str | None = None
created_at: str
updated_at: str | None = None
archived_at: str | None = None
class SalesTimelineEventOut(BaseModel):
@@ -684,6 +778,8 @@ class SalesWorkspaceOut(BaseModel):
communications: list[SalesCommunicationOut] = Field(default_factory=list)
messages: list[SalesMessageOut] = Field(default_factory=list)
calls: list[SalesCallOut] = Field(default_factory=list)
transcripts: list[SalesTranscriptOut] = Field(default_factory=list)
notes: list[SalesNoteOut] = Field(default_factory=list)
offers: list[SalesOfferOut] = Field(default_factory=list)
conditions: list[SalesConditionOut] = Field(default_factory=list)
counterparty: SalesCounterpartyOut | None = None
@@ -691,9 +787,11 @@ class SalesWorkspaceOut(BaseModel):
invoices: list[SalesInvoiceOut] = Field(default_factory=list)
payments: list[SalesPaymentOut] = Field(default_factory=list)
escalations: list[SalesEscalationOut] = Field(default_factory=list)
active_escalation: SalesEscalationOut | None = None
tasks: list[SalesAutomationTaskOut] = Field(default_factory=list)
stage_history: list[SalesStageHistoryOut] = Field(default_factory=list)
channel_switches: list[SalesChannelSwitchOut] = Field(default_factory=list)
recommended_channel_switch: dict | None = None
timeline: list[SalesTimelineEventOut] = Field(default_factory=list)