Improve the inventory page
This commit is contained in:
180
frontend/src/api/services/transformations.ts
Normal file
180
frontend/src/api/services/transformations.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* 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<ProductTransformationResponse> {
|
||||
return apiClient.post<ProductTransformationResponse>(
|
||||
`${this.baseUrl}/${tenantId}/transformations`,
|
||||
transformationData
|
||||
);
|
||||
}
|
||||
|
||||
async getTransformation(
|
||||
tenantId: string,
|
||||
transformationId: string
|
||||
): Promise<ProductTransformationResponse> {
|
||||
return apiClient.get<ProductTransformationResponse>(
|
||||
`${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<ProductTransformationResponse[]> {
|
||||
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<ProductTransformationResponse[]>(url);
|
||||
}
|
||||
|
||||
async getTransformationSummary(
|
||||
tenantId: string,
|
||||
daysBack: number = 30
|
||||
): Promise<any> {
|
||||
const queryParams = new URLSearchParams();
|
||||
queryParams.append('days_back', daysBack.toString());
|
||||
|
||||
return apiClient.get<any>(
|
||||
`${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<any>(
|
||||
`${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<ProductTransformationResponse> {
|
||||
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<ProductTransformationResponse> {
|
||||
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<ProductTransformationResponse[]> {
|
||||
return this.getTransformations(tenantId, {
|
||||
source_stage: sourceStage,
|
||||
target_stage: targetStage,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
|
||||
async getTransformationsForIngredient(
|
||||
tenantId: string,
|
||||
ingredientId: string,
|
||||
limit: number = 50
|
||||
): Promise<ProductTransformationResponse[]> {
|
||||
return this.getTransformations(tenantId, {
|
||||
ingredient_id: ingredientId,
|
||||
limit,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const transformationService = new TransformationService();
|
||||
Reference in New Issue
Block a user