""" Internal Transfer API Endpoints """ from fastapi import APIRouter, Depends, HTTPException, Body from typing import List, Optional, Dict, Any from datetime import date from sqlalchemy.ext.asyncio import AsyncSession from pydantic import BaseModel from app.services.internal_transfer_service import InternalTransferService from app.repositories.purchase_order_repository import PurchaseOrderRepository from app.core.database import get_db from shared.auth.tenant_access import verify_tenant_permission_dep from shared.clients import get_recipes_client, get_production_client, get_inventory_client from app.core.config import settings router = APIRouter() # Pydantic models for request validation class InternalTransferItem(BaseModel): product_id: str product_name: Optional[str] = None quantity: float unit_of_measure: str = 'units' class InternalTransferRequest(BaseModel): parent_tenant_id: str items: List[InternalTransferItem] delivery_date: str notes: Optional[str] = None class ApprovalRequest(BaseModel): pass # Empty for now, might add approval notes later def get_internal_transfer_service(db: AsyncSession = Depends(get_db)) -> InternalTransferService: """Dependency to get internal transfer service""" purchase_order_repository = PurchaseOrderRepository(db) recipe_client = get_recipes_client(config=settings, service_name="procurement-service") production_client = get_production_client(config=settings, service_name="procurement-service") inventory_client = get_inventory_client(config=settings, service_name="procurement-service") return InternalTransferService( purchase_order_repository=purchase_order_repository, recipe_client=recipe_client, production_client=production_client, inventory_client=inventory_client ) @router.post("/tenants/{tenant_id}/procurement/internal-transfers", response_model=None) async def create_internal_purchase_order( tenant_id: str, transfer_request: InternalTransferRequest, internal_transfer_service: InternalTransferService = Depends(get_internal_transfer_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Create an internal purchase order from child to parent tenant **Enterprise Tier Feature**: Internal transfers require Enterprise subscription. """ try: # Validate subscription tier for internal transfers from shared.subscription.plans import PlanFeatures from shared.clients import get_tenant_client tenant_client = get_tenant_client(config=settings, service_name="procurement-service") subscription = await tenant_client.get_tenant_subscription(tenant_id) if not subscription: raise HTTPException( status_code=403, detail="No active subscription found. Internal transfers require Enterprise tier." ) # Check if tier supports internal transfers if not PlanFeatures.validate_internal_transfers(subscription.get("plan", "starter")): raise HTTPException( status_code=403, detail=f"Internal transfers require Enterprise tier. Current tier: {subscription.get('plan', 'starter')}" ) # Parse delivery_date from datetime import datetime delivery_date = datetime.fromisoformat(transfer_request.delivery_date.split('T')[0]).date() # Convert Pydantic items to dict items = [item.model_dump() for item in transfer_request.items] # Create the internal purchase order result = await internal_transfer_service.create_internal_purchase_order( child_tenant_id=tenant_id, parent_tenant_id=transfer_request.parent_tenant_id, items=items, delivery_date=delivery_date, requested_by_user_id="temp_user_id", # Would come from auth context notes=transfer_request.notes ) return result except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to create internal purchase order: {str(e)}") @router.post("/tenants/{tenant_id}/procurement/internal-transfers/{po_id}/approve", response_model=None) async def approve_internal_transfer( tenant_id: str, po_id: str, approval_request: Optional[ApprovalRequest] = None, internal_transfer_service: InternalTransferService = Depends(get_internal_transfer_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Approve an internal transfer request """ try: approved_by_user_id = "temp_user_id" # Would come from auth context result = await internal_transfer_service.approve_internal_transfer( po_id=po_id, approved_by_user_id=approved_by_user_id ) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to approve internal transfer: {str(e)}") @router.get("/tenants/{tenant_id}/procurement/internal-transfers/pending", response_model=None) async def get_pending_internal_transfers( tenant_id: str, internal_transfer_service: InternalTransferService = Depends(get_internal_transfer_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Get pending internal transfers for a tenant """ try: result = await internal_transfer_service.get_pending_internal_transfers(tenant_id=tenant_id) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to get pending internal transfers: {str(e)}") @router.get("/tenants/{tenant_id}/procurement/internal-transfers/history", response_model=None) async def get_internal_transfer_history( tenant_id: str, parent_tenant_id: Optional[str] = None, child_tenant_id: Optional[str] = None, start_date: Optional[date] = None, end_date: Optional[date] = None, internal_transfer_service: InternalTransferService = Depends(get_internal_transfer_service), verified_tenant: str = Depends(verify_tenant_permission_dep) ): """ Get internal transfer history with optional filtering """ try: result = await internal_transfer_service.get_internal_transfer_history( tenant_id=tenant_id, parent_tenant_id=parent_tenant_id, child_tenant_id=child_tenant_id, start_date=start_date, end_date=end_date ) return result except Exception as e: raise HTTPException(status_code=500, detail=f"Failed to get internal transfer history: {str(e)}")