Improve the frontend
This commit is contained in:
226
services/pos/app/api/internal_demo.py
Normal file
226
services/pos/app/api/internal_demo.py
Normal file
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
Internal Demo API Endpoints for POS Service
|
||||
Used by demo_session service to clone data for virtual demo tenants
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Header
|
||||
from typing import Dict, Any
|
||||
from uuid import UUID
|
||||
import structlog
|
||||
import os
|
||||
|
||||
from app.core.database import get_db
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from app.models.pos_config import POSConfiguration
|
||||
from app.models.pos_transaction import POSTransaction, POSTransactionItem
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
|
||||
router = APIRouter()
|
||||
logger = structlog.get_logger()
|
||||
|
||||
# Internal API key for service-to-service communication
|
||||
INTERNAL_API_KEY = os.getenv("INTERNAL_API_KEY", "dev-internal-key-change-in-production")
|
||||
|
||||
|
||||
def verify_internal_api_key(x_internal_api_key: str = Header(...)):
|
||||
"""Verify internal API key for service-to-service communication"""
|
||||
if x_internal_api_key != INTERNAL_API_KEY:
|
||||
raise HTTPException(status_code=403, detail="Invalid internal API key")
|
||||
return True
|
||||
|
||||
|
||||
@router.post("/internal/demo/clone")
|
||||
async def clone_demo_data(
|
||||
base_tenant_id: str,
|
||||
virtual_tenant_id: str,
|
||||
demo_account_type: str,
|
||||
session_id: Optional[str] = None,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: bool = Depends(verify_internal_api_key)
|
||||
):
|
||||
"""
|
||||
Clone POS demo data from base tenant to virtual tenant
|
||||
|
||||
This endpoint is called by the demo_session service during session initialization.
|
||||
It clones POS configurations and recent transactions.
|
||||
"""
|
||||
|
||||
start_time = datetime.now(timezone.utc)
|
||||
session_created_at = datetime.now(timezone.utc)
|
||||
|
||||
logger.info(
|
||||
"Starting POS data cloning with date adjustment",
|
||||
base_tenant_id=base_tenant_id,
|
||||
virtual_tenant_id=virtual_tenant_id,
|
||||
demo_account_type=demo_account_type,
|
||||
session_id=session_id,
|
||||
session_created_at=session_created_at.isoformat()
|
||||
)
|
||||
|
||||
try:
|
||||
base_uuid = uuid.UUID(base_tenant_id)
|
||||
virtual_uuid = uuid.UUID(virtual_tenant_id)
|
||||
|
||||
# Fetch base tenant POS configurations
|
||||
result = await db.execute(
|
||||
select(POSConfiguration).where(POSConfiguration.tenant_id == base_uuid)
|
||||
)
|
||||
base_configs = list(result.scalars().all())
|
||||
|
||||
configs_cloned = 0
|
||||
transactions_cloned = 0
|
||||
|
||||
# Clone each configuration
|
||||
for base_config in base_configs:
|
||||
# Create new config for virtual tenant
|
||||
new_config = POSConfiguration(
|
||||
id=uuid.uuid4(),
|
||||
tenant_id=virtual_uuid,
|
||||
pos_system=base_config.pos_system,
|
||||
provider_name=f"{base_config.provider_name} (Demo Session)",
|
||||
is_active=base_config.is_active,
|
||||
is_connected=base_config.is_connected,
|
||||
encrypted_credentials=base_config.encrypted_credentials,
|
||||
webhook_url=base_config.webhook_url,
|
||||
webhook_secret=base_config.webhook_secret,
|
||||
environment=base_config.environment,
|
||||
location_id=base_config.location_id,
|
||||
merchant_id=base_config.merchant_id,
|
||||
sync_enabled=base_config.sync_enabled,
|
||||
sync_interval_minutes=base_config.sync_interval_minutes,
|
||||
auto_sync_products=base_config.auto_sync_products,
|
||||
auto_sync_transactions=base_config.auto_sync_transactions,
|
||||
last_sync_at=base_config.last_sync_at,
|
||||
last_successful_sync_at=base_config.last_successful_sync_at,
|
||||
last_sync_status=base_config.last_sync_status,
|
||||
last_sync_message=base_config.last_sync_message,
|
||||
provider_settings=base_config.provider_settings,
|
||||
last_health_check_at=base_config.last_health_check_at,
|
||||
health_status=base_config.health_status,
|
||||
health_message=base_config.health_message,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc),
|
||||
notes=f"Cloned from base config {base_config.id} for demo session {session_id}"
|
||||
)
|
||||
|
||||
db.add(new_config)
|
||||
await db.flush()
|
||||
configs_cloned += 1
|
||||
|
||||
# Clone recent transactions for this config
|
||||
tx_result = await db.execute(
|
||||
select(POSTransaction)
|
||||
.where(POSTransaction.pos_config_id == base_config.id)
|
||||
.order_by(POSTransaction.transaction_date.desc())
|
||||
.limit(10) # Clone last 10 transactions
|
||||
)
|
||||
base_transactions = list(tx_result.scalars().all())
|
||||
|
||||
# Clone each transaction
|
||||
for base_tx in base_transactions:
|
||||
new_tx = POSTransaction(
|
||||
id=uuid.uuid4(),
|
||||
tenant_id=virtual_uuid,
|
||||
pos_config_id=new_config.id,
|
||||
pos_system=base_tx.pos_system,
|
||||
external_transaction_id=base_tx.external_transaction_id,
|
||||
external_order_id=base_tx.external_order_id,
|
||||
transaction_type=base_tx.transaction_type,
|
||||
status=base_tx.status,
|
||||
subtotal=base_tx.subtotal,
|
||||
tax_amount=base_tx.tax_amount,
|
||||
tip_amount=base_tx.tip_amount,
|
||||
discount_amount=base_tx.discount_amount,
|
||||
total_amount=base_tx.total_amount,
|
||||
currency=base_tx.currency,
|
||||
payment_method=base_tx.payment_method,
|
||||
payment_status=base_tx.payment_status,
|
||||
transaction_date=base_tx.transaction_date,
|
||||
pos_created_at=base_tx.pos_created_at,
|
||||
pos_updated_at=base_tx.pos_updated_at,
|
||||
location_id=base_tx.location_id,
|
||||
location_name=base_tx.location_name,
|
||||
staff_id=base_tx.staff_id,
|
||||
staff_name=base_tx.staff_name,
|
||||
customer_id=base_tx.customer_id,
|
||||
customer_email=base_tx.customer_email,
|
||||
customer_phone=base_tx.customer_phone,
|
||||
order_type=base_tx.order_type,
|
||||
table_number=base_tx.table_number,
|
||||
receipt_number=base_tx.receipt_number,
|
||||
is_synced_to_sales=base_tx.is_synced_to_sales,
|
||||
sales_record_id=base_tx.sales_record_id,
|
||||
sync_attempted_at=base_tx.sync_attempted_at,
|
||||
sync_completed_at=base_tx.sync_completed_at,
|
||||
sync_error=base_tx.sync_error,
|
||||
sync_retry_count=base_tx.sync_retry_count,
|
||||
raw_data=base_tx.raw_data,
|
||||
is_processed=base_tx.is_processed,
|
||||
processing_error=base_tx.processing_error,
|
||||
is_duplicate=base_tx.is_duplicate,
|
||||
duplicate_of=base_tx.duplicate_of,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.add(new_tx)
|
||||
await db.flush()
|
||||
transactions_cloned += 1
|
||||
|
||||
# Clone transaction items
|
||||
item_result = await db.execute(
|
||||
select(POSTransactionItem).where(POSTransactionItem.transaction_id == base_tx.id)
|
||||
)
|
||||
base_items = list(item_result.scalars().all())
|
||||
|
||||
for base_item in base_items:
|
||||
new_item = POSTransactionItem(
|
||||
id=uuid.uuid4(),
|
||||
transaction_id=new_tx.id,
|
||||
tenant_id=virtual_uuid,
|
||||
external_item_id=base_item.external_item_id,
|
||||
sku=base_item.sku,
|
||||
product_name=base_item.product_name,
|
||||
product_category=base_item.product_category,
|
||||
product_subcategory=base_item.product_subcategory,
|
||||
quantity=base_item.quantity,
|
||||
unit_price=base_item.unit_price,
|
||||
total_price=base_item.total_price,
|
||||
discount_amount=base_item.discount_amount,
|
||||
tax_amount=base_item.tax_amount,
|
||||
modifiers=base_item.modifiers,
|
||||
inventory_product_id=base_item.inventory_product_id,
|
||||
is_mapped_to_inventory=base_item.is_mapped_to_inventory,
|
||||
is_synced_to_sales=base_item.is_synced_to_sales,
|
||||
sync_error=base_item.sync_error,
|
||||
raw_data=base_item.raw_data,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
updated_at=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
db.add(new_item)
|
||||
|
||||
await db.commit()
|
||||
|
||||
logger.info(
|
||||
"POS demo data cloned successfully",
|
||||
virtual_tenant_id=str(virtual_tenant_id),
|
||||
configs_cloned=configs_cloned,
|
||||
transactions_cloned=transactions_cloned
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"records_cloned": configs_cloned + transactions_cloned,
|
||||
"configs_cloned": configs_cloned,
|
||||
"transactions_cloned": transactions_cloned,
|
||||
"service": "pos"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to clone POS demo data", error=str(e), exc_info=True)
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=500, detail=f"Failed to clone POS demo data: {str(e)}")
|
||||
Reference in New Issue
Block a user