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:
1
artery/shunts/amar/api/__init__.py
Normal file
1
artery/shunts/amar/api/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""API routes for Amar mock vein."""
|
||||
302
artery/shunts/amar/api/routes.py
Normal file
302
artery/shunts/amar/api/routes.py
Normal 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,
|
||||
}
|
||||
Reference in New Issue
Block a user