Initial commit - production deployment
This commit is contained in:
248
services/pos/app/schemas/pos_transaction.py
Normal file
248
services/pos/app/schemas/pos_transaction.py
Normal file
@@ -0,0 +1,248 @@
|
||||
"""
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user