Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/adapters/api/v1/schema_models/distribution.py

392 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Schemaهای افزونه پخش مویرگی."""
from __future__ import annotations
from typing import Any, Dict, List, Literal, Optional, Union
from pydantic import BaseModel, Field, field_validator
class DistributionSettingsPayload(BaseModel):
shared_routing_catalog: Optional[bool] = None
require_visit_in_daily_plan: Optional[bool] = None
geofence_radius_meters: Optional[int] = Field(None, ge=0, le=50000)
require_geofence: Optional[bool] = None
visit_checklist_template: Optional[List[Dict[str, Any]]] = None
enable_van_sales: Optional[bool] = None
default_source_warehouse_id: Optional[int] = Field(None, gt=0)
enable_presell: Optional[bool] = None
enable_promotions: Optional[bool] = None
visitor_max_discount_percent: Optional[float] = Field(None, ge=0, le=100)
enable_suggested_order: Optional[bool] = None
map_tile_source: Optional[Literal["osm", "memaps"]] = None
memaps_api_key: Optional[str] = Field(None, max_length=255)
share_live_location: Optional[bool] = None
carry_over_missed_visits: Optional[bool] = None
carry_over_days: Optional[int] = Field(None, ge=1, le=31)
require_pod_signature: Optional[bool] = None
require_pod_photo: Optional[bool] = None
nav_provider: Optional[Literal["neshan", "google", "waze"]] = None
setup_completed: Optional[bool] = None
auto_apply_promotions: Optional[bool] = None
enable_perfect_store: Optional[bool] = None
near_expiry_days: Optional[int] = Field(None, ge=1, le=90)
class TerritoryCreatePayload(BaseModel):
code: str = Field(..., min_length=1, max_length=50)
name: str = Field(..., min_length=1, max_length=255)
description: Optional[str] = None
is_active: bool = True
class TerritoryUpdatePayload(BaseModel):
name: Optional[str] = Field(None, max_length=255)
description: Optional[str] = None
is_active: Optional[bool] = None
class RouteCreatePayload(BaseModel):
code: str = Field(..., min_length=1, max_length=50)
name: str = Field(..., min_length=1, max_length=255)
description: Optional[str] = None
territory_id: Optional[int] = None
is_active: bool = True
class RouteUpdatePayload(BaseModel):
name: Optional[str] = Field(None, max_length=255)
description: Optional[str] = None
territory_id: Optional[int] = None
is_active: Optional[bool] = None
class RouteStopPayload(BaseModel):
id: Optional[int] = None
person_id: int = Field(..., gt=0)
sort_order: int = 0
weekday: Optional[int] = Field(None, ge=0, le=6)
frequency: Optional[Literal["weekly", "biweekly", "monthly"]] = None
cycle_offset: Optional[int] = Field(None, ge=0, le=4)
customer_class: Optional[Literal["A", "B", "C"]] = None
notes: Optional[str] = None
class AssignmentCreatePayload(BaseModel):
route_id: int = Field(..., gt=0)
user_id: int = Field(..., gt=0)
valid_from: str = Field(..., description="YYYY-MM-DD")
valid_to: Optional[str] = None
class VisitStartPayload(BaseModel):
person_id: int = Field(..., gt=0)
route_id: Optional[int] = None
route_stop_id: Optional[int] = None
notes: Optional[str] = None
start_latitude: Optional[float] = None
start_longitude: Optional[float] = None
geofence_override: Optional[bool] = None
geofence_override_reason: Optional[str] = Field(None, max_length=500)
supervisor_user_id: Optional[int] = Field(None, gt=0)
is_carried_over: Optional[bool] = None
extra_info: Optional[Dict[str, Any]] = None
class VisitCompletePayload(BaseModel):
outcome: Literal["order", "no_order"]
no_order_reason: Optional[str] = None
no_order_reason_code: Optional[str] = Field(None, max_length=32)
document_id: Optional[int] = Field(None, gt=0)
deal_id: Optional[int] = Field(None, gt=0)
notes: Optional[str] = None
end_latitude: Optional[float] = None
end_longitude: Optional[float] = None
checklist_answers: Optional[Union[Dict[str, Any], List[Any]]] = None
shelf_photo_file_id: Optional[int] = Field(None, gt=0)
van_sale_lines: Optional[List[Dict[str, Any]]] = None
extra_info: Optional[Dict[str, Any]] = None
pod_confirmed: Optional[bool] = None
pod_signer_name: Optional[str] = Field(None, max_length=255)
pod_note: Optional[str] = Field(None, max_length=500)
pod_signature_png: Optional[str] = None
pod_photo_file_id: Optional[int] = Field(None, gt=0)
pod_signature_file_id: Optional[int] = Field(None, gt=0)
class VisitCancelPayload(BaseModel):
reason: Optional[str] = None
class VisitHeartbeatPayload(BaseModel):
latitude: float
longitude: float
visit_id: Optional[int] = Field(None, gt=0)
class ReturnLinePayload(BaseModel):
product_id: int = Field(..., gt=0)
quantity: float = Field(..., gt=0)
reason: Optional[str] = Field(None, max_length=500)
reason_code: Optional[str] = Field(None, max_length=32)
unit: Optional[str] = Field(None, max_length=32)
lot_code: Optional[str] = Field(None, max_length=64)
expiry_date: Optional[str] = None
unit_weight_kg: Optional[float] = Field(None, ge=0)
unit_volume_m3: Optional[float] = Field(None, ge=0)
@field_validator("quantity")
@classmethod
def _qty_positive(cls, v: float) -> float:
if v <= 0:
raise ValueError("quantity must be positive")
return v
class ReturnRequestCreatePayload(BaseModel):
person_id: int = Field(..., gt=0)
visit_id: Optional[int] = Field(None, gt=0)
source_document_id: Optional[int] = Field(None, gt=0)
lines: List[ReturnLinePayload] = Field(..., min_length=1)
notes: Optional[str] = None
class ReturnResolvePayload(BaseModel):
status: Literal["approved", "rejected"]
resolved_document_id: Optional[int] = Field(None, gt=0)
source_document_id: Optional[int] = Field(None, gt=0)
restock_to_van: Optional[bool] = None
class VanCreatePayload(BaseModel):
code: str = Field(..., min_length=1, max_length=50)
name: str = Field(..., min_length=1, max_length=255)
user_id: Optional[int] = Field(None, gt=0)
is_active: bool = True
plate_number: Optional[str] = Field(None, max_length=32)
max_weight_kg: Optional[float] = Field(None, ge=0)
max_volume_m3: Optional[float] = Field(None, ge=0)
class VanLoadPayload(BaseModel):
lines: List[ReturnLinePayload] = Field(..., min_length=1)
source_warehouse_id: Optional[int] = Field(None, gt=0)
class VanUnloadPayload(BaseModel):
lines: List[ReturnLinePayload] = Field(..., min_length=1)
dest_warehouse_id: Optional[int] = Field(None, gt=0)
class VanUpdatePayload(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=255)
user_id: Optional[int] = Field(None, gt=0)
is_active: Optional[bool] = None
plate_number: Optional[str] = Field(None, max_length=32)
max_weight_kg: Optional[float] = Field(None, ge=0)
max_volume_m3: Optional[float] = Field(None, ge=0)
class PersonLocationPayload(BaseModel):
latitude: float
longitude: float
class OfflineSyncPayload(BaseModel):
client_batch_id: Optional[str] = Field(None, max_length=64)
actions: List[Dict[str, Any]] = Field(..., min_length=1)
class SalesTargetPayload(BaseModel):
user_id: int = Field(..., gt=0)
period_type: Literal["day", "month"]
period_start: str = Field(..., description="YYYY-MM-DD")
target_amount: float = Field(..., gt=0)
metric: Literal["amount", "visits", "sku_qty", "coverage_pct"] = "amount"
product_id: Optional[int] = Field(None, gt=0)
target_value: Optional[float] = Field(None, gt=0)
notes: Optional[str] = None
class SettlementUpsertPayload(BaseModel):
user_id: Optional[int] = Field(None, gt=0)
settlement_date: Optional[str] = None
cash_collected: float = 0
cheque_collected: float = 0
card_collected: float = 0
other_collected: float = 0
expenses: float = 0
expected_sales: Optional[float] = None
cash_register_id: Optional[int] = Field(None, gt=0)
notes: Optional[str] = None
class SettlementConfirmPayload(BaseModel):
create_receipt: bool = False
cash_register_id: Optional[int] = Field(None, gt=0)
bank_id: Optional[int] = Field(None, gt=0)
allow_variance: bool = False
invoice_allocations: Optional[List[Dict[str, Any]]] = None
cheque_items: Optional[List[Dict[str, Any]]] = None
class VisitOrderCreatePayload(BaseModel):
person_id: int = Field(..., gt=0)
visit_id: Optional[int] = Field(None, gt=0)
route_id: Optional[int] = Field(None, gt=0)
lines: List[Dict[str, Any]] = Field(..., min_length=1)
promotion_ids: Optional[List[int]] = None
requested_delivery_date: Optional[str] = None
notes: Optional[str] = None
confirm: bool = False
extra_info: Optional[Dict[str, Any]] = None
class VisitOrderStatusPayload(BaseModel):
status: Literal[
"draft", "confirmed", "picking", "loaded", "out_for_delivery", "delivered", "cancelled"
]
class PromotionUpsertPayload(BaseModel):
code: str = Field(..., min_length=1, max_length=50)
name: str = Field(..., min_length=1, max_length=255)
mechanic: Literal["percent_off", "amount_off", "bxgy", "foc"] = "percent_off"
config: Dict[str, Any] = Field(default_factory=dict)
valid_from: str
valid_to: Optional[str] = None
territory_id: Optional[int] = Field(None, gt=0)
route_id: Optional[int] = Field(None, gt=0)
product_ids: Optional[List[int]] = None
is_active: bool = True
notes: Optional[str] = None
class DeliveryTripCreatePayload(BaseModel):
driver_user_id: Optional[int] = Field(None, gt=0)
van_id: Optional[int] = Field(None, gt=0)
trip_date: Optional[str] = None
order_ids: List[int] = Field(default_factory=list)
notes: Optional[str] = None
class DeliveryStopCompletePayload(BaseModel):
status: Literal["delivered", "partial", "failed"] = "delivered"
pod_confirmed: Optional[bool] = None
pod_signer_name: Optional[str] = Field(None, max_length=255)
pod_note: Optional[str] = Field(None, max_length=500)
pod_photo_file_id: Optional[int] = Field(None, gt=0)
latitude: Optional[float] = None
longitude: Optional[float] = None
warehouse_id: Optional[int] = Field(None, gt=0)
delivered_lines: Optional[List[Dict[str, Any]]] = None
failure_reason: Optional[str] = Field(None, max_length=255)
class LoadPlanCreatePayload(BaseModel):
plan_date: Optional[str] = None
warehouse_id: Optional[int] = Field(None, gt=0)
van_id: Optional[int] = Field(None, gt=0)
order_ids: Optional[List[int]] = None
notes: Optional[str] = None
class LoadPlanConfirmPayload(BaseModel):
actual_lines: Optional[List[ReturnLinePayload]] = None
class CommissionRulePayload(BaseModel):
name: str = Field(..., min_length=1, max_length=255)
rule_type: str = "percent_of_sales"
config: Dict[str, Any] = Field(default_factory=lambda: {"percent": 1})
is_active: bool = True
valid_from: Optional[str] = None
valid_to: Optional[str] = None
class CommissionRunPayload(BaseModel):
user_id: int = Field(..., gt=0)
period_start: str
period_end: Optional[str] = None
rule_id: Optional[int] = Field(None, gt=0)
class ShelfAuditPayload(BaseModel):
person_id: int = Field(..., gt=0)
visit_id: Optional[int] = Field(None, gt=0)
answers: Union[Dict[str, Any], List[Any]]
photo_file_ids: Optional[List[int]] = None
notes: Optional[str] = None
class CustomerAssetPayload(BaseModel):
person_id: Optional[int] = Field(None, gt=0)
asset_code: Optional[str] = Field(None, max_length=64)
asset_type: Optional[str] = Field(None, max_length=64)
name: Optional[str] = Field(None, max_length=255)
status: Optional[str] = None
placed_at: Optional[str] = None
notes: Optional[str] = None
check_now: Optional[bool] = None
class CustomerProfilePayload(BaseModel):
customer_class: Optional[Literal["A", "B", "C"]] = None
visit_frequency: Optional[Literal["weekly", "biweekly", "monthly"]] = None
cycle_offset: Optional[int] = Field(None, ge=0, le=4)
price_list_id: Optional[int] = Field(None, gt=0)
outlet_type: Optional[str] = Field(None, max_length=32)
assortment_id: Optional[int] = Field(None, gt=0)
storefront_photo_file_id: Optional[int] = Field(None, gt=0)
notes: Optional[str] = None
class AssortmentPayload(BaseModel):
code: Optional[str] = Field(None, min_length=1, max_length=50)
name: Optional[str] = Field(None, min_length=1, max_length=255)
outlet_type: Optional[str] = Field(None, max_length=32)
product_ids: Optional[List[int]] = None
must_sell_product_ids: Optional[List[int]] = None
is_active: Optional[bool] = None
notes: Optional[str] = None
class SetupWizardPayload(BaseModel):
enable_van_sales: bool = False
enable_presell: bool = True
enable_promotions: bool = True
default_source_warehouse_id: Optional[int] = Field(None, gt=0)
nav_provider: Optional[Literal["neshan", "google", "waze"]] = None
territory_name: Optional[str] = None
territory_code: Optional[str] = None
route_name: Optional[str] = None
route_code: Optional[str] = None
route_id: Optional[int] = Field(None, gt=0)
territory_id: Optional[int] = Field(None, gt=0)
person_ids: Optional[List[int]] = None
weekday: Optional[int] = Field(None, ge=0, le=6)
frequency: Optional[Literal["weekly", "biweekly", "monthly"]] = None
cycle_offset: Optional[int] = Field(None, ge=0, le=4)
customer_class: Optional[Literal["A", "B", "C"]] = None
visitor_user_id: Optional[int] = Field(None, gt=0)
valid_from: Optional[str] = None
class NewOutletPayload(BaseModel):
name: str = Field(..., min_length=1, max_length=255)
mobile: Optional[str] = None
phone: Optional[str] = None
address: Optional[str] = None
city: Optional[str] = None
latitude: Optional[float] = None
longitude: Optional[float] = None
customer_class: Optional[Literal["A", "B", "C"]] = None
frequency: Optional[Literal["weekly", "biweekly", "monthly"]] = None
outlet_type: Optional[str] = None
price_list_id: Optional[int] = Field(None, gt=0)
assortment_id: Optional[int] = Field(None, gt=0)
storefront_photo_file_id: Optional[int] = Field(None, gt=0)
route_id: Optional[int] = Field(None, gt=0)
weekday: Optional[int] = Field(None, ge=0, le=6)
sort_order: Optional[int] = None
notes: Optional[str] = None