Files
bakery-ia/services/pos/app/models/pos_webhook.py

109 lines
4.9 KiB
Python

# services/pos/app/models/pos_webhook.py
"""
POS Webhook Log Model
Tracks webhook events from POS systems
"""
from sqlalchemy import Column, String, DateTime, Boolean, Integer, Text, JSON, Index
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
import uuid
from shared.database.base import Base
class POSWebhookLog(Base):
"""
Log of webhook events received from POS systems
"""
__tablename__ = "pos_webhook_logs"
# Primary identifiers
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
tenant_id = Column(UUID(as_uuid=True), nullable=True, index=True) # May be null until parsed
# POS Provider Information
pos_system = Column(String(50), nullable=False, index=True) # square, toast, lightspeed
webhook_type = Column(String(100), nullable=False, index=True) # payment.created, order.updated, etc.
# Request Information
method = Column(String(10), nullable=False) # POST, PUT, etc.
url_path = Column(String(500), nullable=False)
query_params = Column(JSON, nullable=True)
headers = Column(JSON, nullable=True)
# Payload
raw_payload = Column(Text, nullable=False) # Raw webhook payload
payload_size = Column(Integer, nullable=False, default=0)
content_type = Column(String(100), nullable=True)
# Security
signature = Column(String(500), nullable=True) # Webhook signature for verification
is_signature_valid = Column(Boolean, nullable=True) # null = not checked, true/false = verified
source_ip = Column(String(45), nullable=True) # IPv4 or IPv6
# Processing Status
status = Column(String(50), nullable=False, default="received", index=True) # received, processing, processed, failed
processing_started_at = Column(DateTime(timezone=True), nullable=True)
processing_completed_at = Column(DateTime(timezone=True), nullable=True)
processing_duration_ms = Column(Integer, nullable=True)
# Error Handling
error_message = Column(Text, nullable=True)
error_code = Column(String(50), nullable=True)
retry_count = Column(Integer, default=0, nullable=False)
max_retries = Column(Integer, default=3, nullable=False)
# Response Information
response_status_code = Column(Integer, nullable=True)
response_body = Column(Text, nullable=True)
response_sent_at = Column(DateTime(timezone=True), nullable=True)
# Event Metadata
event_id = Column(String(255), nullable=True, index=True) # POS system's event ID
event_timestamp = Column(DateTime(timezone=True), nullable=True) # When event occurred in POS
sequence_number = Column(Integer, nullable=True) # For ordered events
# Business Data References
transaction_id = Column(String(255), nullable=True, index=True) # Referenced transaction
order_id = Column(String(255), nullable=True, index=True) # Referenced order
customer_id = Column(String(255), nullable=True) # Referenced customer
# Internal References
created_transaction_id = Column(UUID(as_uuid=True), nullable=True) # Created POSTransaction record
updated_transaction_id = Column(UUID(as_uuid=True), nullable=True) # Updated POSTransaction record
# Duplicate Detection
is_duplicate = Column(Boolean, default=False, nullable=False, index=True)
duplicate_of = Column(UUID(as_uuid=True), nullable=True)
# Processing Priority
priority = Column(String(20), default="normal", nullable=False) # low, normal, high, urgent
# Debugging Information
user_agent = Column(String(500), nullable=True)
forwarded_for = Column(String(200), nullable=True) # X-Forwarded-For header
request_id = Column(String(100), nullable=True) # For request tracing
# Timestamps
received_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
# Indexes for performance
__table_args__ = (
Index('idx_webhook_pos_system_type', 'pos_system', 'webhook_type'),
Index('idx_webhook_status', 'status'),
Index('idx_webhook_event_id', 'event_id'),
Index('idx_webhook_received_at', 'received_at'),
Index('idx_webhook_tenant_received', 'tenant_id', 'received_at'),
Index('idx_webhook_transaction_id', 'transaction_id'),
Index('idx_webhook_order_id', 'order_id'),
Index('idx_webhook_duplicate', 'is_duplicate'),
Index('idx_webhook_priority', 'priority'),
Index('idx_webhook_retry', 'retry_count'),
Index('idx_webhook_signature_valid', 'is_signature_valid'),
)
def __repr__(self):
return f"<POSWebhookLog(id={self.id}, pos_system='{self.pos_system}', type='{self.webhook_type}', status='{self.status}')>"