// ================================================================ // frontend/src/api/services/procurement-service.ts // ================================================================ /** * Procurement Service - Fully aligned with backend Procurement Service API * * Backend API: services/procurement/app/api/ * - procurement_plans.py: Plan CRUD and generation * - analytics.py: Analytics and dashboard * - purchase_orders.py: PO creation from plans * * Base URL: /api/v1/tenants/{tenant_id}/procurement/* * * Last Updated: 2025-10-31 * Status: ✅ Complete - 100% backend alignment */ import { apiClient } from '../client/apiClient'; import { // Procurement Plan types ProcurementPlanResponse, ProcurementPlanCreate, ProcurementPlanUpdate, PaginatedProcurementPlans, // Procurement Requirement types ProcurementRequirementResponse, ProcurementRequirementUpdate, // Dashboard & Analytics types ProcurementDashboardData, ProcurementTrendsData, // Request/Response types GeneratePlanRequest, GeneratePlanResponse, AutoGenerateProcurementRequest, AutoGenerateProcurementResponse, CreatePOsResult, LinkRequirementToPORequest, UpdateDeliveryStatusRequest, ApprovalRequest, RejectionRequest, // Query parameter types GetProcurementPlansParams, GetPlanRequirementsParams, UpdatePlanStatusParams, } from '../types/procurement'; /** * Procurement Service * All methods use the standalone Procurement Service backend API */ export class ProcurementService { // =================================================================== // ANALYTICS & DASHBOARD // Backend: services/procurement/app/api/analytics.py // =================================================================== /** * Get procurement analytics dashboard data * GET /api/v1/tenants/{tenant_id}/procurement/analytics/procurement */ static async getProcurementAnalytics(tenantId: string): Promise { return apiClient.get(`/tenants/${tenantId}/procurement/analytics/procurement`); } /** * Get procurement time-series trends for charts * GET /api/v1/tenants/{tenant_id}/procurement/analytics/procurement/trends */ static async getProcurementTrends(tenantId: string, days: number = 7): Promise { return apiClient.get(`/tenants/${tenantId}/procurement/analytics/procurement/trends?days=${days}`); } // =================================================================== // PROCUREMENT PLAN GENERATION // Backend: services/procurement/app/api/procurement_plans.py // =================================================================== /** * Auto-generate procurement plan from forecast data (Orchestrator integration) * POST /api/v1/tenants/{tenant_id}/procurement/auto-generate * * Called by Orchestrator Service to create procurement plans based on forecast data */ static async autoGenerateProcurement( tenantId: string, request: AutoGenerateProcurementRequest ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/auto-generate`, request ); } /** * Generate a new procurement plan (manual/UI-driven) * POST /api/v1/tenants/{tenant_id}/procurement/plans/generate */ static async generateProcurementPlan( tenantId: string, request: GeneratePlanRequest ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/plans/generate`, request ); } // =================================================================== // PROCUREMENT PLAN CRUD // Backend: services/procurement/app/api/procurement_plans.py // =================================================================== /** * Get the current day's procurement plan * GET /api/v1/tenants/{tenant_id}/procurement/plans/current */ static async getCurrentProcurementPlan(tenantId: string): Promise { return apiClient.get( `/tenants/${tenantId}/procurement/plans/current` ); } /** * Get procurement plan by ID * GET /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id} */ static async getProcurementPlanById( tenantId: string, planId: string ): Promise { return apiClient.get( `/tenants/${tenantId}/procurement/plans/${planId}` ); } /** * Get procurement plan for a specific date * GET /api/v1/tenants/{tenant_id}/procurement/plans/date/{plan_date} */ static async getProcurementPlanByDate( tenantId: string, planDate: string ): Promise { return apiClient.get( `/tenants/${tenantId}/procurement/plans/date/${planDate}` ); } /** * List all procurement plans for tenant with pagination and filtering * GET /api/v1/tenants/{tenant_id}/procurement/plans */ static async getProcurementPlans(params: GetProcurementPlansParams): Promise { const { tenant_id, status, start_date, end_date, limit = 50, offset = 0 } = params; const queryParams = new URLSearchParams({ limit: limit.toString(), offset: offset.toString(), }); if (status) queryParams.append('status', status); if (start_date) queryParams.append('start_date', start_date); if (end_date) queryParams.append('end_date', end_date); return apiClient.get( `/tenants/${tenant_id}/procurement/plans?${queryParams.toString()}` ); } /** * Update procurement plan status * PATCH /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/status */ static async updateProcurementPlanStatus(params: UpdatePlanStatusParams): Promise { const { tenant_id, plan_id, status, notes } = params; const queryParams = new URLSearchParams({ status }); if (notes) queryParams.append('notes', notes); return apiClient.patch( `/tenants/${tenant_id}/procurement/plans/${plan_id}/status?${queryParams.toString()}`, {} ); } // =================================================================== // PROCUREMENT REQUIREMENTS // Backend: services/procurement/app/api/procurement_plans.py // =================================================================== /** * Get all requirements for a procurement plan * GET /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/requirements */ static async getPlanRequirements(params: GetPlanRequirementsParams): Promise { const { tenant_id, plan_id, status, priority } = params; const queryParams = new URLSearchParams(); if (status) queryParams.append('status', status); if (priority) queryParams.append('priority', priority); const url = `/tenants/${tenant_id}/procurement/plans/${plan_id}/requirements${ queryParams.toString() ? `?${queryParams.toString()}` : '' }`; return apiClient.get(url); } /** * Get critical requirements across all plans * GET /api/v1/tenants/{tenant_id}/procurement/requirements/critical */ static async getCriticalRequirements(tenantId: string): Promise { return apiClient.get( `/tenants/${tenantId}/procurement/requirements/critical` ); } /** * Link a procurement requirement to a purchase order * POST /api/v1/tenants/{tenant_id}/procurement/requirements/{requirement_id}/link-purchase-order */ static async linkRequirementToPurchaseOrder( tenantId: string, requirementId: string, request: LinkRequirementToPORequest ): Promise<{ success: boolean; message: string; requirement_id: string; purchase_order_id: string }> { return apiClient.post<{ success: boolean; message: string; requirement_id: string; purchase_order_id: string; }>( `/tenants/${tenantId}/procurement/requirements/${requirementId}/link-purchase-order`, request ); } /** * Update delivery status for a requirement * PUT /api/v1/tenants/{tenant_id}/procurement/requirements/{requirement_id}/delivery-status */ static async updateRequirementDeliveryStatus( tenantId: string, requirementId: string, request: UpdateDeliveryStatusRequest ): Promise<{ success: boolean; message: string; requirement_id: string; delivery_status: string }> { return apiClient.put<{ success: boolean; message: string; requirement_id: string; delivery_status: string; }>( `/tenants/${tenantId}/procurement/requirements/${requirementId}/delivery-status`, request ); } // =================================================================== // ADVANCED PROCUREMENT OPERATIONS // Backend: services/procurement/app/api/procurement_plans.py // =================================================================== /** * Recalculate an existing procurement plan * POST /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/recalculate */ static async recalculateProcurementPlan( tenantId: string, planId: string ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/plans/${planId}/recalculate`, {} ); } /** * Approve a procurement plan with optional notes * POST /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/approve */ static async approveProcurementPlan( tenantId: string, planId: string, request?: ApprovalRequest ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/plans/${planId}/approve`, request || {} ); } /** * Reject a procurement plan with optional notes * POST /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/reject */ static async rejectProcurementPlan( tenantId: string, planId: string, request?: RejectionRequest ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/plans/${planId}/reject`, request || {} ); } // =================================================================== // PURCHASE ORDERS // Backend: services/procurement/app/api/purchase_orders.py // =================================================================== /** * Create purchase orders from procurement plan requirements * Groups requirements by supplier and creates POs * POST /api/v1/tenants/{tenant_id}/procurement/plans/{plan_id}/create-purchase-orders */ static async createPurchaseOrdersFromPlan( tenantId: string, planId: string, autoApprove: boolean = false ): Promise { return apiClient.post( `/tenants/${tenantId}/procurement/plans/${planId}/create-purchase-orders`, { auto_approve: autoApprove } ); } } export default ProcurementService;