refactor: separate standalone and managed room configs

- veins → shunts rename
- add cfg/standalone/ and cfg/<room>/ structure
- remove old data/*.json (moved to cfg/<room>/data/)
- update build.py and ctrl scripts
This commit is contained in:
buenosairesam
2026-01-02 17:09:58 -03:00
parent 46dc78db0e
commit 9e5cbbad1f
57 changed files with 1788 additions and 150 deletions

View File

@@ -0,0 +1,302 @@
"""API routes for Amar (MOCK) vein - Mock Amar API for testing."""
import asyncio
import random
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import JSONResponse
from typing import Optional, List, Dict, Any
from pydantic import BaseModel
# Import datagen from ward/tools
import sys
from pathlib import Path
ward_tools_path = Path(__file__).parent.parent.parent.parent.parent / "ward" / "tools"
sys.path.insert(0, str(ward_tools_path))
from datagen.amar import AmarDataGenerator
from ..core.config import settings
router = APIRouter()
# In-memory storage for mock data (reset on restart)
MOCK_DB = {
"petowners": {},
"pets": {},
"carts": {},
"service_requests": {},
}
# Request/Response Models
class CreatePetOwnerRequest(BaseModel):
address: str
email: Optional[str] = None
phone: Optional[str] = None
class CreatePetRequest(BaseModel):
owner_id: int
name: str
species: str # DOG, CAT
age: Optional[int] = None
age_unit: str = "years" # years, months
class CreateCartRequest(BaseModel):
owner_id: int
class AddCartItemRequest(BaseModel):
service_id: int
pet_id: int
quantity: int = 1
async def _mock_delay():
"""Add realistic delay if enabled."""
if settings.enable_random_delays:
delay_ms = random.randint(settings.min_delay_ms, settings.max_delay_ms)
await asyncio.sleep(delay_ms / 1000)
def _maybe_error():
"""Randomly raise an error based on error_rate."""
if random.random() < settings.error_rate:
raise HTTPException(500, "Mock error: Simulated failure")
@router.get("/health")
async def health():
"""Health check endpoint."""
return {
"status": "ok",
"vein": "Amar\n(MOCK)",
"message": "Mock Amar API for testing",
"_mock": True,
}
@router.post("/api/v1/pet-owners/")
async def create_petowner(request: CreatePetOwnerRequest):
"""Create a guest petowner (VET-536)."""
await _mock_delay()
_maybe_error()
owner = AmarDataGenerator.petowner(
address=request.address,
is_guest=True,
email=request.email,
phone=request.phone,
)
# Store in mock DB
MOCK_DB["petowners"][owner["id"]] = owner
owner["_mock"] = True
return owner
@router.get("/api/v1/pet-owners/{owner_id}")
async def get_petowner(owner_id: int):
"""Get petowner by ID."""
await _mock_delay()
_maybe_error()
owner = MOCK_DB["petowners"].get(owner_id)
if not owner:
raise HTTPException(404, f"PetOwner {owner_id} not found")
return owner
@router.post("/api/v1/pets/")
async def create_pet(request: CreatePetRequest):
"""Create a pet (VET-537)."""
await _mock_delay()
_maybe_error()
# Verify owner exists
if request.owner_id not in MOCK_DB["petowners"]:
raise HTTPException(404, f"Owner {request.owner_id} not found")
pet = AmarDataGenerator.pet(
owner_id=request.owner_id,
name=request.name,
species=request.species,
age_value=request.age,
age_unit=request.age_unit,
)
# Store in mock DB
MOCK_DB["pets"][pet["id"]] = pet
pet["_mock"] = True
return pet
@router.get("/api/v1/pets/{pet_id}")
async def get_pet(pet_id: int):
"""Get pet by ID."""
await _mock_delay()
_maybe_error()
pet = MOCK_DB["pets"].get(pet_id)
if not pet:
raise HTTPException(404, f"Pet {pet_id} not found")
return pet
@router.post("/api/v1/cart/")
async def create_cart(request: CreateCartRequest):
"""Create a cart (VET-538)."""
await _mock_delay()
_maybe_error()
# Verify owner exists
if request.owner_id not in MOCK_DB["petowners"]:
raise HTTPException(404, f"Owner {request.owner_id} not found")
cart = AmarDataGenerator.cart(owner_id=request.owner_id)
# Store in mock DB
MOCK_DB["carts"][cart["id"]] = cart
cart["_mock"] = True
return cart
@router.post("/api/v1/cart/{cart_id}/items/")
async def add_cart_item(cart_id: int, request: AddCartItemRequest):
"""Add item to cart and recalculate summary."""
await _mock_delay()
_maybe_error()
cart = MOCK_DB["carts"].get(cart_id)
if not cart:
raise HTTPException(404, f"Cart {cart_id} not found")
# Get service price
services = AmarDataGenerator.SERVICES
service = next((s for s in services if s["id"] == request.service_id), None)
if not service:
raise HTTPException(404, f"Service {request.service_id} not found")
# Add item
item = {
"service_id": request.service_id,
"service_name": service["name"],
"pet_id": request.pet_id,
"quantity": request.quantity,
"price": service["price"],
}
cart["items"].append(item)
# Recalculate summary
cart = AmarDataGenerator.calculate_cart_summary(cart, cart["items"])
MOCK_DB["carts"][cart_id] = cart
cart["_mock"] = True
return cart
@router.get("/api/v1/cart/{cart_id}")
async def get_cart(cart_id: int):
"""Get cart by ID."""
await _mock_delay()
_maybe_error()
cart = MOCK_DB["carts"].get(cart_id)
if not cart:
raise HTTPException(404, f"Cart {cart_id} not found")
return cart
@router.get("/api/v1/services/")
async def list_services(
species: Optional[str] = Query(None),
neighborhood_id: Optional[int] = Query(None),
):
"""List available services filtered by species and neighborhood (VET-540)."""
await _mock_delay()
_maybe_error()
services = AmarDataGenerator.filter_services(
species=species,
neighborhood_id=neighborhood_id,
)
for service in services:
service["_mock"] = True
return services
@router.get("/api/v1/categories/")
async def list_categories(
species: Optional[str] = Query(None),
neighborhood_id: Optional[int] = Query(None),
):
"""List categories with available services (VET-539)."""
await _mock_delay()
_maybe_error()
categories = AmarDataGenerator.filter_categories(
species=species,
neighborhood_id=neighborhood_id,
)
for category in categories:
category["_mock"] = True
return categories
@router.post("/solicitudes/service-requests/")
async def create_service_request(cart_id: int, requested_date: Optional[str] = None):
"""Create a service request."""
await _mock_delay()
_maybe_error()
cart = MOCK_DB["carts"].get(cart_id)
if not cart:
raise HTTPException(404, f"Cart {cart_id} not found")
request = AmarDataGenerator.service_request(
cart_id=cart_id,
requested_date=requested_date,
)
MOCK_DB["service_requests"][request["id"]] = request
request["_mock"] = True
return request
@router.get("/mock/reset")
async def reset_mock_db():
"""Reset the mock database (useful for testing)."""
MOCK_DB["petowners"].clear()
MOCK_DB["pets"].clear()
MOCK_DB["carts"].clear()
MOCK_DB["service_requests"].clear()
return {
"message": "Mock database reset",
"_mock": True,
}
@router.get("/mock/stats")
async def mock_stats():
"""Get mock database statistics."""
return {
"petowners": len(MOCK_DB["petowners"]),
"pets": len(MOCK_DB["pets"]),
"carts": len(MOCK_DB["carts"]),
"service_requests": len(MOCK_DB["service_requests"]),
"_mock": True,
}