diff --git a/inventory-server/src/routes/ai-validation.js b/inventory-server/src/routes/ai-validation.js index 8795940..a4abf75 100644 --- a/inventory-server/src/routes/ai-validation.js +++ b/inventory-server/src/routes/ai-validation.js @@ -1025,60 +1025,87 @@ router.post("/validate", async (req, res) => { Object.keys(aiResponse) ); - // Create a detailed comparison between original and corrected data + // Merge AI changes back into original products + // AI now only returns changed products and changed fields + const mergedProducts = products.map((original, index) => ({ ...original })); const changeDetails = []; - // Compare original and corrected data - if (aiResponse.correctedData) { - console.log("📊 Changes summary:"); + if (aiResponse.correctedData && Array.isArray(aiResponse.correctedData)) { + console.log("📊 Processing AI changes - received", aiResponse.correctedData.length, "products with changes"); - // Debug: Log the first product's fields - if (products.length > 0) { - console.log("🔍 First product fields:", Object.keys(products[0])); - } - - products.forEach((original, index) => { - const corrected = aiResponse.correctedData[index]; - if (corrected) { - const productChanges = { - productIndex: index, - title: original.name || original.title || `Product ${index + 1}`, - changes: [] - }; - - const changes = Object.keys(corrected).filter( - (key) => - JSON.stringify(original[key]) !== - JSON.stringify(corrected[key]) - ); - - if (changes.length > 0) { - console.log(`\nProduct ${index + 1} changes:`); - changes.forEach((key) => { - console.log(` ${key}:`); - console.log( - ` - Original: ${JSON.stringify(original[key])}` - ); - console.log( - ` - Corrected: ${JSON.stringify(corrected[key])}` - ); - - // Add to our detailed changes array - productChanges.changes.push({ - field: key, - original: original[key], - corrected: corrected[key] - }); - }); - - // Only add products that have changes - if (productChanges.changes.length > 0) { - changeDetails.push(productChanges); + // Process each changed product from AI + aiResponse.correctedData.forEach((changedProduct) => { + // Find the matching original product using stable identifiers in priority order + // Priority: upc > supplier_no > notions_no + // These fields should not change during validation + const identifiers = ['upc', 'supplier_no', 'notions_no']; + let matchedIndex = -1; + let matchedBy = null; + + for (const identifier of identifiers) { + if (changedProduct[identifier] !== undefined && changedProduct[identifier] !== null && changedProduct[identifier] !== '') { + matchedIndex = products.findIndex( + (p) => p[identifier] !== undefined && + p[identifier] !== null && + p[identifier] !== '' && + String(p[identifier]).trim() === String(changedProduct[identifier]).trim() + ); + if (matchedIndex !== -1) { + matchedBy = identifier; + console.log(`✓ Matched product by ${identifier}:`, changedProduct[identifier]); + break; } } } + + // If no identifier match found, log an error with details + if (matchedIndex === -1) { + console.error("❌ Could not match changed product to original. Product identifiers:", { + upc: changedProduct.upc, + supplier_no: changedProduct.supplier_no, + notions_no: changedProduct.notions_no + }); + return; + } + + const original = products[matchedIndex]; + const productChanges = { + productIndex: matchedIndex, + title: original.name || original.title || `Product ${matchedIndex + 1}`, + changes: [] + }; + + // Apply each changed field to the merged product + Object.keys(changedProduct).forEach((key) => { + // Check if the value actually changed + if (JSON.stringify(original[key]) !== JSON.stringify(changedProduct[key])) { + console.log(`\nProduct ${matchedIndex + 1} - Field ${key}:`); + console.log(` - Original: ${JSON.stringify(original[key])}`); + console.log(` - Corrected: ${JSON.stringify(changedProduct[key])}`); + + // Apply the change to merged product + mergedProducts[matchedIndex][key] = changedProduct[key]; + + // Track the change + productChanges.changes.push({ + field: key, + original: original[key], + corrected: changedProduct[key] + }); + } + }); + + // Only add to changeDetails if there were actual changes + if (productChanges.changes.length > 0) { + changeDetails.push(productChanges); + } }); + + console.log(`📊 Applied changes to ${changeDetails.length} products`); } + + // Replace aiResponse.correctedData with the fully merged product array + aiResponse.correctedData = mergedProducts; // Record performance metrics after successful validation const endTime = new Date(); diff --git a/inventory/src/components/product-import/steps/ImageUploadStep/ImageUploadStep.tsx b/inventory/src/components/product-import/steps/ImageUploadStep/ImageUploadStep.tsx index 0e07c01..d7ebf11 100644 --- a/inventory/src/components/product-import/steps/ImageUploadStep/ImageUploadStep.tsx +++ b/inventory/src/components/product-import/steps/ImageUploadStep/ImageUploadStep.tsx @@ -186,7 +186,7 @@ export const ImageUploadStep = ({ } finally { setIsSubmitting(false); } - }, [data, file, onSubmit, productImages]); + }, [data, file, onSubmit, productImages, targetEnvironment, useTestDataSource]); return (