feat(backend): add FastAPI backend — procurement, inventory domain, Casdoor auth, PM arrival endpoints
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Pydantic v2 request schemas — inventory domain (fork's contract, unchanged)."""
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import Field, model_validator
|
||||
|
||||
from app.models.inventory import INVENTORY_TRANSACTION_TYPES
|
||||
from app.schemas.common import APIModel
|
||||
|
||||
TransactionType = Literal[
|
||||
"PURCHASE",
|
||||
"WITHDRAWAL",
|
||||
"RETURN",
|
||||
"TRANSFER_IN",
|
||||
"TRANSFER_OUT",
|
||||
"DAMAGE",
|
||||
"WASTE",
|
||||
"LOSS",
|
||||
"FOUND",
|
||||
"STOCK_COUNT",
|
||||
]
|
||||
|
||||
|
||||
class WarehouseCreate(APIModel):
|
||||
project_id: UUID
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
|
||||
|
||||
class WarehouseUpdate(APIModel):
|
||||
name: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
description: str | None = None
|
||||
project_id: UUID | None = None
|
||||
|
||||
|
||||
class InventoryTransactionCreate(APIModel):
|
||||
"""One inventory operation.
|
||||
|
||||
- For all types except STOCK_COUNT: `quantity` is the amount to add/remove.
|
||||
- STOCK_COUNT uses `physical_qty` (the counted quantity); the difference
|
||||
against the recorded quantity is computed and applied by the service.
|
||||
- TRANSFER_OUT requires `dest_warehouse_id`; the service creates the linked
|
||||
TRANSFER_IN row in the destination warehouse (transfer_pair_id).
|
||||
- `specs` is a dict of technical specifications (dynamic multi-spec entries).
|
||||
- `transaction_date` defaults to server now() when omitted.
|
||||
"""
|
||||
|
||||
transaction_type: TransactionType
|
||||
warehouse_id: UUID
|
||||
dest_warehouse_id: UUID | None = None
|
||||
material_id: UUID
|
||||
brand_id: UUID | None = None
|
||||
quantity: Decimal | None = Field(default=None, gt=0)
|
||||
physical_qty: Decimal | None = Field(default=None, ge=0)
|
||||
unit_id: int | None = None
|
||||
specs: dict | None = None
|
||||
note: str | None = None
|
||||
transaction_date: datetime | None = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_type_rules(self):
|
||||
t = self.transaction_type
|
||||
if t == "STOCK_COUNT":
|
||||
if self.physical_qty is None:
|
||||
raise ValueError("برای شمارش موجودی، تعداد شمارششده (physical_qty) الزامی است")
|
||||
else:
|
||||
if self.quantity is None:
|
||||
raise ValueError("تعداد (quantity) الزامی است")
|
||||
if t == "TRANSFER_OUT":
|
||||
if self.dest_warehouse_id is None:
|
||||
raise ValueError("برای انتقال خروجی، انبار مقصد (dest_warehouse_id) الزامی است")
|
||||
if self.dest_warehouse_id == self.warehouse_id:
|
||||
raise ValueError("انبار مبدأ و مقصد نمیتوانند یکسان باشند")
|
||||
if t not in INVENTORY_TRANSACTION_TYPES:
|
||||
raise ValueError(f"نوع تراکنش نامعتبر است: {t}")
|
||||
return self
|
||||
Reference in New Issue
Block a user