/** * Recipes service - API communication layer * Handles all recipe-related HTTP requests using the API client */ import { apiClient } from '../client/apiClient'; import type { RecipeResponse, RecipeCreate, RecipeUpdate, RecipeSearchParams, RecipeDuplicateRequest, RecipeFeasibilityResponse, RecipeStatisticsResponse, RecipeCategoriesResponse, ProductionBatchResponse, ProductionBatchCreate, ProductionBatchUpdate, } from '../types/recipes'; /** * Recipes API service * All methods return promises that resolve to the response data */ export class RecipesService { private readonly baseUrl = '/recipes'; /** * Create a new recipe */ async createRecipe(recipeData: RecipeCreate): Promise { return apiClient.post(this.baseUrl, recipeData); } /** * Get recipe by ID with ingredients */ async getRecipe(recipeId: string): Promise { return apiClient.get(`${this.baseUrl}/${recipeId}`); } /** * Update an existing recipe */ async updateRecipe(recipeId: string, recipeData: RecipeUpdate): Promise { return apiClient.put(`${this.baseUrl}/${recipeId}`, recipeData); } /** * Delete a recipe */ async deleteRecipe(recipeId: string): Promise<{ message: string }> { return apiClient.delete<{ message: string }>(`${this.baseUrl}/${recipeId}`); } /** * Search recipes with filters */ async searchRecipes(params: RecipeSearchParams = {}): Promise { const searchParams = new URLSearchParams(); Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== '') { searchParams.append(key, String(value)); } }); const queryString = searchParams.toString(); const url = queryString ? `${this.baseUrl}?${queryString}` : this.baseUrl; return apiClient.get(url); } /** * Get all recipes (shorthand for search without filters) */ async getRecipes(): Promise { return this.searchRecipes(); } /** * Duplicate an existing recipe */ async duplicateRecipe(recipeId: string, duplicateData: RecipeDuplicateRequest): Promise { return apiClient.post(`${this.baseUrl}/${recipeId}/duplicate`, duplicateData); } /** * Activate a recipe for production */ async activateRecipe(recipeId: string): Promise { return apiClient.post(`${this.baseUrl}/${recipeId}/activate`); } /** * Check if recipe can be produced with current inventory */ async checkRecipeFeasibility(recipeId: string, batchMultiplier: number = 1.0): Promise { const params = new URLSearchParams({ batch_multiplier: String(batchMultiplier) }); return apiClient.get(`${this.baseUrl}/${recipeId}/feasibility?${params}`); } /** * Get recipe statistics for dashboard */ async getRecipeStatistics(): Promise { return apiClient.get(`${this.baseUrl}/statistics/dashboard`); } /** * Get list of recipe categories used by tenant */ async getRecipeCategories(): Promise { return apiClient.get(`${this.baseUrl}/categories/list`); } // Production Batch Methods /** * Create a production batch for a recipe */ async createProductionBatch(batchData: ProductionBatchCreate): Promise { return apiClient.post('/production/batches', batchData); } /** * Get production batch by ID */ async getProductionBatch(batchId: string): Promise { return apiClient.get(`/production/batches/${batchId}`); } /** * Update production batch */ async updateProductionBatch(batchId: string, batchData: ProductionBatchUpdate): Promise { return apiClient.put(`/production/batches/${batchId}`, batchData); } /** * Delete production batch */ async deleteProductionBatch(batchId: string): Promise<{ message: string }> { return apiClient.delete<{ message: string }>(`/production/batches/${batchId}`); } /** * Get production batches for a recipe */ async getRecipeProductionBatches(recipeId: string): Promise { return apiClient.get(`/production/batches?recipe_id=${recipeId}`); } /** * Get all production batches with optional filtering */ async getProductionBatches(params: { recipe_id?: string; status?: string; start_date?: string; end_date?: string; limit?: number; offset?: number; } = {}): Promise { const searchParams = new URLSearchParams(); Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== '') { searchParams.append(key, String(value)); } }); const queryString = searchParams.toString(); const url = queryString ? `/production/batches?${queryString}` : '/production/batches'; return apiClient.get(url); } /** * Start production batch */ async startProductionBatch(batchId: string): Promise { return apiClient.post(`/production/batches/${batchId}/start`); } /** * Complete production batch */ async completeProductionBatch( batchId: string, completionData: { actual_quantity?: number; quality_score?: number; quality_notes?: string; waste_quantity?: number; waste_reason?: string; } ): Promise { return apiClient.post(`/production/batches/${batchId}/complete`, completionData); } /** * Cancel production batch */ async cancelProductionBatch(batchId: string, reason?: string): Promise { return apiClient.post(`/production/batches/${batchId}/cancel`, { reason }); } } // Create and export singleton instance export const recipesService = new RecipesService(); export default recipesService;