// frontend/src/api/services/sales.service.ts /** * Sales Data Service * Handles sales data operations for the sales microservice */ import { apiClient } from '../client'; import { RequestTimeouts } from '../client/config'; import type { SalesData, SalesValidationResult, SalesDataQuery, SalesDataImport, SalesImportResult, DashboardStats, PaginatedResponse, ActivityItem, } from '../types'; export class SalesService { /** * Upload Sales History File */ async uploadSalesHistory( tenantId: string, file: File, additionalData?: Record ): Promise { // Determine file format const fileName = file.name.toLowerCase(); let fileFormat: string; if (fileName.endsWith('.csv')) { fileFormat = 'csv'; } else if (fileName.endsWith('.json')) { fileFormat = 'json'; } else if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) { fileFormat = 'excel'; } else { fileFormat = 'csv'; // Default fallback } const uploadData = { file_format: fileFormat, ...additionalData, }; return apiClient.upload( `/tenants/${tenantId}/sales/import`, file, uploadData, { timeout: RequestTimeouts.LONG, } ); } /** * Validate Sales Data */ async validateSalesData( tenantId: string, file: File ): Promise { const fileName = file.name.toLowerCase(); let fileFormat: string; if (fileName.endsWith('.csv')) { fileFormat = 'csv'; } else if (fileName.endsWith('.json')) { fileFormat = 'json'; } else if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) { fileFormat = 'excel'; } else { fileFormat = 'csv'; } return apiClient.upload( `/tenants/${tenantId}/sales/import/validate`, file, { file_format: fileFormat, validate_only: true, source: 'onboarding_upload', }, { timeout: RequestTimeouts.MEDIUM, } ); } /** * Get Sales Data */ async getSalesData( tenantId: string, query?: SalesDataQuery ): Promise> { return apiClient.get(`/tenants/${tenantId}/sales`, { params: query }); } /** * Get Single Sales Record */ async getSalesRecord(tenantId: string, recordId: string): Promise { return apiClient.get(`/tenants/${tenantId}/sales/${recordId}`); } /** * Update Sales Record */ async updateSalesRecord( tenantId: string, recordId: string, data: Partial ): Promise { return apiClient.put(`/tenants/${tenantId}/sales/${recordId}`, data); } /** * Delete Sales Record */ async deleteSalesRecord(tenantId: string, recordId: string): Promise<{ message: string }> { return apiClient.delete(`/tenants/${tenantId}/sales/${recordId}`); } /** * Get Dashboard Statistics */ async getDashboardStats(tenantId: string): Promise { return apiClient.get(`/tenants/${tenantId}/sales/stats`); } /** * Get Analytics Data */ async getAnalytics( tenantId: string, params?: { start_date?: string; end_date?: 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 { return apiClient.get(`/tenants/${tenantId}/sales/analytics`, { params }); } /** * Export Sales Data */ async exportSalesData( tenantId: string, format: 'csv' | 'excel' | 'json', query?: SalesDataQuery ): Promise { const response = await apiClient.request(`/tenants/${tenantId}/sales/export`, { method: 'GET', params: { ...query, format }, headers: { 'Accept': format === 'csv' ? 'text/csv' : format === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'application/json', }, }); return new Blob([response], { type: format === 'csv' ? 'text/csv' : format === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'application/json', }); } /** * Get Recent Activity */ async getRecentActivity(tenantId: string, limit?: number): Promise { return apiClient.get(`/tenants/${tenantId}/sales/activity`, { params: { limit }, }); } /** * Get Products List from Sales Data */ async getProductsList(tenantId: string): Promise { try { const response = await apiClient.get(`/tenants/${tenantId}/sales/products`); console.log('🔍 Products API Response Analysis:'); console.log('- Type:', typeof response); console.log('- Is Array:', Array.isArray(response)); console.log('- Keys:', Object.keys(response || {})); console.log('- Response:', response); let productsArray: any[] = []; // ✅ FIX: Handle different response formats if (Array.isArray(response)) { // Standard array response productsArray = response; console.log('✅ Response is already an array'); } else if (response && typeof response === 'object') { // Object with numeric keys - convert to array const keys = Object.keys(response); if (keys.length > 0 && keys.every(key => !isNaN(Number(key)))) { // Object has numeric keys like {0: {...}, 1: {...}} productsArray = Object.values(response); console.log('✅ Converted object with numeric keys to array'); } else { console.warn('⚠️ Response is object but not with numeric keys:', response); return []; } } else { console.warn('⚠️ Response is not array or object:', response); return []; } console.log('📦 Products array:', productsArray); // Extract product names from the array const productNames = productsArray .map((product: any) => { if (typeof product === 'string') { return product; } if (product && typeof product === 'object') { return product.product_name || product.name || product.productName || null; } return null; }) .filter(Boolean) // Remove null/undefined values .filter((name: string) => name.trim().length > 0); // Remove empty strings console.log('📋 Extracted product names:', productNames); if (productNames.length === 0) { console.warn('⚠️ No valid product names extracted from response'); } return productNames; } catch (error) { console.error('❌ Failed to fetch products list:', error); // Return fallback products for Madrid bakery return [ 'Croissants', 'Pan de molde', 'Baguettes', 'Café', 'Napolitanas', 'Pan integral', 'Magdalenas', 'Churros' ]; } } /** * Get Sales Summary by Period */ async getSalesSummary( tenantId: string, period: 'daily' | 'weekly' | 'monthly' = 'daily' ): Promise { return apiClient.get(`/tenants/${tenantId}/sales/summary`, { params: { period } }); } /** * Get Sales Analytics */ async getSalesAnalytics( tenantId: string, startDate?: string, endDate?: string ): Promise<{ total_revenue: number; waste_reduction_percentage?: number; forecast_accuracy?: number; stockout_events?: number; }> { return apiClient.get(`/tenants/${tenantId}/sales/analytics/summary`, { params: { start_date: startDate, end_date: endDate } }); } } export const salesService = new SalesService();