Files
ERP/backend/app/schemas/inventory.py
T
whqreza d85ede7d11 feat(inventory): display all warehouse items on selection and track withdrawal recipient
- Show all available inventory items immediately when selecting a warehouse in withdrawal form
- Add vertical scrolling container with max height to prevent layout overflow for large item lists
- Add Material column to the inventory rows table for clear item identification
- Add required 'delivered_to' recipient field in withdrawal form with frontend validation
- Track delivered_to in database, models, schemas, and API
- Display recipient badge on withdrawal cards in daily control page
- Group daily control withdrawals by inventory ID and recipient
2026-09-28 22:54:02 +03:30

87 lines
3.1 KiB
Python

"""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):
"""Rename/re-describe a warehouse.
`project_id` is accepted only to be rejected: a warehouse belongs
permanently to its parent project and cannot be reassigned (the router
answers 400 unless the value equals the current project).
"""
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
delivered_to: 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