Files
bakery-ia/frontend/src/api/services/production.ts

431 lines
15 KiB
TypeScript
Raw Normal View History

2025-10-06 15:27:01 +02:00
// ================================================================
// frontend/src/api/services/production.ts
// ================================================================
2025-09-23 12:49:35 +02:00
/**
2025-10-06 15:27:01 +02:00
* Production Service - Complete backend alignment
*
* Backend API structure (3-tier architecture):
* - ATOMIC: production_batches.py, production_schedules.py
* - OPERATIONS: production_operations.py (batch lifecycle, capacity management)
* - ANALYTICS: analytics.py, production_dashboard.py
*
* Last Updated: 2025-10-05
* Status: Complete - Zero drift with backend
2025-09-23 12:49:35 +02:00
*/
2025-10-06 15:27:01 +02:00
2025-09-23 12:49:35 +02:00
import { apiClient } from '../client/apiClient';
import {
2025-10-06 15:27:01 +02:00
// Batches
2025-09-23 12:49:35 +02:00
ProductionBatchResponse,
2025-09-10 08:00:50 +02:00
ProductionBatchCreate,
2025-09-23 12:49:35 +02:00
ProductionBatchUpdate,
2025-09-10 08:00:50 +02:00
ProductionBatchStatusUpdate,
ProductionBatchListResponse,
2025-09-23 12:49:35 +02:00
ProductionBatchFilters,
2025-10-06 15:27:01 +02:00
BatchStatistics,
// Schedules
2025-09-23 12:49:35 +02:00
ProductionScheduleResponse,
ProductionScheduleCreate,
ProductionScheduleUpdate,
ProductionScheduleFilters,
2025-10-06 15:27:01 +02:00
// Capacity
2025-09-23 12:49:35 +02:00
ProductionCapacityResponse,
ProductionCapacityFilters,
2025-10-06 15:27:01 +02:00
// Quality
2025-09-23 12:49:35 +02:00
QualityCheckResponse,
QualityCheckCreate,
QualityCheckFilters,
2025-10-06 15:27:01 +02:00
// Analytics
2025-09-23 12:49:35 +02:00
ProductionPerformanceAnalytics,
YieldTrendsAnalytics,
TopDefectsAnalytics,
EquipmentEfficiencyAnalytics,
CapacityBottlenecks,
2025-10-06 15:27:01 +02:00
// Dashboard
2025-09-10 08:00:50 +02:00
ProductionDashboardSummary,
} from '../types/production';
export class ProductionService {
2025-10-06 15:27:01 +02:00
private baseUrl = '/tenants';
2025-09-23 12:49:35 +02:00
2025-10-06 15:27:01 +02:00
// ===================================================================
// ATOMIC: Production Batches CRUD
// Backend: services/production/app/api/production_batches.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getBatches(
tenantId: string,
filters?: ProductionBatchFilters
): Promise<ProductionBatchListResponse> {
const params = new URLSearchParams();
if (filters?.status) params.append('status', filters.status);
if (filters?.product_id) params.append('product_id', filters.product_id);
if (filters?.order_id) params.append('order_id', filters.order_id);
if (filters?.start_date) params.append('start_date', filters.start_date);
if (filters?.end_date) params.append('end_date', filters.end_date);
if (filters?.page) params.append('page', filters.page.toString());
if (filters?.page_size) params.append('page_size', filters.page_size.toString());
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/batches${queryString ? `?${queryString}` : ''}`;
2025-09-10 08:00:50 +02:00
2025-09-23 12:49:35 +02:00
return apiClient.get<ProductionBatchListResponse>(url);
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
async getBatch(tenantId: string, batchId: string): Promise<ProductionBatchResponse> {
2025-10-06 15:27:01 +02:00
return apiClient.get<ProductionBatchResponse>(
`${this.baseUrl}/${tenantId}/production/batches/${batchId}`
);
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
async createBatch(
tenantId: string,
batchData: ProductionBatchCreate
): Promise<ProductionBatchResponse> {
return apiClient.post<ProductionBatchResponse>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/batches`,
2025-09-23 12:49:35 +02:00
batchData
);
}
async updateBatch(
tenantId: string,
batchId: string,
batchData: ProductionBatchUpdate
): Promise<ProductionBatchResponse> {
return apiClient.put<ProductionBatchResponse>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/batches/${batchId}`,
2025-09-23 12:49:35 +02:00
batchData
);
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
async deleteBatch(tenantId: string, batchId: string): Promise<void> {
2025-10-06 15:27:01 +02:00
return apiClient.delete<void>(`${this.baseUrl}/${tenantId}/production/batches/${batchId}`);
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
async getBatchStatistics(
2025-09-10 08:00:50 +02:00
tenantId: string,
startDate?: string,
endDate?: string
2025-09-23 12:49:35 +02:00
): Promise<BatchStatistics> {
const params = new URLSearchParams();
if (startDate) params.append('start_date', startDate);
if (endDate) params.append('end_date', endDate);
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/batches/stats${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get<BatchStatistics>(url);
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// ATOMIC: Production Schedules CRUD
// Backend: services/production/app/api/production_schedules.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getSchedules(
tenantId: string,
filters?: ProductionScheduleFilters
): Promise<{ schedules: ProductionScheduleResponse[]; total_count: number; page: number; page_size: number }> {
const params = new URLSearchParams();
if (filters?.start_date) params.append('start_date', filters.start_date);
if (filters?.end_date) params.append('end_date', filters.end_date);
2025-10-06 15:27:01 +02:00
if (filters?.is_finalized !== undefined)
params.append('is_finalized', filters.is_finalized.toString());
2025-09-23 12:49:35 +02:00
if (filters?.page) params.append('page', filters.page.toString());
if (filters?.page_size) params.append('page_size', filters.page_size.toString());
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/schedules${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get(url);
}
async getSchedule(tenantId: string, scheduleId: string): Promise<ProductionScheduleResponse> {
2025-10-06 15:27:01 +02:00
return apiClient.get<ProductionScheduleResponse>(
`${this.baseUrl}/${tenantId}/production/schedules/${scheduleId}`
);
2025-09-23 12:49:35 +02:00
}
async createSchedule(
tenantId: string,
scheduleData: ProductionScheduleCreate
): Promise<ProductionScheduleResponse> {
return apiClient.post<ProductionScheduleResponse>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/schedules`,
2025-09-23 12:49:35 +02:00
scheduleData
);
}
async updateSchedule(
tenantId: string,
scheduleId: string,
scheduleData: ProductionScheduleUpdate
): Promise<ProductionScheduleResponse> {
return apiClient.put<ProductionScheduleResponse>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/schedules/${scheduleId}`,
2025-09-23 12:49:35 +02:00
scheduleData
);
}
async deleteSchedule(tenantId: string, scheduleId: string): Promise<void> {
2025-10-06 15:27:01 +02:00
return apiClient.delete<void>(`${this.baseUrl}/${tenantId}/production/schedules/${scheduleId}`);
2025-09-23 12:49:35 +02:00
}
2025-10-06 15:27:01 +02:00
async getTodaysSchedule(tenantId: string): Promise<ProductionScheduleResponse | null> {
return apiClient.get<ProductionScheduleResponse | null>(
`${this.baseUrl}/${tenantId}/production/schedules/today`
2025-09-23 12:49:35 +02:00
);
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// OPERATIONS: Batch Lifecycle Management
// Backend: services/production/app/api/production_operations.py
// ===================================================================
async updateBatchStatus(
tenantId: string,
batchId: string,
statusData: ProductionBatchStatusUpdate
): Promise<ProductionBatchResponse> {
return apiClient.patch<ProductionBatchResponse>(
`${this.baseUrl}/${tenantId}/production/batches/${batchId}/status`,
statusData
);
}
async startBatch(tenantId: string, batchId: string): Promise<ProductionBatchResponse> {
return apiClient.post<ProductionBatchResponse>(
`${this.baseUrl}/${tenantId}/production/batches/${batchId}/start`
);
}
async completeBatch(
tenantId: string,
batchId: string,
completionData?: { actual_quantity?: number; notes?: string }
): Promise<ProductionBatchResponse> {
return apiClient.post<ProductionBatchResponse>(
`${this.baseUrl}/${tenantId}/production/batches/${batchId}/complete`,
completionData || {}
);
}
async finalizeSchedule(tenantId: string, scheduleId: string): Promise<ProductionScheduleResponse> {
return apiClient.post<ProductionScheduleResponse>(
`${this.baseUrl}/${tenantId}/production/schedules/${scheduleId}/finalize`
);
2025-09-23 12:49:35 +02:00
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// OPERATIONS: Capacity Management
// Backend: services/production/app/api/production_operations.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getCapacity(
tenantId: string,
filters?: ProductionCapacityFilters
): Promise<{ capacity: ProductionCapacityResponse[]; total_count: number; page: number; page_size: number }> {
const params = new URLSearchParams();
if (filters?.resource_type) params.append('resource_type', filters.resource_type);
if (filters?.date) params.append('date', filters.date);
2025-10-06 15:27:01 +02:00
if (filters?.availability !== undefined)
params.append('availability', filters.availability.toString());
2025-09-23 12:49:35 +02:00
if (filters?.page) params.append('page', filters.page.toString());
if (filters?.page_size) params.append('page_size', filters.page_size.toString());
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/capacity${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get(url);
}
async getCapacityByDate(tenantId: string, date: string): Promise<ProductionCapacityResponse[]> {
2025-10-06 15:27:01 +02:00
return apiClient.get<ProductionCapacityResponse[]>(
`${this.baseUrl}/${tenantId}/production/capacity/date/${date}`
);
2025-09-23 12:49:35 +02:00
}
2025-10-06 15:27:01 +02:00
async getCapacityByResource(
tenantId: string,
resourceId: string
): Promise<ProductionCapacityResponse[]> {
return apiClient.get<ProductionCapacityResponse[]>(
`${this.baseUrl}/${tenantId}/production/capacity/resource/${resourceId}`
);
2025-09-10 08:00:50 +02:00
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// OPERATIONS: Quality Checks
// Backend: services/production/app/api/production_operations.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getQualityChecks(
tenantId: string,
filters?: QualityCheckFilters
): Promise<{ quality_checks: QualityCheckResponse[]; total_count: number; page: number; page_size: number }> {
const params = new URLSearchParams();
if (filters?.batch_id) params.append('batch_id', filters.batch_id);
if (filters?.product_id) params.append('product_id', filters.product_id);
if (filters?.start_date) params.append('start_date', filters.start_date);
if (filters?.end_date) params.append('end_date', filters.end_date);
if (filters?.pass_fail !== undefined) params.append('pass_fail', filters.pass_fail.toString());
if (filters?.page) params.append('page', filters.page.toString());
if (filters?.page_size) params.append('page_size', filters.page_size.toString());
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/quality-checks${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get(url);
}
async getQualityCheck(tenantId: string, checkId: string): Promise<QualityCheckResponse> {
2025-10-06 15:27:01 +02:00
return apiClient.get<QualityCheckResponse>(
`${this.baseUrl}/${tenantId}/production/quality-checks/${checkId}`
);
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
async createQualityCheck(
tenantId: string,
checkData: QualityCheckCreate
): Promise<QualityCheckResponse> {
return apiClient.post<QualityCheckResponse>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/quality-checks`,
2025-09-23 12:49:35 +02:00
checkData
);
}
2025-10-06 15:27:01 +02:00
async getQualityChecksByBatch(
tenantId: string,
batchId: string
): Promise<QualityCheckResponse[]> {
return apiClient.get<QualityCheckResponse[]>(
`${this.baseUrl}/${tenantId}/production/quality-checks/batch/${batchId}`
);
2025-09-23 12:49:35 +02:00
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// ANALYTICS: Performance & Trends
// Backend: services/production/app/api/analytics.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getPerformanceAnalytics(
2025-09-10 08:00:50 +02:00
tenantId: string,
startDate: string,
endDate: string
2025-09-23 12:49:35 +02:00
): Promise<ProductionPerformanceAnalytics> {
return apiClient.get<ProductionPerformanceAnalytics>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/analytics/performance?start_date=${startDate}&end_date=${endDate}`
2025-09-23 12:49:35 +02:00
);
}
async getYieldTrends(
tenantId: string,
period: 'week' | 'month' = 'week'
): Promise<YieldTrendsAnalytics> {
return apiClient.get<YieldTrendsAnalytics>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/analytics/yield-trends?period=${period}`
2025-09-23 12:49:35 +02:00
);
}
async getTopDefects(
tenantId: string,
startDate?: string,
endDate?: string
): Promise<TopDefectsAnalytics> {
const params = new URLSearchParams();
if (startDate) params.append('start_date', startDate);
if (endDate) params.append('end_date', endDate);
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/analytics/defects${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get<TopDefectsAnalytics>(url);
}
async getEquipmentEfficiency(
tenantId: string,
startDate?: string,
endDate?: string
): Promise<EquipmentEfficiencyAnalytics> {
const params = new URLSearchParams();
if (startDate) params.append('start_date', startDate);
if (endDate) params.append('end_date', endDate);
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/analytics/equipment-efficiency${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get<EquipmentEfficiencyAnalytics>(url);
}
2025-10-06 15:27:01 +02:00
async getCapacityBottlenecks(tenantId: string, days: number = 7): Promise<CapacityBottlenecks> {
2025-09-23 12:49:35 +02:00
return apiClient.get<CapacityBottlenecks>(
2025-10-06 15:27:01 +02:00
`${this.baseUrl}/${tenantId}/production/analytics/capacity-bottlenecks?days=${days}`
2025-09-23 12:49:35 +02:00
);
}
2025-10-06 15:27:01 +02:00
// ===================================================================
// ANALYTICS: Dashboard
// Backend: services/production/app/api/production_dashboard.py
// ===================================================================
2025-09-23 12:49:35 +02:00
async getDashboardSummary(tenantId: string): Promise<ProductionDashboardSummary> {
2025-10-06 15:27:01 +02:00
return apiClient.get<ProductionDashboardSummary>(
`${this.baseUrl}/${tenantId}/production/dashboard/summary`
);
2025-09-23 12:49:35 +02:00
}
async getDailyProductionPlan(tenantId: string, date?: string): Promise<any> {
const queryString = date ? `?date=${date}` : '';
2025-10-06 15:27:01 +02:00
return apiClient.get(`${this.baseUrl}/${tenantId}/production/dashboard/daily-plan${queryString}`);
2025-09-23 12:49:35 +02:00
}
async getProductionRequirements(tenantId: string, date: string): Promise<any> {
2025-10-21 19:50:07 +02:00
return apiClient.get(`${this.baseUrl}/${tenantId}/production/dashboard/requirements?date=${date}`);
2025-09-23 12:49:35 +02:00
}
async getCapacityOverview(tenantId: string, date?: string): Promise<any> {
const queryString = date ? `?date=${date}` : '';
2025-10-06 15:27:01 +02:00
return apiClient.get(
`${this.baseUrl}/${tenantId}/production/dashboard/capacity-overview${queryString}`
);
2025-09-23 12:49:35 +02:00
}
async getQualityOverview(
tenantId: string,
startDate?: string,
endDate?: string
): Promise<any> {
const params = new URLSearchParams();
if (startDate) params.append('start_date', startDate);
if (endDate) params.append('end_date', endDate);
const queryString = params.toString();
2025-10-06 15:27:01 +02:00
const url = `${this.baseUrl}/${tenantId}/production/dashboard/quality-overview${queryString ? `?${queryString}` : ''}`;
2025-09-23 12:49:35 +02:00
return apiClient.get(url);
2025-09-10 08:00:50 +02:00
}
2025-10-24 13:05:04 +02:00
// ===================================================================
// OPERATIONS: Scheduler
// ===================================================================
/**
* Trigger production scheduler manually (for testing/development)
* POST /tenants/{tenant_id}/production/operations/scheduler/trigger
*/
static async triggerProductionScheduler(tenantId: string): Promise<{
success: boolean;
message: string;
tenant_id: string
}> {
return apiClient.post(
`/tenants/${tenantId}/production/operations/scheduler/trigger`,
{}
);
}
2025-09-10 08:00:50 +02:00
}
2025-09-23 12:49:35 +02:00
export const productionService = new ProductionService();
2025-10-06 15:27:01 +02:00
export default productionService;