From ddff880215225652dae9d21a9ceae5f96c287f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Thu, 27 Aug 2026 11:22:12 -0300 Subject: [PATCH] Add pre-cut layer and marker planning --- src/pages/Cutting.tsx | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/pages/Cutting.tsx b/src/pages/Cutting.tsx index 9c3f8b8..6a1dc04 100644 --- a/src/pages/Cutting.tsx +++ b/src/pages/Cutting.tsx @@ -168,6 +168,9 @@ const Cutting = () => { const [previewPage, setPreviewPage] = useState(1); const [previewItemsPerPage, setPreviewItemsPerPage] = useState(10); const [selectedPreviewRowIds, setSelectedPreviewRowIds] = useState([]); + const [previewQuantityOverrides, setPreviewQuantityOverrides] = useState>({}); + const [previewLayers, setPreviewLayers] = useState>({}); + const [previewMarkerReferences, setPreviewMarkerReferences] = useState>({}); const [lotSelections, setLotSelections] = useState>({}); const [productionPlanForm, setProductionPlanForm] = useState({ name: '', responsibleUserId: null as number | null, responsibleName: '', expectedDate: '', notes: '' }); const [operationalUsers, setOperationalUsers] = useState([]); @@ -391,13 +394,18 @@ const Cutting = () => { }; }, [cutPlan.needRows, materialReadinessByProductId]); + const getPreviewQuantity = (row: CutPlanSkuRow) => { + const override = Number((previewQuantityOverrides[row.id] || '').replace(',', '.')); + return Number.isFinite(override) && override > 0 ? Math.round(override) : row.suggestedCutQuantity; + }; + const selectedPreviewRows = useMemo(() => { const selectedIds = new Set(selectedPreviewRowIds); return rowsAvailableForOrder.filter(row => selectedIds.has(row.id)); }, [rowsAvailableForOrder, selectedPreviewRowIds]); const orderPreviewTotalUnits = useMemo(() => ( - selectedPreviewRows.reduce((total, row) => total + row.suggestedCutQuantity, 0) - ), [selectedPreviewRows]); + selectedPreviewRows.reduce((total, row) => total + getPreviewQuantity(row), 0) + ), [previewQuantityOverrides, selectedPreviewRows]); const selectedResponsibleUser = useMemo(() => ( operationalUsers.find((user) => user.id === productionPlanForm.responsibleUserId && user.name === productionPlanForm.responsibleName) || null ), [operationalUsers, productionPlanForm.responsibleName, productionPlanForm.responsibleUserId]); @@ -421,12 +429,12 @@ const Cutting = () => { unit: component.unit || 'UN', quantity: 0 }; - current.quantity += row.suggestedCutQuantity * component.quantityPerUnit; + current.quantity += getPreviewQuantity(row) * component.quantityPerUnit; requirements.set(key, current); }); }); return Array.from(requirements.values()).sort((a, b) => a.label.localeCompare(b.label, 'pt-BR')); - }, [compositionsByProductId, selectedPreviewRows]); + }, [compositionsByProductId, previewQuantityOverrides, selectedPreviewRows]); const selectedLotReservations = useMemo(() => ( selectedMaterialRequirements.flatMap(requirement => { @@ -675,6 +683,9 @@ const Cutting = () => { setGenerationMessage(''); setPreviewPage(1); setSelectedPreviewRowIds(rowsAvailableForOrder.map(row => row.id)); + setPreviewQuantityOverrides({}); + setPreviewLayers({}); + setPreviewMarkerReferences({}); setLotSelections({}); setProductionPlanForm({ name: cutPlanReference, responsibleUserId: null, responsibleName: '', expectedDate: '', notes: '' }); setIsPlanDetailsOpen(false); @@ -729,7 +740,7 @@ const Cutting = () => { issueDate, productSku: row.id, productDescription: row.name, - quantity: row.suggestedCutQuantity, + quantity: getPreviewQuantity(row), unit: 'UN', integrationStatus: 'Local', components: (compositionsByProductId.get(normalizeMaterialKey(row.id))?.components || []) @@ -739,12 +750,14 @@ const Cutting = () => { componentSku: component.componentSku, componentName: component.componentName, quantityPerUnit: component.quantityPerUnit, - totalQuantity: row.suggestedCutQuantity * component.quantityPerUnit, + totalQuantity: getPreviewQuantity(row) * component.quantityPerUnit, unit: component.unit })), markers: [ { label: row.family.materialLabel, color: '#38bdf8' }, ...(row.color ? [{ label: row.color, color: '#52DFA0' }] : []), + ...(Number(previewLayers[row.id]) > 0 ? [{ label: `${previewLayers[row.id]} camadas`, color: '#c084fc' }] : []), + ...(previewMarkerReferences[row.id]?.trim() ? [{ label: `Risco ${previewMarkerReferences[row.id].trim()}`, color: '#38bdf8' }] : []), { label: 'Material confirmado', color: '#52DFA0' }, ...(row.issues.length ? [{ label: 'Dados pendentes', color: '#f59e0b' }] : []) ], @@ -760,6 +773,9 @@ const Cutting = () => { stock: row.stock, openProductionQuantity: row.openProductionQuantity, availableQuantity: row.availableQuantity, + plannedLayers: Number(previewLayers[row.id]) || null, + markerReference: previewMarkerReferences[row.id]?.trim() || '', + manuallyAdjustedQuantity: getPreviewQuantity(row) !== row.suggestedCutQuantity, issues: row.issues } })), selectedLotReservations, { @@ -992,7 +1008,7 @@ const Cutting = () => {
{selectedPreviewRows.map(row => ( -
+

{row.name}

@@ -1002,10 +1018,19 @@ const Cutting = () => { {row.size || 'Sem tamanho'}
- {formatNumber(row.suggestedCutQuantity)} un. + + +
))}
+

A quantidade sugerida vem da cobertura. Ajustes manuais ficam marcados na OP; camadas e risco são referências de preparação, e o resultado real é confirmado durante a execução.

}