/** * Product Transformation Service - Handle transformation operations */ import { apiClient } from '../client'; import { ProductTransformationCreate, ProductTransformationResponse, ProductionStage, } from '../types/inventory'; export class TransformationService { private readonly baseUrl = '/tenants'; // Product Transformation Operations async createTransformation( tenantId: string, transformationData: ProductTransformationCreate ): Promise { return apiClient.post( `${this.baseUrl}/${tenantId}/transformations`, transformationData ); } async getTransformation( tenantId: string, transformationId: string ): Promise { return apiClient.get( `${this.baseUrl}/${tenantId}/transformations/${transformationId}` ); } async getTransformations( tenantId: string, options?: { skip?: number; limit?: number; ingredient_id?: string; source_stage?: ProductionStage; target_stage?: ProductionStage; days_back?: number; } ): Promise { const queryParams = new URLSearchParams(); if (options?.skip !== undefined) queryParams.append('skip', options.skip.toString()); if (options?.limit !== undefined) queryParams.append('limit', options.limit.toString()); if (options?.ingredient_id) queryParams.append('ingredient_id', options.ingredient_id); if (options?.source_stage) queryParams.append('source_stage', options.source_stage); if (options?.target_stage) queryParams.append('target_stage', options.target_stage); if (options?.days_back !== undefined) queryParams.append('days_back', options.days_back.toString()); const url = queryParams.toString() ? `${this.baseUrl}/${tenantId}/transformations?${queryParams.toString()}` : `${this.baseUrl}/${tenantId}/transformations`; return apiClient.get(url); } async getTransformationSummary( tenantId: string, daysBack: number = 30 ): Promise { const queryParams = new URLSearchParams(); queryParams.append('days_back', daysBack.toString()); return apiClient.get( `${this.baseUrl}/${tenantId}/transformations/summary?${queryParams.toString()}` ); } // Convenience Methods for Common Transformations async createParBakeToFreshTransformation( tenantId: string, options: { source_ingredient_id: string; target_ingredient_id: string; quantity: number; target_batch_number?: string; expiration_hours?: number; notes?: string; } ): Promise<{ transformation_id: string; transformation_reference: string; source_quantity: number; target_quantity: number; expiration_date: string; message: string; }> { const queryParams = new URLSearchParams(); queryParams.append('source_ingredient_id', options.source_ingredient_id); queryParams.append('target_ingredient_id', options.target_ingredient_id); queryParams.append('quantity', options.quantity.toString()); if (options.target_batch_number) { queryParams.append('target_batch_number', options.target_batch_number); } if (options.expiration_hours !== undefined) { queryParams.append('expiration_hours', options.expiration_hours.toString()); } if (options.notes) { queryParams.append('notes', options.notes); } return apiClient.post( `${this.baseUrl}/${tenantId}/transformations/par-bake-to-fresh?${queryParams.toString()}` ); } async bakeParBakedCroissants( tenantId: string, parBakedIngredientId: string, freshBakedIngredientId: string, quantity: number, expirationHours: number = 24, notes?: string ): Promise { return this.createTransformation(tenantId, { source_ingredient_id: parBakedIngredientId, target_ingredient_id: freshBakedIngredientId, source_stage: ProductionStage.PAR_BAKED, target_stage: ProductionStage.FULLY_BAKED, source_quantity: quantity, target_quantity: quantity, // Assume 1:1 ratio for croissants expiration_calculation_method: 'days_from_transformation', expiration_days_offset: Math.max(1, Math.floor(expirationHours / 24)), process_notes: notes || `Baked ${quantity} par-baked croissants to fresh croissants`, }); } async transformFrozenToPrepared( tenantId: string, frozenIngredientId: string, preparedIngredientId: string, quantity: number, notes?: string ): Promise { return this.createTransformation(tenantId, { source_ingredient_id: frozenIngredientId, target_ingredient_id: preparedIngredientId, source_stage: ProductionStage.FROZEN_PRODUCT, target_stage: ProductionStage.PREPARED_DOUGH, source_quantity: quantity, target_quantity: quantity, expiration_calculation_method: 'days_from_transformation', expiration_days_offset: 3, // Prepared dough typically lasts 3 days process_notes: notes || `Thawed and prepared ${quantity} frozen products`, }); } // Analytics and Reporting async getTransformationsByStage( tenantId: string, sourceStage?: ProductionStage, targetStage?: ProductionStage, limit: number = 50 ): Promise { return this.getTransformations(tenantId, { source_stage: sourceStage, target_stage: targetStage, limit, }); } async getTransformationsForIngredient( tenantId: string, ingredientId: string, limit: number = 50 ): Promise { return this.getTransformations(tenantId, { ingredient_id: ingredientId, limit, }); } } export const transformationService = new TransformationService();