Improve the frontend

This commit is contained in:
Urtzi Alfaro
2025-10-21 19:50:07 +02:00
parent 05da20357d
commit 8d30172483
105 changed files with 14699 additions and 4630 deletions

View 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)}")