Compare commits

..

4 Commits

Author SHA1 Message Date
Cauê Faleiros
9d99f2387b perf: limit cut plan to active orders
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 53s
2026-08-28 13:14:21 -03:00
Cauê Faleiros
4122e21dc2 perf: defer cut yield recommendations
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m10s
2026-08-28 12:53:37 -03:00
Cauê Faleiros
c5edaec7d3 Reapply "feat: open administration to all users"
This reverts commit 9f4db67f4f.
2026-08-28 12:49:22 -03:00
Cauê Faleiros
9f4db67f4f Revert "feat: open administration to all users"
This reverts commit b4b21fb21b.
2026-08-28 12:47:13 -03:00
3 changed files with 20 additions and 6 deletions

View File

@@ -884,6 +884,10 @@ const listProductionOrders = async (filters = {}) => {
)`); )`);
} }
if (filters.activeOnly === 'true') {
where.push(`po.status IN ('open', 'cutting', 'sewing', 'review', 'in_progress')`);
}
const result = await pool.query(` const result = await pool.query(`
${baseProductionOrderSelect} ${baseProductionOrderSelect}
${where.length ? `WHERE ${where.join(' AND ')}` : ''} ${where.length ? `WHERE ${where.join(' AND ')}` : ''}

View File

@@ -222,12 +222,13 @@ export const downloadDatabaseDiagnostic = async (): Promise<void> => {
export const fetchProductionOrders = async ( export const fetchProductionOrders = async (
dateRange: DateRange, dateRange: DateRange,
filters?: { search?: string }, filters?: { search?: string; activeOnly?: boolean },
options?: CacheOptions options?: CacheOptions
): Promise<ProductionOrderSummary> => { ): Promise<ProductionOrderSummary> => {
const params = buildDateRangeParams(dateRange); const params = buildDateRangeParams(dateRange);
const search = filters?.search?.trim(); const search = filters?.search?.trim();
if (search) params.set('search', search); if (search) params.set('search', search);
if (filters?.activeOnly) params.set('activeOnly', 'true');
const path = `/production-orders?${params.toString()}`; const path = `/production-orders?${params.toString()}`;
return getCachedAnalytics(path, async () => { return getCachedAnalytics(path, async () => {

View File

@@ -157,6 +157,7 @@ const Cutting = () => {
const [settingsSection, setSettingsSection] = useState<SettingsSection>('rules'); const [settingsSection, setSettingsSection] = useState<SettingsSection>('rules');
const [cuttingSettings, setCuttingSettings] = useState<CuttingSettings>(loadCuttingSettings); const [cuttingSettings, setCuttingSettings] = useState<CuttingSettings>(loadCuttingSettings);
const [yieldRecommendations, setYieldRecommendations] = useState<ProductionYieldRecommendation[]>([]); const [yieldRecommendations, setYieldRecommendations] = useState<ProductionYieldRecommendation[]>([]);
const [hasLoadedYieldRecommendations, setHasLoadedYieldRecommendations] = useState(false);
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle'); const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle');
const [hasUnsavedSettings, setHasUnsavedSettings] = useState(false); const [hasUnsavedSettings, setHasUnsavedSettings] = useState(false);
const [correctionIssueFilter, setCorrectionIssueFilter] = useState<CorrectionIssueFilter>('all'); const [correctionIssueFilter, setCorrectionIssueFilter] = useState<CorrectionIssueFilter>('all');
@@ -214,14 +215,22 @@ const Cutting = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!isSettingsOpen || settingsSection !== 'rules' || hasLoadedYieldRecommendations) return;
let isMounted = true; let isMounted = true;
void fetchProductionOrderImportData().then(data => { void fetchProductionOrderImportData().then(data => {
if (isMounted) setYieldRecommendations(data.recommendations); if (isMounted) {
setYieldRecommendations(data.recommendations);
setHasLoadedYieldRecommendations(true);
}
}).catch(() => { }).catch(() => {
if (isMounted) setYieldRecommendations([]); if (isMounted) {
setYieldRecommendations([]);
setHasLoadedYieldRecommendations(true);
}
}); });
return () => { isMounted = false; }; return () => { isMounted = false; };
}, []); }, [hasLoadedYieldRecommendations, isSettingsOpen, settingsSection]);
useEffect(() => { useEffect(() => {
let isMounted = true; let isMounted = true;
@@ -230,7 +239,7 @@ const Cutting = () => {
setIsLoading(true); setIsLoading(true);
const [productData, productionOrderData, compositionData, stockData, supplySummary] = await Promise.all([ const [productData, productionOrderData, compositionData, stockData, supplySummary] = await Promise.all([
fetchProductAnalytics(dateRange), fetchProductAnalytics(dateRange),
fetchProductionOrders(allProductionOrdersRange), fetchProductionOrders(allProductionOrdersRange, { activeOnly: true }),
fetchProductCompositions(), fetchProductCompositions(),
fetchStock(), fetchStock(),
fetchSupplySummary() fetchSupplySummary()
@@ -785,7 +794,7 @@ const Cutting = () => {
source: 'cut_plan' source: 'cut_plan'
}); });
const refreshedOrders = await fetchProductionOrders(allProductionOrdersRange, undefined, { force: true }); const refreshedOrders = await fetchProductionOrders(allProductionOrdersRange, { activeOnly: true }, { force: true });
setProductionOrders(refreshedOrders.orders); setProductionOrders(refreshedOrders.orders);
setGenerationMessage(`${result.plan?.number || 'Plano'} criado com ${result.created.length} OPs${result.skipped.length ? ` · ${result.skipped.length} já existiam abertas` : ''}.`); setGenerationMessage(`${result.plan?.number || 'Plano'} criado com ${result.created.length} OPs${result.skipped.length ? ` · ${result.skipped.length} já existiam abertas` : ''}.`);
setIsOrderPreviewOpen(false); setIsOrderPreviewOpen(false);