diff --git a/src/pages/Cutting.tsx b/src/pages/Cutting.tsx index dea5353..6080651 100644 --- a/src/pages/Cutting.tsx +++ b/src/pages/Cutting.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState } from 'react'; import { Link, useOutletContext, useSearchParams } from 'react-router-dom'; -import { AlertTriangle, ArrowLeft, ClipboardList, Download, Eye, Layers3, Palette, Pencil, RotateCcw, Ruler, Save as SaveIcon, Scissors, Search, Settings2, X } from 'lucide-react'; +import { AlertTriangle, ArrowLeft, ClipboardList, Download, Eye, Layers3, Pencil, RotateCcw, Ruler, Save as SaveIcon, Scissors, Search, Settings2, X } from 'lucide-react'; import DateRangePicker from '../components/DateRangePicker'; import PaginationControls from '../components/PaginationControls'; import ProductColorBadge from '../components/ProductColorBadge'; @@ -327,6 +327,24 @@ const Cutting = () => { filteredRows.filter(row => row.suggestedCutQuantity > 0 && materialReadinessByProductId.get(row.id)?.status === 'ready') ), [filteredRows, materialReadinessByProductId]); + const cutExecutionSummary = useMemo(() => { + const rowsWithNeed = cutPlan.needRows.filter(row => row.suggestedCutQuantity > 0); + const readyRows = rowsWithNeed.filter(row => materialReadinessByProductId.get(row.id)?.status === 'ready'); + const blockedByMaterial = rowsWithNeed.filter(row => { + const status = materialReadinessByProductId.get(row.id)?.status; + return status === 'blocked' || status === 'missing'; + }); + const blockedByData = rowsWithNeed.filter(row => materialReadinessByProductId.get(row.id)?.status === 'material_ready'); + return { + rawUnits: rowsWithNeed.reduce((total, row) => total + row.suggestedCutQuantity, 0), + readyUnits: readyRows.reduce((total, row) => total + row.suggestedCutQuantity, 0), + readyRows: readyRows.length, + blockedRows: blockedByMaterial.length + blockedByData.length, + blockedByMaterial: blockedByMaterial.length, + blockedByData: blockedByData.length, + }; + }, [cutPlan.needRows, materialReadinessByProductId]); + const orderPreviewTotalUnits = useMemo(() => ( rowsAvailableForOrder.reduce((total, row) => total + row.suggestedCutQuantity, 0) ), [rowsAvailableForOrder]); @@ -1007,8 +1025,8 @@ const Cutting = () => {
Unidades a cortar
-{formatNumber(cutPlan.summary.suggestedCutQuantity)}
+Necessidade bruta
+{formatNumber(cutExecutionSummary.rawUnits)}
{formatNumber(cutPlan.summary.skuCount)} SKUs com necessidade
Famílias
-{formatNumber(cutPlan.summary.familiesWithNeed)}
-- {cutPlan.summary.estimatedRolls === null ? 'Rolos pendentes de rendimento' : `${formatNumber(cutPlan.summary.estimatedRolls)} rolos estimados`} -
+Pronto para corte
+{formatNumber(cutExecutionSummary.readyUnits)}
+{formatNumber(cutExecutionSummary.readyRows)} SKUs liberados para gerar OP
Cores / tamanhos
-- {formatNumber(cutPlan.summary.colorsWithNeed)} / {formatNumber(cutPlan.summary.sizesWithNeed)} -
-Com corte sugerido
+Bloqueios
+{formatNumber(cutExecutionSummary.blockedRows)}
+{formatNumber(cutExecutionSummary.blockedByMaterial)} material · {formatNumber(cutExecutionSummary.blockedByData)} dados
OP aberta
-{formatNumber(cutPlan.summary.openProductionQuantity)}
-Unidades abatidas quando há match
+Famílias
+{formatNumber(cutPlan.summary.familiesWithNeed)}
+{cutPlan.summary.estimatedRolls === null ? 'Rendimento ainda não configurado' : `${formatNumber(cutPlan.summary.estimatedRolls)} rolos estimados`}
Há demanda, mas nenhum SKU está liberado para corte.
+Corrija materiais bloqueados e rendimentos antes de gerar ordens de produção.
+