feat(backend): add FastAPI backend — procurement, inventory domain, Casdoor auth, PM arrival endpoints
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
"""Pydantic v2 request schemas — catalog domain."""
|
||||
from decimal import Decimal
|
||||
from typing import Literal
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from app.schemas.common import APIModel
|
||||
|
||||
MaterialStatus = Literal["active", "discontinued", "draft"]
|
||||
AttributeDataType = Literal["number", "integer", "string", "enum", "boolean", "date"]
|
||||
|
||||
|
||||
class UnitCreate(APIModel):
|
||||
code: str = Field(min_length=1, max_length=255)
|
||||
name_fa: str | None = None
|
||||
dimension: str | None = None
|
||||
si_factor: Decimal = Field(default=Decimal("1.0"), gt=0)
|
||||
is_base: bool = False
|
||||
|
||||
|
||||
class UnitUpdate(APIModel):
|
||||
code: str | None = Field(default=None, min_length=1, max_length=255)
|
||||
name_fa: str | None = None
|
||||
dimension: str | None = None
|
||||
si_factor: Decimal | None = Field(default=None, gt=0)
|
||||
is_base: bool | None = None
|
||||
|
||||
|
||||
class BrandCreate(APIModel):
|
||||
name: str = Field(min_length=1)
|
||||
country: str | None = None
|
||||
|
||||
|
||||
class BrandUpdate(APIModel):
|
||||
name: str | None = Field(default=None, min_length=1)
|
||||
country: str | None = None
|
||||
|
||||
|
||||
class MaterialCategoryCreate(APIModel):
|
||||
slug: str = Field(min_length=1)
|
||||
name: str = Field(min_length=1)
|
||||
description: str | None = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class MaterialCategoryUpdate(APIModel):
|
||||
slug: str | None = Field(default=None, min_length=1)
|
||||
name: str | None = Field(default=None, min_length=1)
|
||||
description: str | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class AttributeDefinitionCreate(APIModel):
|
||||
attribute_key: str = Field(min_length=1)
|
||||
label: str = Field(min_length=1)
|
||||
data_type: AttributeDataType
|
||||
unit_id: int | None = None
|
||||
enum_values: list | None = None
|
||||
|
||||
|
||||
class AttributeDefinitionUpdate(APIModel):
|
||||
label: str | None = Field(default=None, min_length=1)
|
||||
data_type: AttributeDataType | None = None
|
||||
unit_id: int | None = None
|
||||
enum_values: list | None = None
|
||||
|
||||
|
||||
class CategoryAttributeCreate(APIModel):
|
||||
attribute_definition_id: UUID
|
||||
is_required: bool = False
|
||||
is_filterable: bool = False
|
||||
conditional_rules: dict | None = None
|
||||
sort_order: int = 0
|
||||
|
||||
|
||||
class CategoryAttributeUpdate(APIModel):
|
||||
is_required: bool | None = None
|
||||
is_filterable: bool | None = None
|
||||
conditional_rules: dict | None = None
|
||||
sort_order: int | None = None
|
||||
|
||||
|
||||
class MaterialAttributeIn(APIModel):
|
||||
"""One EAV value. `value` is coerced against attribute_definitions.data_type."""
|
||||
|
||||
attribute_definition_id: UUID
|
||||
value: int | float | str | bool | None = None
|
||||
|
||||
|
||||
class MaterialCreate(APIModel):
|
||||
category_id: UUID | None = None # v2.5: optional — derived from first linked supplier
|
||||
name: str = Field(min_length=1)
|
||||
topic: str | None = None # تاپیک جلوی برنامه (Persian) — legacy
|
||||
canonical_unit_id: int
|
||||
status: MaterialStatus = "active"
|
||||
brand_ids: list[UUID] = Field(default_factory=list)
|
||||
attributes: list[MaterialAttributeIn] = Field(default_factory=list)
|
||||
|
||||
|
||||
class MaterialUpdate(APIModel):
|
||||
name: str | None = Field(default=None, min_length=1)
|
||||
topic: str | None = None
|
||||
canonical_unit_id: int | None = None
|
||||
status: MaterialStatus | None = None
|
||||
|
||||
|
||||
class BrandMaterialCreate(APIModel):
|
||||
brand_id: UUID
|
||||
material_id: UUID
|
||||
catalog_code: str | None = None
|
||||
is_active: bool = True
|
||||
|
||||
|
||||
class BrandMaterialUpdate(APIModel):
|
||||
# brand_id / material_id are immutable (UNIQUE pair) — not accepted here.
|
||||
catalog_code: str | None = None
|
||||
is_active: bool | None = None
|
||||
|
||||
|
||||
class MaterialUnitCreate(APIModel):
|
||||
brand_material_id: UUID | None = None
|
||||
unit_id: int
|
||||
conversion_factor: Decimal = Field(gt=0)
|
||||
is_default: bool = False
|
||||
|
||||
|
||||
class MaterialUnitUpdate(APIModel):
|
||||
unit_id: int | None = None
|
||||
conversion_factor: Decimal | None = Field(default=None, gt=0)
|
||||
is_default: bool | None = None
|
||||
|
||||
|
||||
class MaterialAttributeValuesPut(APIModel):
|
||||
attributes: list[MaterialAttributeIn] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CategoryReferenceUnitPut(APIModel):
|
||||
ref_unit: str = Field(min_length=1)
|
||||
|
||||
|
||||
class UnitConversionCreate(APIModel):
|
||||
category_id: UUID
|
||||
brand: str | None = None
|
||||
from_unit: str = Field(min_length=1)
|
||||
to_unit: str = Field(min_length=1)
|
||||
factor: Decimal = Field(gt=0)
|
||||
|
||||
|
||||
class UnitConversionUpdate(APIModel):
|
||||
brand: str | None = None
|
||||
from_unit: str | None = Field(default=None, min_length=1)
|
||||
to_unit: str | None = Field(default=None, min_length=1)
|
||||
factor: Decimal | None = Field(default=None, gt=0)
|
||||
|
||||
|
||||
class StandardConversionCreate(APIModel):
|
||||
from_unit: str = Field(min_length=1)
|
||||
to_unit: str = Field(min_length=1)
|
||||
factor: Decimal = Field(gt=0)
|
||||
|
||||
|
||||
class StandardConversionUpdate(APIModel):
|
||||
from_unit: str | None = Field(default=None, min_length=1)
|
||||
to_unit: str | None = Field(default=None, min_length=1)
|
||||
factor: Decimal | None = Field(default=None, gt=0)
|
||||
Reference in New Issue
Block a user