""" Pydantic schemas for POS transaction API requests and responses """ from typing import Optional, List, Dict, Any from datetime import datetime from decimal import Decimal from pydantic import BaseModel, Field from enum import Enum class TransactionType(str, Enum): """Transaction type enumeration""" SALE = "sale" REFUND = "refund" VOID = "void" EXCHANGE = "exchange" class TransactionStatus(str, Enum): """Transaction status enumeration""" COMPLETED = "completed" PENDING = "pending" FAILED = "failed" REFUNDED = "refunded" VOIDED = "voided" class PaymentMethod(str, Enum): """Payment method enumeration""" CARD = "card" CASH = "cash" DIGITAL_WALLET = "digital_wallet" OTHER = "other" class OrderType(str, Enum): """Order type enumeration""" DINE_IN = "dine_in" TAKEOUT = "takeout" DELIVERY = "delivery" PICKUP = "pickup" class POSTransactionItemResponse(BaseModel): """Schema for POS transaction item response""" id: str transaction_id: str tenant_id: str external_item_id: Optional[str] = None sku: Optional[str] = None product_name: str product_category: Optional[str] = None product_subcategory: Optional[str] = None quantity: Decimal unit_price: Decimal total_price: Decimal discount_amount: Decimal = Decimal("0") tax_amount: Decimal = Decimal("0") modifiers: Optional[Dict[str, Any]] = None inventory_product_id: Optional[str] = None is_mapped_to_inventory: bool = False is_synced_to_sales: bool = False created_at: datetime updated_at: datetime class Config: from_attributes = True use_enum_values = True json_encoders = { datetime: lambda v: v.isoformat() if v else None, Decimal: lambda v: float(v) if v else 0.0 } @classmethod def from_orm(cls, obj): """Convert ORM object to schema with proper UUID and Decimal handling""" return cls( id=str(obj.id), transaction_id=str(obj.transaction_id), tenant_id=str(obj.tenant_id), external_item_id=obj.external_item_id, sku=obj.sku, product_name=obj.product_name, product_category=obj.product_category, product_subcategory=obj.product_subcategory, quantity=obj.quantity, unit_price=obj.unit_price, total_price=obj.total_price, discount_amount=obj.discount_amount, tax_amount=obj.tax_amount, modifiers=obj.modifiers, inventory_product_id=str(obj.inventory_product_id) if obj.inventory_product_id else None, is_mapped_to_inventory=obj.is_mapped_to_inventory, is_synced_to_sales=obj.is_synced_to_sales, created_at=obj.created_at, updated_at=obj.updated_at ) class POSTransactionResponse(BaseModel): """Schema for POS transaction response""" id: str tenant_id: str pos_config_id: str pos_system: str external_transaction_id: str external_order_id: Optional[str] = None transaction_type: TransactionType status: TransactionStatus subtotal: Decimal tax_amount: Decimal tip_amount: Decimal discount_amount: Decimal total_amount: Decimal currency: str = "EUR" payment_method: Optional[PaymentMethod] = None payment_status: Optional[str] = None transaction_date: datetime pos_created_at: datetime pos_updated_at: Optional[datetime] = None location_id: Optional[str] = None location_name: Optional[str] = None staff_id: Optional[str] = None staff_name: Optional[str] = None customer_id: Optional[str] = None customer_email: Optional[str] = None customer_phone: Optional[str] = None order_type: Optional[OrderType] = None table_number: Optional[str] = None receipt_number: Optional[str] = None is_synced_to_sales: bool = False sales_record_id: Optional[str] = None sync_attempted_at: Optional[datetime] = None sync_completed_at: Optional[datetime] = None sync_error: Optional[str] = None sync_retry_count: int = 0 is_processed: bool = False is_duplicate: bool = False created_at: datetime updated_at: datetime items: List[POSTransactionItemResponse] = [] class Config: from_attributes = True use_enum_values = True json_encoders = { datetime: lambda v: v.isoformat() if v else None, Decimal: lambda v: float(v) if v else 0.0 } @classmethod def from_orm(cls, obj): """Convert ORM object to schema with proper UUID and Decimal handling""" return cls( id=str(obj.id), tenant_id=str(obj.tenant_id), pos_config_id=str(obj.pos_config_id), pos_system=obj.pos_system, external_transaction_id=obj.external_transaction_id, external_order_id=obj.external_order_id, transaction_type=obj.transaction_type, status=obj.status, subtotal=obj.subtotal, tax_amount=obj.tax_amount, tip_amount=obj.tip_amount, discount_amount=obj.discount_amount, total_amount=obj.total_amount, currency=obj.currency, payment_method=obj.payment_method, payment_status=obj.payment_status, transaction_date=obj.transaction_date, pos_created_at=obj.pos_created_at, pos_updated_at=obj.pos_updated_at, location_id=obj.location_id, location_name=obj.location_name, staff_id=obj.staff_id, staff_name=obj.staff_name, customer_id=obj.customer_id, customer_email=obj.customer_email, customer_phone=obj.customer_phone, order_type=obj.order_type, table_number=obj.table_number, receipt_number=obj.receipt_number, is_synced_to_sales=obj.is_synced_to_sales, sales_record_id=str(obj.sales_record_id) if obj.sales_record_id else None, sync_attempted_at=obj.sync_attempted_at, sync_completed_at=obj.sync_completed_at, sync_error=obj.sync_error, sync_retry_count=obj.sync_retry_count, is_processed=obj.is_processed, is_duplicate=obj.is_duplicate, created_at=obj.created_at, updated_at=obj.updated_at, items=[POSTransactionItemResponse.from_orm(item) for item in obj.items] if hasattr(obj, 'items') and obj.items else [] ) class POSTransactionSummary(BaseModel): """Summary information for a transaction (lightweight)""" id: str external_transaction_id: str transaction_date: datetime total_amount: Decimal status: TransactionStatus payment_method: Optional[PaymentMethod] = None is_synced_to_sales: bool item_count: int = 0 class Config: from_attributes = True use_enum_values = True json_encoders = { datetime: lambda v: v.isoformat() if v else None, Decimal: lambda v: float(v) if v else 0.0 } class POSTransactionListResponse(BaseModel): """Schema for paginated transaction list response""" transactions: List[POSTransactionResponse] total: int has_more: bool = False summary: Optional[Dict[str, Any]] = None class Config: from_attributes = True class POSTransactionDashboardSummary(BaseModel): """Dashboard summary for POS transactions""" total_transactions_today: int = 0 total_transactions_this_week: int = 0 total_transactions_this_month: int = 0 revenue_today: Decimal = Decimal("0") revenue_this_week: Decimal = Decimal("0") revenue_this_month: Decimal = Decimal("0") average_transaction_value: Decimal = Decimal("0") status_breakdown: Dict[str, int] = {} payment_method_breakdown: Dict[str, int] = {} sync_status: Dict[str, Any] = {} class Config: from_attributes = True json_encoders = { Decimal: lambda v: float(v) if v else 0.0, datetime: lambda v: v.isoformat() if v else None }