|
from pydantic import BaseModel, EmailStr, Field |
|
from typing import List, Optional, Union |
|
from datetime import datetime, date |
|
import enum |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserRole(str, enum.Enum): |
|
ADMIN = "ADMIN" |
|
USER = "USER" |
|
|
|
class TransactionType(str, enum.Enum): |
|
PURCHASE = "PURCHASE" |
|
SELL = "SELL" |
|
|
|
class TransactionStatus(str, enum.Enum): |
|
PENDING = "PENDING" |
|
PROCESSING = "PROCESSING" |
|
COMPLETED = "COMPLETED" |
|
CANCELLED = "CANCELLED" |
|
|
|
|
|
|
|
|
|
|
|
class CategoryBase(BaseModel): |
|
name: str |
|
|
|
class CategoryCreate(CategoryBase): |
|
pass |
|
|
|
class Category(CategoryBase): |
|
id: int |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
class ProductBase(BaseModel): |
|
productCode: str = Field(..., description="貨品編號,必須唯一") |
|
productName: str = Field(..., description="貨品名稱") |
|
unit: str = Field(..., description="單位(箱、盒等)") |
|
warehouse: Optional[str] = None |
|
unitWeight: Optional[float] = None |
|
barcode: Optional[str] = None |
|
category_id: int = Field(..., description="類別ID") |
|
|
|
class ProductCreate(ProductBase): |
|
pass |
|
|
|
|
|
class Product(ProductBase): |
|
id: int |
|
stock: int = Field(default=0, description="庫存數量") |
|
is_deleted: bool = Field(default=False, description="是否已刪除") |
|
deleted_at: Optional[datetime] = None |
|
deleted_by: Optional[int] = None |
|
createdAt: datetime |
|
updatedAt: Optional[datetime] = None |
|
category: Optional[Category] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
class ProductUpdate(BaseModel): |
|
productCode: Optional[str] = None |
|
productName: Optional[str] = None |
|
unit: Optional[str] = None |
|
warehouse: Optional[str] = None |
|
unitWeight: Optional[float] = None |
|
barcode: Optional[str] = None |
|
category_id: Optional[int] = None |
|
stock: Optional[int] = Field(None, ge=0, description="庫存數量,必須大於等於0") |
|
|
|
|
|
|
|
class SupplierBase(BaseModel): |
|
name: str |
|
contactInfo: Optional[str] = None |
|
address: Optional[str] = None |
|
|
|
class SupplierCreate(SupplierBase): |
|
pass |
|
|
|
class Supplier(SupplierBase): |
|
id: int |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
class CustomerBase(BaseModel): |
|
customerType: str |
|
salesPersonId: Optional[str] = None |
|
salesPersonName: Optional[str] = None |
|
customerCode: str = Field(..., description="客戶編號,必須唯一") |
|
customerName: str = Field(..., description="客戶名稱") |
|
contactPerson: Optional[str] = None |
|
invoiceTitle: Optional[str] = None |
|
taxId: Optional[str] = None |
|
phoneNumber: Optional[str] = None |
|
faxNumber: Optional[str] = None |
|
deliveryAddress: Optional[str] = None |
|
businessHours: Optional[str] = None |
|
paymentMethod: Optional[str] = None |
|
paymentCategory: Optional[str] = None |
|
creditLimit: Optional[float] = 0.0 |
|
|
|
class CustomerCreate(CustomerBase): |
|
pass |
|
|
|
class CustomerUpdate(BaseModel): |
|
customerType: Optional[str] = None |
|
salesPersonId: Optional[str] = None |
|
salesPersonName: Optional[str] = None |
|
customerCode: Optional[str] = None |
|
customerName: Optional[str] = None |
|
contactPerson: Optional[str] = None |
|
invoiceTitle: Optional[str] = None |
|
taxId: Optional[str] = None |
|
phoneNumber: Optional[str] = None |
|
faxNumber: Optional[str] = None |
|
deliveryAddress: Optional[str] = None |
|
businessHours: Optional[str] = None |
|
paymentMethod: Optional[str] = None |
|
paymentCategory: Optional[str] = None |
|
creditLimit: Optional[float] = None |
|
|
|
class Customer(CustomerBase): |
|
id: int |
|
createdDate: datetime |
|
updatedAt: Optional[datetime] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
class UserBase(BaseModel): |
|
name: Optional[str] = None |
|
email: EmailStr |
|
phoneNumber: Optional[str] = None |
|
role: Optional[UserRole] = UserRole.USER |
|
|
|
class UserCreate(UserBase): |
|
password: str = Field(..., min_length=4) |
|
|
|
class UserUpdate(BaseModel): |
|
name: Optional[str] = None |
|
email: Optional[EmailStr] = None |
|
phoneNumber: Optional[str] = None |
|
role: Optional[UserRole] = None |
|
|
|
|
|
class User(UserBase): |
|
id: int |
|
createdAt: datetime |
|
|
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class TransactionProductAssociationBase(BaseModel): |
|
product_id: int |
|
quantity: Optional[int] = 1 |
|
unit_price: Optional[float] = None |
|
line_total: Optional[float] = None |
|
notes: Optional[str] = None |
|
|
|
class TransactionProductAssociationCreate(TransactionProductAssociationBase): |
|
pass |
|
|
|
class TransactionProductAssociation(TransactionProductAssociationBase): |
|
|
|
product: Optional[Product] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class TransactionBase(BaseModel): |
|
totalProducts: int |
|
totalPrice: float |
|
transactionType: TransactionType |
|
transactionStatus: Optional[TransactionStatus] = TransactionStatus.PENDING |
|
description: Optional[str] = None |
|
note: Optional[str] = None |
|
user_id: Optional[int] = None |
|
supplier_id: Optional[int] = None |
|
customer_id: Optional[int] = None |
|
|
|
|
|
|
|
|
|
class TransactionCreate(TransactionBase): |
|
|
|
|
|
products_involved: List[TransactionProductAssociationCreate] |
|
|
|
|
|
class Transaction(TransactionBase): |
|
id: int |
|
createdAt: datetime |
|
updatedAt: Optional[datetime] = None |
|
user: Optional[User] = None |
|
supplier: Optional[Supplier] = None |
|
customer: Optional[Customer] = None |
|
products: List[TransactionProductAssociation] |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
class TransactionStatusUpdate(BaseModel): |
|
status: TransactionStatus |
|
|
|
|
|
class Token(BaseModel): |
|
access_token: str |
|
token_type: str |
|
|
|
class TokenData(BaseModel): |
|
email: Optional[str] = None |
|
|
|
class UserLogin(BaseModel): |
|
email: EmailStr |
|
password: str |
|
|
|
|
|
|
|
class PurchaseOrderStatus(str, enum.Enum): |
|
DRAFT = "DRAFT" |
|
PENDING = "PENDING" |
|
CONFIRMED = "CONFIRMED" |
|
RECEIVED = "RECEIVED" |
|
CANCELLED = "CANCELLED" |
|
|
|
class PaymentStatus(str, enum.Enum): |
|
UNPAID = "UNPAID" |
|
PARTIAL = "PARTIAL" |
|
PAID = "PAID" |
|
|
|
class TaxType(str, enum.Enum): |
|
INCLUSIVE = "INCLUSIVE" |
|
EXCLUSIVE = "EXCLUSIVE" |
|
ADDITIONAL = "ADDITIONAL" |
|
|
|
|
|
class GoodsReceiptStatus(str, enum.Enum): |
|
DRAFT = "DRAFT" |
|
PENDING = "PENDING" |
|
COMPLETED = "COMPLETED" |
|
CANCELLED = "CANCELLED" |
|
|
|
class WarehouseType(str, enum.Enum): |
|
MAIN = "MAIN" |
|
RAW_MATERIAL = "RAW_MATERIAL" |
|
FINISHED_GOODS = "FINISHED_GOODS" |
|
QUARANTINE = "QUARANTINE" |
|
DAMAGED = "DAMAGED" |
|
|
|
|
|
class SalesOrderStatus(str, enum.Enum): |
|
DRAFT = "DRAFT" |
|
CONFIRMED = "CONFIRMED" |
|
SHIPPED = "SHIPPED" |
|
DELIVERED = "DELIVERED" |
|
CANCELLED = "CANCELLED" |
|
|
|
class PaymentTerm(str, enum.Enum): |
|
CASH = "CASH" |
|
MONTHLY = "MONTHLY" |
|
TRANSFER = "TRANSFER" |
|
CREDIT_CARD = "CREDIT_CARD" |
|
CHECK = "CHECK" |
|
|
|
|
|
|
|
class PurchaseOrderItemBase(BaseModel): |
|
product_id: int = Field(..., description="產品ID") |
|
quantity: int = Field(..., gt=0, description="數量,必須大於0") |
|
unit_price: float = Field(..., ge=0, description="單價,必須大於等於0") |
|
notes: Optional[str] = None |
|
|
|
class PurchaseOrderItemCreate(PurchaseOrderItemBase): |
|
pass |
|
|
|
class PurchaseOrderItemUpdate(BaseModel): |
|
product_id: Optional[int] = None |
|
quantity: Optional[int] = Field(None, gt=0) |
|
unit_price: Optional[float] = Field(None, ge=0) |
|
notes: Optional[str] = None |
|
|
|
class PurchaseOrderItem(PurchaseOrderItemBase): |
|
id: int |
|
line_total: float |
|
product: Optional[Product] = None |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class PurchaseOrderBase(BaseModel): |
|
purchase_date: date = Field(..., description="採購日期") |
|
expected_delivery_date: Optional[date] = None |
|
supplier_id: int = Field(..., description="供應商ID") |
|
notes: Optional[str] = None |
|
tax_type: TaxType = TaxType.INCLUSIVE |
|
tax_rate: float = Field(0.05, ge=0, le=1, description="稅率,0-1之間") |
|
payment_method: Optional[str] = None |
|
|
|
class PurchaseOrderCreate(PurchaseOrderBase): |
|
items: List[PurchaseOrderItemCreate] = Field(..., min_items=1, description="採購明細,至少要有一項") |
|
|
|
class PurchaseOrderUpdate(BaseModel): |
|
purchase_date: Optional[date] = None |
|
expected_delivery_date: Optional[date] = None |
|
supplier_id: Optional[int] = None |
|
status: Optional[PurchaseOrderStatus] = None |
|
notes: Optional[str] = None |
|
tax_type: Optional[TaxType] = None |
|
tax_rate: Optional[float] = Field(None, ge=0, le=1) |
|
payment_method: Optional[str] = None |
|
payment_status: Optional[PaymentStatus] = None |
|
|
|
class PurchaseOrder(PurchaseOrderBase): |
|
id: int |
|
po_number: str |
|
purchaser_id: int |
|
status: PurchaseOrderStatus |
|
subtotal: float |
|
tax_amount: float |
|
total_amount: float |
|
payment_status: PaymentStatus |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
|
|
purchaser: Optional[User] = None |
|
supplier: Optional[Supplier] = None |
|
items: List[PurchaseOrderItem] = [] |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class GoodsReceiptItemBase(BaseModel): |
|
purchase_order_item_id: int = Field(..., description="採購明細ID") |
|
product_id: int = Field(..., description="產品ID") |
|
ordered_quantity: int = Field(..., gt=0, description="採購數量") |
|
received_quantity: int = Field(..., ge=0, description="實到數量,必須大於等於0") |
|
storage_location: Optional[str] = None |
|
notes: Optional[str] = None |
|
|
|
class GoodsReceiptItemCreate(GoodsReceiptItemBase): |
|
pass |
|
|
|
class GoodsReceiptItemUpdate(BaseModel): |
|
purchase_order_item_id: Optional[int] = None |
|
product_id: Optional[int] = None |
|
received_quantity: Optional[int] = Field(None, ge=0) |
|
storage_location: Optional[str] = None |
|
notes: Optional[str] = None |
|
|
|
class GoodsReceiptItem(GoodsReceiptItemBase): |
|
id: int |
|
product: Optional[Product] = None |
|
purchase_order_item: Optional[PurchaseOrderItem] = None |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class GoodsReceiptBase(BaseModel): |
|
receipt_date: date = Field(..., description="入庫日期") |
|
purchase_order_id: int = Field(..., description="採購單ID") |
|
warehouse_type: WarehouseType = WarehouseType.MAIN |
|
warehouse_location: Optional[str] = None |
|
notes: Optional[str] = None |
|
|
|
class GoodsReceiptCreate(GoodsReceiptBase): |
|
items: List[GoodsReceiptItemCreate] = Field(..., min_items=1, description="入庫明細,至少要有一項") |
|
|
|
class GoodsReceiptUpdate(BaseModel): |
|
receipt_date: Optional[date] = None |
|
warehouse_type: Optional[WarehouseType] = None |
|
warehouse_location: Optional[str] = None |
|
status: Optional[GoodsReceiptStatus] = None |
|
notes: Optional[str] = None |
|
items: Optional[List[GoodsReceiptItemUpdate]] = None |
|
|
|
class GoodsReceipt(GoodsReceiptBase): |
|
id: int |
|
gr_number: str |
|
warehouse_staff_id: int |
|
status: GoodsReceiptStatus |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
|
|
warehouse_staff: Optional[User] = None |
|
purchase_order: Optional[PurchaseOrder] = None |
|
items: List[GoodsReceiptItem] = [] |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class SalesOrderItemBase(BaseModel): |
|
product_id: int = Field(..., description="產品ID") |
|
quantity: int = Field(..., gt=0, description="數量,必須大於0") |
|
unit_price: float = Field(..., ge=0, description="單價,必須大於等於0") |
|
notes: Optional[str] = None |
|
|
|
class SalesOrderItemCreate(SalesOrderItemBase): |
|
pass |
|
|
|
class SalesOrderItemUpdate(BaseModel): |
|
product_id: Optional[int] = None |
|
quantity: Optional[int] = Field(None, gt=0) |
|
unit_price: Optional[float] = Field(None, ge=0) |
|
notes: Optional[str] = None |
|
|
|
class SalesOrderItem(SalesOrderItemBase): |
|
id: int |
|
line_total: float |
|
product: Optional[Product] = None |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
class Config: |
|
from_attributes = True |
|
|
|
|
|
|
|
class SalesOrderBase(BaseModel): |
|
sales_date: date = Field(..., description="銷售日期") |
|
customer_id: int = Field(..., description="客戶ID") |
|
payment_term: PaymentTerm = PaymentTerm.CASH |
|
notes: Optional[str] = None |
|
tax_type: TaxType = TaxType.INCLUSIVE |
|
tax_rate: float = Field(0.05, ge=0, le=1, description="稅率,0-1之間") |
|
discount_rate: float = Field(0.0, ge=0, le=1, description="折扣率,0-1之間") |
|
|
|
class SalesOrderCreate(SalesOrderBase): |
|
items: List[SalesOrderItemCreate] = Field(..., min_items=1, description="銷售明細,至少要有一項") |
|
|
|
class SalesOrderUpdate(BaseModel): |
|
sales_date: Optional[date] = None |
|
customer_id: Optional[int] = None |
|
payment_term: Optional[PaymentTerm] = None |
|
status: Optional[SalesOrderStatus] = None |
|
notes: Optional[str] = None |
|
tax_type: Optional[TaxType] = None |
|
tax_rate: Optional[float] = Field(None, ge=0, le=1) |
|
discount_rate: Optional[float] = Field(None, ge=0, le=1) |
|
items: Optional[List[SalesOrderItemUpdate]] = None |
|
|
|
class SalesOrder(SalesOrderBase): |
|
id: int |
|
so_number: str |
|
salesperson_id: int |
|
status: SalesOrderStatus |
|
subtotal: float |
|
tax_amount: float |
|
discount_amount: float |
|
total_amount: float |
|
created_at: datetime |
|
updated_at: Optional[datetime] = None |
|
|
|
|
|
salesperson: Optional[User] = None |
|
customer: Optional[Customer] = None |
|
items: List[SalesOrderItem] = [] |
|
|
|
class Config: |
|
from_attributes = True |
|
|