feature: Added Transactions and major Order System Overhaul

This commit is contained in:
2026-03-25 10:32:47 +02:00
parent 2d57c75d2f
commit b2d1e2bdc4
8 changed files with 1089 additions and 123 deletions

View File

@@ -1,5 +1,5 @@
from enum import Enum
from typing import List, Optional
from typing import Any, Dict, List, Optional
from pydantic import BaseModel
@@ -129,6 +129,50 @@ class CustomerLocation(BaseModel):
country: Optional[str] = None
# ── New customer status models ────────────────────────────────────────────────
class TechnicalIssue(BaseModel):
active: bool = True
opened_date: str # ISO string
resolved_date: Optional[str] = None
note: str
opened_by: str
resolved_by: Optional[str] = None
class InstallSupportEntry(BaseModel):
active: bool = True
opened_date: str # ISO string
resolved_date: Optional[str] = None
note: str
opened_by: str
resolved_by: Optional[str] = None
class TransactionEntry(BaseModel):
date: str # ISO string
flow: str # "invoice" | "payment" | "refund" | "credit"
payment_type: Optional[str] = None # "cash" | "bank_transfer" | "card" | "paypal" — null for invoices
category: str # "full_payment" | "advance" | "installment"
amount: float
currency: str = "EUR"
invoice_ref: Optional[str] = None
order_ref: Optional[str] = None
recorded_by: str
note: str = ""
# Lightweight summary stored on customer doc for fast CustomerList expanded view
class CrmSummary(BaseModel):
active_order_status: Optional[str] = None
active_order_status_date: Optional[str] = None
active_order_title: Optional[str] = None
active_issues_count: int = 0
latest_issue_date: Optional[str] = None
active_support_count: int = 0
latest_support_date: Optional[str] = None
class CustomerCreate(BaseModel):
title: Optional[str] = None
name: str
@@ -143,9 +187,12 @@ class CustomerCreate(BaseModel):
owned_items: List[OwnedItem] = []
linked_user_ids: List[str] = []
nextcloud_folder: Optional[str] = None
folder_id: Optional[str] = None # Human-readable Nextcloud folder name, e.g. "saint-john-corfu"
negotiating: bool = False
has_problem: bool = False
folder_id: Optional[str] = None
relationship_status: str = "lead"
technical_issues: List[Dict[str, Any]] = []
install_support: List[Dict[str, Any]] = []
transaction_history: List[Dict[str, Any]] = []
crm_summary: Optional[Dict[str, Any]] = None
class CustomerUpdate(BaseModel):
@@ -162,8 +209,7 @@ class CustomerUpdate(BaseModel):
owned_items: Optional[List[OwnedItem]] = None
linked_user_ids: Optional[List[str]] = None
nextcloud_folder: Optional[str] = None
negotiating: Optional[bool] = None
has_problem: Optional[bool] = None
relationship_status: Optional[str] = None
# folder_id intentionally excluded from update — set once at creation
@@ -181,18 +227,34 @@ class CustomerListResponse(BaseModel):
# ── Orders ───────────────────────────────────────────────────────────────────
class OrderStatus(str, Enum):
draft = "draft"
confirmed = "confirmed"
in_production = "in_production"
negotiating = "negotiating"
awaiting_quotation = "awaiting_quotation"
awaiting_customer_confirmation = "awaiting_customer_confirmation"
awaiting_fulfilment = "awaiting_fulfilment"
awaiting_payment = "awaiting_payment"
manufacturing = "manufacturing"
shipped = "shipped"
delivered = "delivered"
cancelled = "cancelled"
installed = "installed"
declined = "declined"
complete = "complete"
class PaymentStatus(str, Enum):
pending = "pending"
partial = "partial"
paid = "paid"
class OrderPaymentStatus(BaseModel):
required_amount: float = 0
received_amount: float = 0
balance_due: float = 0
advance_required: bool = False
advance_amount: Optional[float] = None
payment_complete: bool = False
class OrderTimelineEvent(BaseModel):
date: str # ISO string
type: str # "quote_request" | "quote_sent" | "quote_accepted" | "quote_declined"
# | "mfg_started" | "mfg_complete" | "order_shipped" | "installed"
# | "payment_received" | "invoice_sent" | "note"
note: str = ""
updated_by: str
class OrderDiscount(BaseModel):
@@ -223,29 +285,36 @@ class OrderItem(BaseModel):
class OrderCreate(BaseModel):
customer_id: str
order_number: Optional[str] = None
status: OrderStatus = OrderStatus.draft
title: Optional[str] = None
created_by: Optional[str] = None
status: OrderStatus = OrderStatus.negotiating
status_updated_date: Optional[str] = None
status_updated_by: Optional[str] = None
items: List[OrderItem] = []
subtotal: float = 0
discount: Optional[OrderDiscount] = None
total_price: float = 0
currency: str = "EUR"
shipping: Optional[OrderShipping] = None
payment_status: PaymentStatus = PaymentStatus.pending
payment_status: Optional[Dict[str, Any]] = None
invoice_path: Optional[str] = None
notes: Optional[str] = None
timeline: List[Dict[str, Any]] = []
class OrderUpdate(BaseModel):
customer_id: Optional[str] = None
order_number: Optional[str] = None
title: Optional[str] = None
status: Optional[OrderStatus] = None
status_updated_date: Optional[str] = None
status_updated_by: Optional[str] = None
items: Optional[List[OrderItem]] = None
subtotal: Optional[float] = None
discount: Optional[OrderDiscount] = None
total_price: Optional[float] = None
currency: Optional[str] = None
shipping: Optional[OrderShipping] = None
payment_status: Optional[PaymentStatus] = None
payment_status: Optional[Dict[str, Any]] = None
invoice_path: Optional[str] = None
notes: Optional[str] = None