Spaces:
Runtime error
Runtime error
| # -*- coding: utf-8 -*- | |
| """ | |
| J1K OS v2.2 Final Master - Pydantic Models | |
| UUID Edition with JSONB Support | |
| """ | |
| from pydantic import BaseModel, Field, field_validator | |
| from typing import Optional, List, Dict, Any | |
| from uuid import UUID | |
| import uuid | |
| from enum import Enum | |
| from datetime import datetime | |
| # ========================================== | |
| # Helper: Hybrid UUID Validator | |
| # ========================================== | |
| def validate_hybrid_biz_id(v): | |
| """ | |
| ๐ง ุงูู ุญุฑู ุงูุณุญุฑู: ุจูุชุฑุฌู ุฃู Slug ุฃู UUID String ูู UUID Object | |
| """ | |
| if not v: | |
| raise ValueError("Business ID is missing") | |
| # ูู ุฌุงู UUID Object ุฎูุงุต | |
| if isinstance(v, uuid.UUID): | |
| return v | |
| # ูู ุฌุงู Stringุ ุญุงูู ุชุญููู ูู UUID | |
| try: | |
| # ู ุญุงููุฉ UUID ู ุจุงุดุฑุฉ | |
| return uuid.UUID(str(v)) | |
| except ValueError: | |
| # ู ุด UUID ุตุงูุญุ ูุจูู Slug - ุงูู Backend ููุฑุฌุนู ู ู ุงูุฏุงุชุงุจูุฒ | |
| # Note: ุงูู resolve_biz_id_cached ูุชุชููุฐ ูู ุงูู Endpoint | |
| pass | |
| # ุฑุฌุน String ุนุดุงู ุงูู Endpoint ูุญูู | |
| return str(v) | |
| # ========================================== | |
| # 1. Business Models | |
| # ========================================== | |
| class Business(BaseModel): | |
| id: Optional[UUID] = None | |
| name: str | |
| sector: str | |
| whatsapp_number: Optional[str] = None | |
| slug: Optional[str] = None | |
| logo_url: Optional[str] = None | |
| gps_location: Optional[str] = None | |
| contacts_json: Optional[str] = None | |
| is_active: Optional[bool] = True | |
| is_open: Optional[int] = 1 | |
| is_premium: Optional[bool] = False | |
| ai_enabled: Optional[bool] = False | |
| offers_access: Optional[bool] = False | |
| delivery_fee: Optional[float] = 0.0 | |
| subscription_expires_at: Optional[str] = None | |
| theme_primary_color: Optional[str] = None | |
| theme_secondary_color: Optional[str] = None | |
| # ๐ ุญู ุงูุฉ ุงูุจูุงูุงุช ุงูุณูุงุฏูุฉ | |
| username: Optional[str] = None | |
| password: Optional[str] = None | |
| class BusinessCreate(BaseModel): | |
| name: str | |
| sector: str | |
| slug: str | |
| username: str | |
| password: str | |
| whatsapp_number: Optional[str] = None | |
| logo_url: Optional[str] = None | |
| gps_location: Optional[str] = None | |
| is_active: bool = True | |
| is_premium: bool = False | |
| ai_enabled: bool = False | |
| offers_access: bool = False | |
| class BusinessUpdate(BaseModel): | |
| whatsapp_number: Optional[str] = None | |
| delivery_fee: Optional[float] = None | |
| logo_url: Optional[str] = None | |
| gps_location: Optional[str] = None | |
| contacts_json: Optional[str] = None | |
| ai_enabled: Optional[bool] = None | |
| is_premium: Optional[bool] = None | |
| is_open: Optional[int] = None | |
| is_active: Optional[bool] = None | |
| class ThemeUpdateRequest(BaseModel): | |
| theme_primary_color: Optional[str] = None | |
| theme_secondary_color: Optional[str] = None | |
| # ========================================== | |
| # 2. Inventory Item Models | |
| # ========================================== | |
| class InventoryItem(BaseModel): | |
| id: Optional[UUID] = None | |
| business_id: UUID # โ UUID ุนุดุงู RLS | |
| name: str | |
| description: Optional[str] = "" | |
| price: float | |
| old_price: Optional[float] = 0.0 | |
| category: str | |
| image_data: Optional[str] = "" | |
| image_url: Optional[str] = None | |
| is_available: Optional[int] = 1 | |
| is_bogo: Optional[bool] = False | |
| extra_info: Optional[Dict[str, Any]] = {} | |
| created_at: Optional[datetime] = None | |
| class InventoryItemCreate(BaseModel): | |
| business_id: UUID | |
| name: str | |
| description: Optional[str] = "" | |
| price: float | |
| old_price: Optional[float] = 0.0 | |
| category: str | |
| image_data: Optional[str] = "" | |
| is_bogo: Optional[bool] = False | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| class InventoryItemExt(BaseModel): | |
| """ูุณุฎุฉ ู ูุณุนุฉ ู ุน Validator""" | |
| business_id: UUID | |
| name: str | |
| description: Optional[str] = "" | |
| price: float | |
| old_price: Optional[float] = 0.0 | |
| is_bogo: Optional[bool] = False | |
| category: str | |
| image_data: Optional[str] = "" | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| class ItemUpdate(BaseModel): | |
| name: Optional[str] = None | |
| description: Optional[str] = None | |
| category: Optional[str] = None | |
| price: Optional[float] = None | |
| old_price: Optional[float] = None | |
| is_bogo: Optional[bool] = None | |
| image_data: Optional[str] = None | |
| is_available: Optional[int] = None | |
| # ========================================== | |
| # 3. Order Item (JSONB Structure) | |
| # ========================================== | |
| class OrderItem(BaseModel): | |
| """Structure ููู item ูู ุงูุฃูุฑุฏุฑ - ููู JSONB""" | |
| id: str # item ID ู ู inventory | |
| name: str | |
| price: float | |
| quantity: int | |
| category: Optional[str] = None | |
| notes: Optional[str] = None # ุชุนุฏููุงุช ุฒู "ุจุฏูู ุจุตู" | |
| # ========================================== | |
| # 4. Order Models (JSONB Edition) | |
| # ========================================== | |
| class OrderType(str, Enum): | |
| delivery = "delivery" | |
| takeaway = "takeaway" | |
| dine_in = "dine_in" | |
| manual = "manual" | |
| class OrderSubmit(BaseModel): | |
| """ | |
| ๐ JSONB Edition: items ูู List of Dicts | |
| ู ุด String ู ุนู ูููุง json.dumps() | |
| """ | |
| business_id: UUID | |
| customer_name: str | |
| customer_phone: str | |
| customer_address: Optional[str] = "ุงุณุชูุงู ู ู ุงููุฑุน" | |
| notes: str = "" | |
| status: str = "pending" | |
| gps_link: str = "" | |
| # ๐ฏ JSONB: List of OrderItem objects | |
| items: List[OrderItem] # โ ู ุด str! | |
| total_price: float | |
| order_type: OrderType = OrderType.delivery | |
| table_number: Optional[str] = None | |
| discount_amount: float = 0.0 | |
| used_points: int = 0 | |
| device_fingerprint: Optional[str] = "Unknown" | |
| delivery_name: Optional[str] = None | |
| delivery_phone: Optional[str] = None | |
| delivery_fee: Optional[float] = 0.0 | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| def validate_items(cls, v): | |
| """ุชุฃูุฏ ุฅู ุงูู items List ู ุด ูุงุถูุฉ""" | |
| if isinstance(v, str): | |
| # ๐ก๏ธ ูู ุงูู Frontend ูุณู ุจูุจุนุช Stringุ ุญููู | |
| import json | |
| try: | |
| v = json.loads(v) | |
| except json.JSONDecodeError: | |
| raise ValueError("items must be valid JSON array") | |
| if not isinstance(v, list): | |
| raise ValueError("items must be a list") | |
| if len(v) == 0: | |
| raise ValueError("items cannot be empty") | |
| return v | |
| class OrderStatusUpdate(BaseModel): | |
| status: str | |
| # ========================================== | |
| # 5. Coupon Models | |
| # ========================================== | |
| class CouponCreate(BaseModel): | |
| business_id: UUID | |
| code: str | |
| discount_percent: float | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| class CouponValidate(BaseModel): | |
| business_id: UUID | |
| code: str | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| # ========================================== | |
| # 6. Shift Models | |
| # ========================================== | |
| class ShiftAction(BaseModel): | |
| action: str # 'open' or 'close' | |
| cashier_name: Optional[str] = None | |
| opening_balance: Optional[float] = 0.0 | |
| class ExpenseCreate(BaseModel): | |
| shift_id: UUID | |
| amount: float | |
| description: str | |
| created_by: str | |
| # ========================================== | |
| # 7. Settlement Models | |
| # ========================================== | |
| class SettlementCreate(BaseModel): | |
| pilot_name: str | |
| total_amount: float | |
| orders_count: int = 1 | |
| notes: Optional[str] = None | |
| # ========================================== | |
| # 8. AI Models | |
| # ========================================== | |
| class AIRequest(BaseModel): | |
| business_id: UUID | |
| item_name: str | |
| sector: str = "FOOD_HUB" | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| class ImageRequest(BaseModel): | |
| item_name: str | |
| business_id: UUID | |
| description: str | |
| sector: str | |
| forced_keywords: Optional[str] = None | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| class AIChatRequest(BaseModel): | |
| prompt: str | |
| menuContext: Any | |
| business_id: Optional[UUID] = None | |
| history: List[Dict[str, str]] = [] | |
| cartContext: Any = [] | |
| businessName: Optional[str] = "ู ุทุนู ูุง" | |
| location: Optional[str] = "ู ุตุฑ" | |
| currentTime: Optional[str] = "" | |
| weather: Optional[str] = "ู ุนุชุฏู" | |
| def resolve_id(cls, v): | |
| if v and str(v) != "default": | |
| return validate_hybrid_biz_id(v) | |
| return v | |
| class AIStatusUpdate(BaseModel): | |
| business_id: UUID | |
| ai_enabled: bool = False | |
| is_premium: bool = False | |
| def resolve_id(cls, v): | |
| return validate_hybrid_biz_id(v) | |
| # ========================================== | |
| # 9. Auth Models | |
| # ========================================== | |
| class LoginRequest(BaseModel): | |
| username: str | |
| password: str | |
| class OTPRequest(BaseModel): | |
| phone: str | |
| class PasswordReset(BaseModel): | |
| phone: str | |
| otp: str | |
| new_password: str | |
| # ========================================== | |
| # 10. Analytics Models | |
| # ========================================== | |
| class AnalyticsResponse(BaseModel): | |
| peak_hours: Dict[str, int] | |
| top_selling: Dict[str, int] | |
| dead_stock: List[str] | |
| total_revenue: float | |
| order_split: Dict[str, int] | |
| # ========================================== | |
| # 11. Master Admin Models | |
| # ========================================== | |
| class MasterBizUpdate(BaseModel): | |
| whatsapp_number: Optional[str] = None | |
| delivery_fee: Optional[float] = 0.0 | |
| logo_url: Optional[str] = None | |
| gps_location: Optional[str] = None | |
| contacts_json: Optional[Dict[str, Any]] = None | |
| ai_enabled: Optional[bool] = None | |
| is_premium: Optional[bool] = None | |
| offers_access: Optional[bool] = None | |
| sector: Optional[str] = None | |
| subscription_expires_at: Optional[str] = None | |
| is_active: Optional[bool] = None | |
| class MasterGenesis(BaseModel): | |
| name: str | |
| slug: str | |
| sector: str | |
| username: str | |
| password: str | |
| is_active: bool = True | |
| whatsapp_number: Optional[str] = None | |
| logo_url: str | |
| gps_location: Optional[str] = None | |
| offers_access: bool = False | |
| ai_enabled: bool = False | |
| is_premium: bool = False | |
| contacts_json: Optional[Dict[str, Any]] = None | |
| subscription_expires_at: Optional[str] = None | |
| class BranchStatusUpdate(BaseModel): | |
| is_open: int | |