Fix new services implementation 3
This commit is contained in:
@@ -163,7 +163,8 @@ export const useForecast = () => {
|
||||
tenantId: string,
|
||||
format: 'csv' | 'excel' | 'json',
|
||||
params?: {
|
||||
product_name?: string;
|
||||
inventory_product_id?: string; // Primary way to filter by product
|
||||
product_name?: string; // For backward compatibility
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ export class ForecastingService {
|
||||
async getForecasts(
|
||||
tenantId: string,
|
||||
params?: BaseQueryParams & {
|
||||
product_name?: string;
|
||||
inventory_product_id?: string; // Primary way to filter by product
|
||||
product_name?: string; // For backward compatibility - will need inventory service lookup
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
model_id?: string;
|
||||
@@ -158,7 +159,8 @@ export class ForecastingService {
|
||||
}
|
||||
|
||||
return forecastsArray.map((forecast: any) => ({
|
||||
product_name: forecast.product_name,
|
||||
inventory_product_id: forecast.inventory_product_id,
|
||||
product_name: forecast.product_name, // Optional - for display
|
||||
next_day_prediction: forecast.predicted_demand || 0,
|
||||
next_week_avg: forecast.predicted_demand || 0,
|
||||
trend_direction: 'stable' as const,
|
||||
@@ -168,9 +170,10 @@ export class ForecastingService {
|
||||
} catch (error) {
|
||||
console.error('QuickForecasts API call failed, using fallback data:', error);
|
||||
|
||||
// Return mock data for common bakery products
|
||||
// Return mock data for common bakery products (using mock inventory_product_ids)
|
||||
return [
|
||||
{
|
||||
inventory_product_id: 'mock-pan-de-molde-001',
|
||||
product_name: 'Pan de Molde',
|
||||
next_day_prediction: 25,
|
||||
next_week_avg: 175,
|
||||
@@ -179,6 +182,7 @@ export class ForecastingService {
|
||||
last_updated: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
inventory_product_id: 'mock-baguettes-002',
|
||||
product_name: 'Baguettes',
|
||||
next_day_prediction: 20,
|
||||
next_week_avg: 140,
|
||||
@@ -187,6 +191,7 @@ export class ForecastingService {
|
||||
last_updated: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
inventory_product_id: 'mock-croissants-003',
|
||||
product_name: 'Croissants',
|
||||
next_day_prediction: 15,
|
||||
next_week_avg: 105,
|
||||
@@ -195,6 +200,7 @@ export class ForecastingService {
|
||||
last_updated: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
inventory_product_id: 'mock-magdalenas-004',
|
||||
product_name: 'Magdalenas',
|
||||
next_day_prediction: 12,
|
||||
next_week_avg: 84,
|
||||
@@ -244,7 +250,8 @@ export class ForecastingService {
|
||||
tenantId: string,
|
||||
format: 'csv' | 'excel' | 'json',
|
||||
params?: {
|
||||
product_name?: string;
|
||||
inventory_product_id?: string; // Primary way to filter by product
|
||||
product_name?: string; // For backward compatibility
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
}
|
||||
@@ -272,7 +279,8 @@ export class ForecastingService {
|
||||
async getForecastAccuracy(
|
||||
tenantId: string,
|
||||
params?: {
|
||||
product_name?: string;
|
||||
inventory_product_id?: string; // Primary way to filter by product
|
||||
product_name?: string; // For backward compatibility
|
||||
model_id?: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
@@ -280,7 +288,8 @@ export class ForecastingService {
|
||||
): Promise<{
|
||||
overall_accuracy: number;
|
||||
product_accuracy: Array<{
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
product_name?: string; // Optional - for display
|
||||
accuracy: number;
|
||||
sample_size: number;
|
||||
}>;
|
||||
|
||||
@@ -139,7 +139,8 @@ export class SalesService {
|
||||
params?: {
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
product_names?: string[];
|
||||
inventory_product_ids?: string[]; // Primary way to filter by products
|
||||
product_names?: string[]; // For backward compatibility - will need inventory service lookup
|
||||
metrics?: string[];
|
||||
}
|
||||
): Promise<any> {
|
||||
|
||||
@@ -176,7 +176,8 @@ export interface PurchaseOrderItem {
|
||||
price_list_item_id?: string;
|
||||
ingredient_id: string;
|
||||
product_code?: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
ordered_quantity: number;
|
||||
unit_of_measure: string;
|
||||
unit_price: number;
|
||||
@@ -207,7 +208,8 @@ export interface CreatePurchaseOrderRequest {
|
||||
items: {
|
||||
ingredient_id: string;
|
||||
product_code?: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for backward compatibility
|
||||
ordered_quantity: number;
|
||||
unit_of_measure: string;
|
||||
unit_price: number;
|
||||
@@ -268,7 +270,8 @@ export interface DeliveryItem {
|
||||
delivery_id: string;
|
||||
purchase_order_item_id: string;
|
||||
ingredient_id: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
ordered_quantity: number;
|
||||
delivered_quantity: number;
|
||||
accepted_quantity: number;
|
||||
|
||||
@@ -101,7 +101,8 @@ export class TrainingService {
|
||||
async getModels(
|
||||
tenantId: string,
|
||||
params?: BaseQueryParams & {
|
||||
product_name?: string;
|
||||
inventory_product_id?: string; // Primary way to filter by product
|
||||
product_name?: string; // For backward compatibility - will need inventory service lookup
|
||||
is_active?: boolean;
|
||||
}
|
||||
): Promise<PaginatedResponse<ModelInfo>> {
|
||||
|
||||
@@ -9,8 +9,10 @@ export interface SalesData {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
date: string;
|
||||
product_name: string;
|
||||
category?: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
// Note: product_name now needs to be fetched from inventory service using inventory_product_id
|
||||
product_name?: string; // Optional - for backward compatibility, populated by frontend logic
|
||||
category?: string; // Optional - fetched from inventory service
|
||||
quantity: number;
|
||||
unit_price: number;
|
||||
total_revenue: number;
|
||||
@@ -55,7 +57,9 @@ export interface SalesDataQuery extends BaseQueryParams {
|
||||
tenant_id: string;
|
||||
start_date?: string;
|
||||
end_date?: string;
|
||||
product_names?: string[];
|
||||
// Note: product_names filtering now requires inventory service integration or use inventory_product_ids
|
||||
product_names?: string[]; // For backward compatibility - will need inventory service lookup
|
||||
inventory_product_ids?: string[]; // Primary way to filter by products
|
||||
location_ids?: string[];
|
||||
sources?: string[];
|
||||
min_quantity?: number;
|
||||
@@ -64,7 +68,7 @@ export interface SalesDataQuery extends BaseQueryParams {
|
||||
max_revenue?: number;
|
||||
search_term?: string;
|
||||
sales_channel?: string;
|
||||
inventory_product_id?: string;
|
||||
inventory_product_id?: string; // Single product filter
|
||||
is_validated?: boolean;
|
||||
}
|
||||
|
||||
@@ -115,7 +119,8 @@ export interface DashboardStats {
|
||||
}
|
||||
|
||||
export interface ProductStats {
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
total_quantity: number;
|
||||
total_revenue: number;
|
||||
avg_price: number;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { ExternalFactors } from './data';
|
||||
|
||||
export interface SingleForecastRequest {
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
forecast_date: string;
|
||||
forecast_days: number;
|
||||
location: string;
|
||||
@@ -16,7 +16,8 @@ export interface SingleForecastRequest {
|
||||
}
|
||||
|
||||
export interface BatchForecastRequest {
|
||||
product_names?: string[];
|
||||
inventory_product_ids?: string[]; // Primary way to specify products
|
||||
product_names?: string[]; // For backward compatibility - will need inventory service lookup
|
||||
forecast_date: string;
|
||||
forecast_days: number;
|
||||
location: string;
|
||||
@@ -28,7 +29,8 @@ export interface BatchForecastRequest {
|
||||
export interface ForecastResponse {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
forecast_date: string;
|
||||
predicted_demand: number;
|
||||
confidence_lower?: number;
|
||||
@@ -77,7 +79,8 @@ export interface ForecastAlert {
|
||||
}
|
||||
|
||||
export interface QuickForecast {
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
next_day_prediction: number;
|
||||
next_week_avg: number;
|
||||
trend_direction: 'up' | 'down' | 'stable';
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface TrainingJobRequest {
|
||||
}
|
||||
|
||||
export interface SingleProductTrainingRequest {
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
config?: TrainingJobConfig;
|
||||
priority?: number;
|
||||
}
|
||||
@@ -81,11 +81,12 @@ export interface TrainingJobResults {
|
||||
total_training_time_seconds: number;
|
||||
average_model_accuracy?: number;
|
||||
trained_models: TrainedModelInfo[];
|
||||
failed_products?: string[];
|
||||
failed_products?: string[]; // inventory_product_ids of failed products
|
||||
}
|
||||
|
||||
export interface TrainedModelInfo {
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
model_id: string;
|
||||
model_type: string;
|
||||
accuracy_metrics: TrainingMetrics;
|
||||
@@ -107,7 +108,8 @@ export interface TrainingMetrics {
|
||||
export interface ModelInfo {
|
||||
model_id: string;
|
||||
tenant_id: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string;
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
model_type: string;
|
||||
model_path: string;
|
||||
version: number;
|
||||
|
||||
@@ -33,7 +33,8 @@ interface PurchaseOrderFormProps {
|
||||
interface OrderItem {
|
||||
ingredient_id: string;
|
||||
product_code: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name: string; // For backward compatibility and display
|
||||
ordered_quantity: number;
|
||||
unit_of_measure: string;
|
||||
unit_price: number;
|
||||
@@ -80,6 +81,7 @@ const initialFormData: FormData = {
|
||||
const initialOrderItem: OrderItem = {
|
||||
ingredient_id: '',
|
||||
product_code: '',
|
||||
inventory_product_id: '',
|
||||
product_name: '',
|
||||
ordered_quantity: 0,
|
||||
unit_of_measure: '',
|
||||
@@ -123,7 +125,8 @@ const PurchaseOrderForm: React.FC<PurchaseOrderFormProps> = ({
|
||||
items: order.items?.map(item => ({
|
||||
ingredient_id: item.ingredient_id,
|
||||
product_code: item.product_code || '',
|
||||
product_name: item.product_name,
|
||||
inventory_product_id: item.inventory_product_id,
|
||||
product_name: item.product_name || '',
|
||||
ordered_quantity: item.ordered_quantity,
|
||||
unit_of_measure: item.unit_of_measure,
|
||||
unit_price: item.unit_price,
|
||||
@@ -193,6 +196,7 @@ const PurchaseOrderForm: React.FC<PurchaseOrderFormProps> = ({
|
||||
const ingredient = ingredients.find(ing => ing.id === ingredientId);
|
||||
if (ingredient) {
|
||||
handleItemChange(index, 'ingredient_id', ingredientId);
|
||||
handleItemChange(index, 'inventory_product_id', ingredient.id);
|
||||
handleItemChange(index, 'product_name', ingredient.name);
|
||||
handleItemChange(index, 'unit_of_measure', ingredient.unit_of_measure);
|
||||
handleItemChange(index, 'product_code', ingredient.sku || '');
|
||||
@@ -279,6 +283,7 @@ const PurchaseOrderForm: React.FC<PurchaseOrderFormProps> = ({
|
||||
items: formData.items.map(item => ({
|
||||
ingredient_id: item.ingredient_id,
|
||||
product_code: item.product_code || undefined,
|
||||
inventory_product_id: item.inventory_product_id,
|
||||
product_name: item.product_name,
|
||||
ordered_quantity: item.ordered_quantity,
|
||||
unit_of_measure: item.unit_of_measure,
|
||||
|
||||
@@ -115,7 +115,8 @@ export const useDashboard = () => {
|
||||
const forecastPromises = products.map(async (product) => {
|
||||
try {
|
||||
const forecastRequest = {
|
||||
product_name: product,
|
||||
inventory_product_id: product, // Use product as inventory_product_id
|
||||
product_name: product, // Keep for backward compatibility
|
||||
forecast_date: new Date().toISOString().split('T')[0], // Today's date as YYYY-MM-DD
|
||||
forecast_days: 1,
|
||||
location: 'madrid_centro', // Default location for Madrid bakery
|
||||
|
||||
@@ -101,7 +101,9 @@ export const useOrderSuggestions = () => {
|
||||
|
||||
for (const product of dailyProducts) {
|
||||
// Find forecast for this product
|
||||
const forecast = quickForecasts.find(f => f.product_name === product);
|
||||
const forecast = quickForecasts.find(f =>
|
||||
f.product_name === product || f.inventory_product_id === product
|
||||
);
|
||||
|
||||
if (forecast) {
|
||||
// Calculate suggested quantity based on prediction
|
||||
|
||||
@@ -4,7 +4,8 @@ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
|
||||
export interface Forecast {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
location: string;
|
||||
forecast_date: string;
|
||||
created_at: string;
|
||||
@@ -41,7 +42,8 @@ export interface ForecastAlert {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
type: 'high_demand' | 'low_demand' | 'stockout_risk' | 'overproduction';
|
||||
product_name: string;
|
||||
inventory_product_id: string; // Reference to inventory service product
|
||||
product_name?: string; // Optional - for display, populated by frontend from inventory service
|
||||
message: string;
|
||||
severity: 'low' | 'medium' | 'high';
|
||||
created_at: string;
|
||||
@@ -109,13 +111,15 @@ export const generateForecast = createAsyncThunk(
|
||||
'forecast/generate',
|
||||
async ({
|
||||
tenantId,
|
||||
productName,
|
||||
inventoryProductId,
|
||||
productName, // For backward compatibility
|
||||
forecastDate,
|
||||
forecastDays = 1,
|
||||
location
|
||||
}: {
|
||||
tenantId: string;
|
||||
productName: string;
|
||||
inventoryProductId?: string;
|
||||
productName?: string; // For backward compatibility
|
||||
forecastDate: string;
|
||||
forecastDays?: number;
|
||||
location: string;
|
||||
@@ -127,7 +131,7 @@ export const generateForecast = createAsyncThunk(
|
||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
product_name: productName,
|
||||
inventory_product_id: inventoryProductId || productName, // Use inventoryProductId or fallback to productName for backward compatibility
|
||||
forecast_date: forecastDate,
|
||||
forecast_days: forecastDays,
|
||||
location,
|
||||
@@ -146,11 +150,13 @@ export const generateBatchForecast = createAsyncThunk(
|
||||
'forecast/generateBatch',
|
||||
async ({
|
||||
tenantId,
|
||||
products,
|
||||
inventoryProductIds,
|
||||
products, // For backward compatibility
|
||||
forecastDays = 7
|
||||
}: {
|
||||
tenantId: string;
|
||||
products: string[];
|
||||
inventoryProductIds?: string[];
|
||||
products?: string[]; // For backward compatibility
|
||||
forecastDays?: number;
|
||||
}) => {
|
||||
const response = await fetch(`/api/v1/tenants/${tenantId}/forecasts/batch`, {
|
||||
@@ -160,7 +166,7 @@ export const generateBatchForecast = createAsyncThunk(
|
||||
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
products,
|
||||
inventory_product_ids: inventoryProductIds || products, // Use inventoryProductIds or fallback to products for backward compatibility
|
||||
forecast_days: forecastDays,
|
||||
batch_name: `Batch_${new Date().toISOString()}`,
|
||||
}),
|
||||
@@ -358,7 +364,7 @@ const forecastSlice = createSlice({
|
||||
state.isLoading = false;
|
||||
// Convert API forecasts to QuickForecast format
|
||||
state.todayForecasts = (action.payload.forecasts || []).map((forecast: Forecast) => ({
|
||||
product: forecast.product_name,
|
||||
product: forecast.product_name || forecast.inventory_product_id, // Use product_name if available, otherwise use ID
|
||||
predicted: Math.round(forecast.predicted_demand),
|
||||
confidence: forecast.confidence_level > 0.8 ? 'high' :
|
||||
forecast.confidence_level > 0.6 ? 'medium' : 'low',
|
||||
|
||||
Reference in New Issue
Block a user