Add more services

This commit is contained in:
Urtzi Alfaro
2025-08-21 20:28:14 +02:00
parent d6fd53e461
commit c6dd6fd1de
85 changed files with 17842 additions and 1828 deletions

View File

@@ -15,6 +15,9 @@ import { NotificationService } from './notification.service';
import { OnboardingService } from './onboarding.service';
import { InventoryService } from './inventory.service';
import { RecipesService } from './recipes.service';
import { ProductionService } from './production.service';
import { OrdersService } from './orders.service';
import { SuppliersService } from './suppliers.service';
// Create service instances
export const authService = new AuthService();
@@ -27,6 +30,9 @@ export const notificationService = new NotificationService();
export const onboardingService = new OnboardingService();
export const inventoryService = new InventoryService();
export const recipesService = new RecipesService();
export const productionService = new ProductionService();
export const ordersService = new OrdersService();
export const suppliersService = new SuppliersService();
// Export the classes as well
export {
@@ -39,7 +45,10 @@ export {
NotificationService,
OnboardingService,
InventoryService,
RecipesService
RecipesService,
ProductionService,
OrdersService,
SuppliersService
};
// Import base client
@@ -61,6 +70,9 @@ export const api = {
onboarding: onboardingService,
inventory: inventoryService,
recipes: recipesService,
production: productionService,
orders: ordersService,
suppliers: suppliersService,
} as const;
// Service status checking
@@ -81,6 +93,9 @@ export class HealthService {
{ name: 'External', endpoint: '/external/health' },
{ name: 'Training', endpoint: '/training/health' },
{ name: 'Inventory', endpoint: '/inventory/health' },
{ name: 'Production', endpoint: '/production/health' },
{ name: 'Orders', endpoint: '/orders/health' },
{ name: 'Suppliers', endpoint: '/suppliers/health' },
{ name: 'Forecasting', endpoint: '/forecasting/health' },
{ name: 'Notification', endpoint: '/notifications/health' },
];

View File

@@ -433,22 +433,6 @@ export class InventoryService {
// ========== DASHBOARD & ANALYTICS ==========
/**
* Get inventory dashboard data
*/
async getDashboardData(tenantId: string): Promise<InventoryDashboardData> {
// TODO: Map to correct endpoint when available
return {
total_items: 0,
low_stock_items: 0,
out_of_stock_items: 0,
total_value: 0,
recent_movements: [],
top_products: [],
stock_alerts: []
};
// return apiClient.get(`/tenants/${tenantId}/inventory/dashboard`);
}
/**
* Get inventory value report
@@ -696,6 +680,129 @@ export class InventoryService {
return null;
}
}
// ========== ENHANCED DASHBOARD FEATURES ==========
/**
* Get inventory dashboard data with analytics
*/
async getDashboardData(tenantId: string, params?: {
date_from?: string;
date_to?: string;
location?: string;
}): Promise<{
summary: {
total_items: number;
low_stock_count: number;
out_of_stock_items: number;
expiring_soon: number;
total_value: number;
};
recent_movements: any[];
active_alerts: any[];
stock_trends: {
dates: string[];
stock_levels: number[];
movements_in: number[];
movements_out: number[];
};
}> {
try {
return await apiClient.get(`/tenants/${tenantId}/inventory/dashboard`, { params });
} catch (error) {
console.error('❌ Error fetching inventory dashboard:', error);
throw error;
}
}
/**
* Get food safety compliance data
*/
async getFoodSafetyCompliance(tenantId: string): Promise<{
compliant_items: number;
non_compliant_items: number;
expiring_items: any[];
temperature_violations: any[];
compliance_score: number;
}> {
try {
return await apiClient.get(`/tenants/${tenantId}/inventory/food-safety/compliance`);
} catch (error) {
console.error('❌ Error fetching food safety compliance:', error);
throw error;
}
}
/**
* Get temperature monitoring data
*/
async getTemperatureMonitoring(tenantId: string, params?: {
item_id?: string;
location?: string;
date_from?: string;
date_to?: string;
}): Promise<{
readings: any[];
violations: any[];
}> {
try {
return await apiClient.get(`/tenants/${tenantId}/inventory/food-safety/temperature-monitoring`, { params });
} catch (error) {
console.error('❌ Error fetching temperature monitoring:', error);
throw error;
}
}
/**
* Record temperature reading
*/
async recordTemperatureReading(tenantId: string, params: {
item_id: string;
temperature: number;
humidity?: number;
location: string;
notes?: string;
}): Promise<void> {
try {
return await apiClient.post(`/tenants/${tenantId}/inventory/food-safety/temperature-reading`, params);
} catch (error) {
console.error('❌ Error recording temperature reading:', error);
throw error;
}
}
/**
* Get inventory alerts
*/
async getInventoryAlerts(tenantId: string, params?: {
alert_type?: string;
severity?: string;
status?: string;
item_id?: string;
limit?: number;
}): Promise<any[]> {
try {
return await apiClient.get(`/tenants/${tenantId}/inventory/alerts`, { params });
} catch (error) {
console.error('❌ Error fetching inventory alerts:', error);
throw error;
}
}
/**
* Get restock recommendations
*/
async getRestockRecommendations(tenantId: string): Promise<{
urgent_restocks: any[];
optimal_orders: any[];
}> {
try {
return await apiClient.get(`/tenants/${tenantId}/inventory/forecasting/restock-recommendations`);
} catch (error) {
console.error('❌ Error fetching restock recommendations:', error);
throw error;
}
}
}
export const inventoryService = new InventoryService();

View File

@@ -0,0 +1,363 @@
// ================================================================
// frontend/src/api/services/orders.service.ts
// ================================================================
/**
* Orders Service - API client for Orders Service endpoints
*/
import { apiClient } from '../client';
// Order Types
export interface Order {
id: string;
tenant_id: string;
customer_id?: string;
customer_name?: string;
customer_email?: string;
customer_phone?: string;
order_number: string;
status: 'pending' | 'confirmed' | 'in_production' | 'ready' | 'delivered' | 'cancelled';
order_type: 'walk_in' | 'online' | 'phone' | 'catering';
business_model: 'individual_bakery' | 'central_bakery';
items: OrderItem[];
subtotal: number;
tax_amount: number;
discount_amount: number;
total_amount: number;
delivery_date?: string;
delivery_address?: string;
notes?: string;
created_at: string;
updated_at: string;
}
export interface OrderItem {
id: string;
recipe_id: string;
recipe_name: string;
quantity: number;
unit_price: number;
total_price: number;
customizations?: Record<string, any>;
production_notes?: string;
}
export interface Customer {
id: string;
name: string;
email?: string;
phone?: string;
address?: string;
customer_type: 'individual' | 'business' | 'catering';
preferences?: string[];
loyalty_points?: number;
total_orders: number;
total_spent: number;
created_at: string;
updated_at: string;
}
export interface OrderDashboardData {
summary: {
total_orders_today: number;
pending_orders: number;
orders_in_production: number;
completed_orders: number;
revenue_today: number;
average_order_value: number;
};
recent_orders: Order[];
peak_hours: { hour: number; orders: number }[];
popular_items: { recipe_name: string; quantity: number }[];
business_model_distribution: { model: string; count: number; revenue: number }[];
}
export interface ProcurementPlan {
id: string;
date: string;
status: 'draft' | 'approved' | 'ordered' | 'completed';
total_cost: number;
items: ProcurementItem[];
supplier_orders: SupplierOrder[];
created_at: string;
updated_at: string;
}
export interface ProcurementItem {
ingredient_id: string;
ingredient_name: string;
required_quantity: number;
current_stock: number;
quantity_to_order: number;
unit: string;
estimated_cost: number;
priority: 'low' | 'medium' | 'high' | 'critical';
supplier_id?: string;
supplier_name?: string;
}
export interface SupplierOrder {
supplier_id: string;
supplier_name: string;
items: ProcurementItem[];
total_cost: number;
delivery_date?: string;
notes?: string;
}
export interface OrderCreateRequest {
customer_id?: string;
customer_name?: string;
customer_email?: string;
customer_phone?: string;
order_type: 'walk_in' | 'online' | 'phone' | 'catering';
business_model: 'individual_bakery' | 'central_bakery';
items: {
recipe_id: string;
quantity: number;
customizations?: Record<string, any>;
}[];
delivery_date?: string;
delivery_address?: string;
notes?: string;
}
export interface OrderUpdateRequest {
status?: 'pending' | 'confirmed' | 'in_production' | 'ready' | 'delivered' | 'cancelled';
items?: {
recipe_id: string;
quantity: number;
customizations?: Record<string, any>;
}[];
delivery_date?: string;
delivery_address?: string;
notes?: string;
}
export class OrdersService {
private readonly basePath = '/orders';
// Dashboard
async getDashboardData(params?: {
date_from?: string;
date_to?: string;
}): Promise<OrderDashboardData> {
return apiClient.get(`${this.basePath}/dashboard`, { params });
}
async getDashboardMetrics(params?: {
date_from?: string;
date_to?: string;
granularity?: 'hour' | 'day' | 'week' | 'month';
}): Promise<{
dates: string[];
order_counts: number[];
revenue: number[];
average_order_values: number[];
business_model_breakdown: { model: string; orders: number[]; revenue: number[] }[];
}> {
return apiClient.get(`${this.basePath}/dashboard/metrics`, { params });
}
// Orders
async getOrders(params?: {
status?: string;
order_type?: string;
business_model?: string;
customer_id?: string;
date_from?: string;
date_to?: string;
limit?: number;
offset?: number;
}): Promise<Order[]> {
return apiClient.get(`${this.basePath}`, { params });
}
async getOrder(orderId: string): Promise<Order> {
return apiClient.get(`${this.basePath}/${orderId}`);
}
async createOrder(order: OrderCreateRequest): Promise<Order> {
return apiClient.post(`${this.basePath}`, order);
}
async updateOrder(orderId: string, updates: OrderUpdateRequest): Promise<Order> {
return apiClient.put(`${this.basePath}/${orderId}`, updates);
}
async deleteOrder(orderId: string): Promise<void> {
return apiClient.delete(`${this.basePath}/${orderId}`);
}
async updateOrderStatus(orderId: string, status: Order['status']): Promise<Order> {
return apiClient.patch(`${this.basePath}/${orderId}/status`, { status });
}
async getOrderHistory(orderId: string): Promise<{
order: Order;
status_changes: {
status: string;
timestamp: string;
user: string;
notes?: string
}[];
}> {
return apiClient.get(`${this.basePath}/${orderId}/history`);
}
// Customers
async getCustomers(params?: {
search?: string;
customer_type?: string;
limit?: number;
offset?: number;
}): Promise<Customer[]> {
return apiClient.get(`${this.basePath}/customers`, { params });
}
async getCustomer(customerId: string): Promise<Customer> {
return apiClient.get(`${this.basePath}/customers/${customerId}`);
}
async createCustomer(customer: {
name: string;
email?: string;
phone?: string;
address?: string;
customer_type: 'individual' | 'business' | 'catering';
preferences?: string[];
}): Promise<Customer> {
return apiClient.post(`${this.basePath}/customers`, customer);
}
async updateCustomer(customerId: string, updates: {
name?: string;
email?: string;
phone?: string;
address?: string;
customer_type?: 'individual' | 'business' | 'catering';
preferences?: string[];
}): Promise<Customer> {
return apiClient.put(`${this.basePath}/customers/${customerId}`, updates);
}
async getCustomerOrders(customerId: string, params?: {
limit?: number;
offset?: number;
}): Promise<Order[]> {
return apiClient.get(`${this.basePath}/customers/${customerId}/orders`, { params });
}
// Procurement Planning
async getProcurementPlans(params?: {
status?: string;
date_from?: string;
date_to?: string;
limit?: number;
offset?: number;
}): Promise<ProcurementPlan[]> {
return apiClient.get(`${this.basePath}/procurement/plans`, { params });
}
async getProcurementPlan(planId: string): Promise<ProcurementPlan> {
return apiClient.get(`${this.basePath}/procurement/plans/${planId}`);
}
async createProcurementPlan(params: {
date: string;
orders?: string[];
forecast_days?: number;
}): Promise<ProcurementPlan> {
return apiClient.post(`${this.basePath}/procurement/plans`, params);
}
async updateProcurementPlan(planId: string, updates: {
items?: ProcurementItem[];
notes?: string;
}): Promise<ProcurementPlan> {
return apiClient.put(`${this.basePath}/procurement/plans/${planId}`, updates);
}
async approveProcurementPlan(planId: string): Promise<ProcurementPlan> {
return apiClient.post(`${this.basePath}/procurement/plans/${planId}/approve`);
}
async generateSupplierOrders(planId: string): Promise<SupplierOrder[]> {
return apiClient.post(`${this.basePath}/procurement/plans/${planId}/generate-orders`);
}
// Business Model Detection
async detectBusinessModel(): Promise<{
detected_model: 'individual_bakery' | 'central_bakery';
confidence: number;
factors: {
daily_order_volume: number;
delivery_ratio: number;
catering_ratio: number;
average_order_size: number;
};
recommendations: string[];
}> {
return apiClient.post(`${this.basePath}/business-model/detect`);
}
async updateBusinessModel(model: 'individual_bakery' | 'central_bakery'): Promise<void> {
return apiClient.put(`${this.basePath}/business-model`, { business_model: model });
}
// Analytics
async getOrderTrends(params?: {
date_from?: string;
date_to?: string;
granularity?: 'hour' | 'day' | 'week' | 'month';
}): Promise<{
dates: string[];
order_counts: number[];
revenue: number[];
popular_items: { recipe_name: string; count: number }[];
}> {
return apiClient.get(`${this.basePath}/analytics/trends`, { params });
}
async getCustomerAnalytics(params?: {
date_from?: string;
date_to?: string;
}): Promise<{
new_customers: number;
returning_customers: number;
customer_retention_rate: number;
average_lifetime_value: number;
top_customers: Customer[];
}> {
return apiClient.get(`${this.basePath}/analytics/customers`, { params });
}
async getSeasonalAnalysis(params?: {
date_from?: string;
date_to?: string;
}): Promise<{
seasonal_patterns: { month: string; order_count: number; revenue: number }[];
weekly_patterns: { day: string; order_count: number }[];
hourly_patterns: { hour: number; order_count: number }[];
trending_products: { recipe_name: string; growth_rate: number }[];
}> {
return apiClient.get(`${this.basePath}/analytics/seasonal`, { params });
}
// Alerts
async getOrderAlerts(params?: {
severity?: string;
status?: string;
limit?: number;
}): Promise<any[]> {
return apiClient.get(`${this.basePath}/alerts`, { params });
}
async acknowledgeAlert(alertId: string): Promise<void> {
return apiClient.post(`${this.basePath}/alerts/${alertId}/acknowledge`);
}
async resolveAlert(alertId: string, resolution?: string): Promise<void> {
return apiClient.post(`${this.basePath}/alerts/${alertId}/resolve`, { resolution });
}
}

View File

@@ -0,0 +1,314 @@
// ================================================================
// frontend/src/api/services/production.service.ts
// ================================================================
/**
* Production Service - API client for Production Service endpoints
*/
import { apiClient } from '../client';
// Production Types
export interface ProductionBatch {
id: string;
recipe_id: string;
recipe_name: string;
quantity: number;
unit: string;
status: 'scheduled' | 'in_progress' | 'completed' | 'delayed' | 'failed';
scheduled_start: string;
actual_start?: string;
expected_end: string;
actual_end?: string;
equipment_id: string;
equipment_name: string;
operator_id: string;
operator_name: string;
temperature?: number;
humidity?: number;
quality_score?: number;
notes?: string;
created_at: string;
updated_at: string;
}
export interface ProductionPlan {
id: string;
date: string;
total_capacity: number;
allocated_capacity: number;
efficiency_target: number;
quality_target: number;
batches: ProductionBatch[];
status: 'draft' | 'approved' | 'in_progress' | 'completed';
created_at: string;
updated_at: string;
}
export interface Equipment {
id: string;
name: string;
type: string;
status: 'active' | 'idle' | 'maintenance' | 'error';
location: string;
capacity: number;
current_batch_id?: string;
temperature?: number;
utilization: number;
last_maintenance: string;
next_maintenance: string;
created_at: string;
updated_at: string;
}
export interface ProductionDashboardData {
summary: {
active_batches: number;
equipment_in_use: number;
current_efficiency: number;
todays_production: number;
alerts_count: number;
};
efficiency_trend: { date: string; efficiency: number }[];
quality_trend: { date: string; quality: number }[];
equipment_status: Equipment[];
active_batches: ProductionBatch[];
alerts: any[];
}
export interface BatchCreateRequest {
recipe_id: string;
quantity: number;
scheduled_start: string;
expected_end: string;
equipment_id: string;
operator_id: string;
notes?: string;
priority?: number;
}
export interface BatchUpdateRequest {
status?: 'scheduled' | 'in_progress' | 'completed' | 'delayed' | 'failed';
actual_start?: string;
actual_end?: string;
temperature?: number;
humidity?: number;
quality_score?: number;
notes?: string;
}
export interface PlanCreateRequest {
date: string;
batches: BatchCreateRequest[];
efficiency_target?: number;
quality_target?: number;
}
export class ProductionService {
private readonly basePath = '/production';
// Dashboard
async getDashboardData(params?: {
date_from?: string;
date_to?: string;
}): Promise<ProductionDashboardData> {
return apiClient.get(`${this.basePath}/dashboard`, { params });
}
async getDashboardMetrics(params?: {
date_from?: string;
date_to?: string;
granularity?: 'hour' | 'day' | 'week' | 'month';
}): Promise<{
dates: string[];
efficiency: number[];
quality: number[];
production_volume: number[];
equipment_utilization: number[];
}> {
return apiClient.get(`${this.basePath}/dashboard/metrics`, { params });
}
// Batches
async getBatches(params?: {
status?: string;
equipment_id?: string;
date_from?: string;
date_to?: string;
limit?: number;
offset?: number;
}): Promise<ProductionBatch[]> {
return apiClient.get(`${this.basePath}/batches`, { params });
}
async getBatch(batchId: string): Promise<ProductionBatch> {
return apiClient.get(`${this.basePath}/batches/${batchId}`);
}
async createBatch(batch: BatchCreateRequest): Promise<ProductionBatch> {
return apiClient.post(`${this.basePath}/batches`, batch);
}
async updateBatch(batchId: string, updates: BatchUpdateRequest): Promise<ProductionBatch> {
return apiClient.put(`${this.basePath}/batches/${batchId}`, updates);
}
async deleteBatch(batchId: string): Promise<void> {
return apiClient.delete(`${this.basePath}/batches/${batchId}`);
}
async startBatch(batchId: string): Promise<ProductionBatch> {
return apiClient.post(`${this.basePath}/batches/${batchId}/start`);
}
async completeBatch(batchId: string, qualityScore?: number, notes?: string): Promise<ProductionBatch> {
return apiClient.post(`${this.basePath}/batches/${batchId}/complete`, {
quality_score: qualityScore,
notes
});
}
async getBatchStatus(batchId: string): Promise<{
status: string;
progress: number;
current_phase: string;
temperature: number;
humidity: number;
estimated_completion: string;
alerts: any[];
}> {
return apiClient.get(`${this.basePath}/batches/${batchId}/status`);
}
// Production Plans
async getPlans(params?: {
date_from?: string;
date_to?: string;
status?: string;
limit?: number;
offset?: number;
}): Promise<ProductionPlan[]> {
return apiClient.get(`${this.basePath}/plans`, { params });
}
async getPlan(planId: string): Promise<ProductionPlan> {
return apiClient.get(`${this.basePath}/plans/${planId}`);
}
async createPlan(plan: PlanCreateRequest): Promise<ProductionPlan> {
return apiClient.post(`${this.basePath}/plans`, plan);
}
async updatePlan(planId: string, updates: Partial<PlanCreateRequest>): Promise<ProductionPlan> {
return apiClient.put(`${this.basePath}/plans/${planId}`, updates);
}
async deletePlan(planId: string): Promise<void> {
return apiClient.delete(`${this.basePath}/plans/${planId}`);
}
async approvePlan(planId: string): Promise<ProductionPlan> {
return apiClient.post(`${this.basePath}/plans/${planId}/approve`);
}
async optimizePlan(planId: string): Promise<ProductionPlan> {
return apiClient.post(`${this.basePath}/plans/${planId}/optimize`);
}
// Equipment
async getEquipment(params?: {
status?: string;
type?: string;
location?: string;
limit?: number;
offset?: number;
}): Promise<Equipment[]> {
return apiClient.get(`${this.basePath}/equipment`, { params });
}
async getEquipmentById(equipmentId: string): Promise<Equipment> {
return apiClient.get(`${this.basePath}/equipment/${equipmentId}`);
}
async updateEquipment(equipmentId: string, updates: {
status?: 'active' | 'idle' | 'maintenance' | 'error';
temperature?: number;
notes?: string;
}): Promise<Equipment> {
return apiClient.put(`${this.basePath}/equipment/${equipmentId}`, updates);
}
async getEquipmentMetrics(equipmentId: string, params?: {
date_from?: string;
date_to?: string;
}): Promise<{
utilization: number[];
temperature: number[];
maintenance_events: any[];
performance_score: number;
}> {
return apiClient.get(`${this.basePath}/equipment/${equipmentId}/metrics`, { params });
}
async scheduleMaintenanceForEquipment(equipmentId: string, scheduledDate: string, notes?: string): Promise<void> {
return apiClient.post(`${this.basePath}/equipment/${equipmentId}/maintenance`, {
scheduled_date: scheduledDate,
notes
});
}
// Analytics
async getEfficiencyTrends(params?: {
date_from?: string;
date_to?: string;
equipment_id?: string;
}): Promise<{
dates: string[];
efficiency: number[];
quality: number[];
volume: number[];
}> {
return apiClient.get(`${this.basePath}/analytics/efficiency`, { params });
}
async getProductionForecast(params?: {
days?: number;
include_weather?: boolean;
}): Promise<{
dates: string[];
predicted_volume: number[];
confidence_intervals: number[][];
factors: string[];
}> {
return apiClient.get(`${this.basePath}/analytics/forecast`, { params });
}
async getQualityAnalysis(params?: {
date_from?: string;
date_to?: string;
recipe_id?: string;
}): Promise<{
average_quality: number;
quality_trend: number[];
quality_factors: { factor: string; impact: number }[];
recommendations: string[];
}> {
return apiClient.get(`${this.basePath}/analytics/quality`, { params });
}
// Alerts
async getProductionAlerts(params?: {
severity?: string;
status?: string;
limit?: number;
}): Promise<any[]> {
return apiClient.get(`${this.basePath}/alerts`, { params });
}
async acknowledgeAlert(alertId: string): Promise<void> {
return apiClient.post(`${this.basePath}/alerts/${alertId}/acknowledge`);
}
async resolveAlert(alertId: string, resolution?: string): Promise<void> {
return apiClient.post(`${this.basePath}/alerts/${alertId}/resolve`, { resolution });
}
}

File diff suppressed because it is too large Load Diff