Implement supplier product/price association & unify onboarding UI

MAJOR FEATURES IMPLEMENTED:

1.  CRITICAL: Supplier Product/Price Association
   - Created SupplierProductManager component (438 lines)
   - Multi-select product picker from inventory
   - Price entry with unit of measure and min quantity
   - Expandable UI per supplier (collapsed by default)
   - Full CRUD operations via existing API hooks
   - Required for automatic Purchase Order (PO) creation
   - Warning shown if supplier has no products

2.  Step Re-Ordering: Inventory Before Suppliers
   - Manual path: inventory-setup now comes BEFORE suppliers-setup
   - AI path: Already has inventory from sales data upload
   - Ensures products exist before supplier association
   - Critical workflow fix identified by user

3.  UI/UX Unification
   - Unified badge styles across AI suggestions
   - Changed hardcoded colors to CSS variables
   - Consistent rounded-full badge design
   - Added flex-wrap for responsive badges

IMPLEMENTATION DETAILS:

SupplierProductManager.tsx (NEW - 438 lines):
- useSupplierPriceLists() - Fetch existing products for supplier
- useIngredients() - Fetch all available inventory items
- useCreate/Update/DeleteSupplierPriceList() mutations
- Expandable UI: Collapsed shows count, expanded shows management
- Product selection: Checkboxes with inline price forms
- Form fields: unit_price (required), unit_of_measure, min_order_quantity
- Validation: Price must be > 0, unit required
- Warning: Shows if no products added (blocks PO creation)

UnifiedOnboardingWizard.tsx:
- inventory-setup moved before suppliers-setup
- inventory-setup condition: dataSource === 'manual'
- suppliers-setup condition: Inventory exists (AI stockEntryCompleted OR manual inventoryCompleted)
- Ensures products always exist before supplier association

SuppliersSetupStep.tsx:
- Added SupplierProductManager import
- Changed supplier card layout from flex items-center to block
- Integrated ProductManager component into each supplier card
- Product management appears below contact info, above edit/delete

UploadSalesDataStep.tsx:
- Updated badge colors: blue-100/blue-800 → CSS variables
- Changed bg-[var(--bg-tertiary)] → bg-[var(--bg-primary)]
- Added flex-wrap to badge container
- Consistent rounded-full design

FLOW IMPROVEMENTS:

AI-Assisted Path:
Registration → Bakery Type → Data Source → Tenant Setup →
Upload Sales → Categorize → Enter Stock → **Suppliers (with products)** →
ML Training → Complete

Manual Path:
Registration → Bakery Type → Data Source → Tenant Setup →
**Inventory Setup → Suppliers (with products)** → Recipes → Processes →
ML Training → Complete

BENEFITS:
 Automatic PO creation now possible
 System knows supplier-product relationships
 Prices tracked for cost analysis
 Logical workflow (products before suppliers)
 Unified, consistent UI across onboarding
 Critical missing feature implemented

Build: Successful (21.73s)
Files: 4 changed (3 modified, 1 new)
Lines: +438 new component, ~50 lines modified
This commit is contained in:
Claude
2025-11-06 14:09:10 +00:00
parent fc8a63260b
commit 2974ff3dbf
4 changed files with 492 additions and 70 deletions

View File

@@ -432,22 +432,22 @@ export const UploadSalesDataStep: React.FC<UploadSalesDataStepProps> = ({
<p className="text-sm text-[var(--text-secondary)]">
{item.category} Unidad: {item.unit_of_measure}
</p>
<div className="flex items-center gap-2 mt-1">
<span className="text-xs bg-[var(--bg-tertiary)] px-2 py-1 rounded">
<div className="flex items-center gap-2 mt-1 flex-wrap">
<span className="text-xs bg-[var(--bg-primary)] px-2 py-0.5 rounded-full text-[var(--text-secondary)]">
Confianza: {Math.round(item.confidence_score * 100)}%
</span>
{item.requires_refrigeration && (
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded">
<span className="text-xs bg-[var(--color-info)]/10 text-[var(--color-info)] px-2 py-0.5 rounded-full">
Requiere refrigeración
</span>
)}
{item.requires_freezing && (
<span className="text-xs bg-cyan-100 text-cyan-800 px-2 py-1 rounded">
<span className="text-xs bg-[var(--color-info)]/10 text-[var(--color-info)] px-2 py-0.5 rounded-full">
Requiere congelación
</span>
)}
{item.is_seasonal && (
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">
<span className="text-xs bg-[var(--color-success)]/10 text-[var(--color-success)] px-2 py-0.5 rounded-full">
Producto estacional
</span>
)}