diff --git a/ui/src/stores/orderentryStore.js b/ui/src/stores/orderentryStore.js index e46216b..c9e157e 100644 --- a/ui/src/stores/orderentryStore.js +++ b/ui/src/stores/orderentryStore.js @@ -1018,6 +1018,37 @@ export const useOrderEntryStore = defineStore('orderentry', { throw new Error('Backend header yok') } + // Editor ile aynı grpKey kararını verebilmek için + // eksik model metadata'sını (kategori/ana-alt grup) cache'e al. + const backendLines = Array.isArray(backend?.lines) ? backend.lines : [] + const modelCodes = [...new Set( + backendLines + .map(l => String(l?.ItemCode || l?.Model || '').trim()) + .filter(Boolean) + )] + const missingCodes = modelCodes.filter(code => !pc?.[code]) + if (missingCodes.length) { + await Promise.all( + missingCodes.map(async code => { + try { + const d = (await api.get('/product-detail', { params: { code } }))?.data || {} + pc[code] = { + ...(pc[code] || {}), + ...d, + UrunAnaGrubu: d.UrunAnaGrubu || d.ProductGroup || d.ProductAtt01Desc || '', + UrunAltGrubu: d.UrunAltGrubu || d.ProductSubGroup || d.ProductAtt02Desc || '', + Kategori: d.Kategori || '', + YETISKIN_GARSON: d.YETISKIN_GARSON || d.YetiskinGarson || d.AskiliYan || '', + YetiskinGarson: d.YetiskinGarson || d.YETISKIN_GARSON || d.AskiliYan || '', + AskiliYan: d.AskiliYan || '' + } + } catch (e) { + console.warn(`⚠ model detail alınamadı (${code})`, e) + } + }) + ) + } + /* ======================================================= 🔹 HEADER — SADECE BACKEND (orderlist açılışında local merge YOK) @@ -1035,7 +1066,7 @@ export const useOrderEntryStore = defineStore('orderentry', { ✔ row.isClosed (boolean) ======================================================= */ const normalized = this.normalizeOrderLines( - backend.lines || [], + backendLines, this.header.DocCurrencyCode || 'USD', pc ) @@ -2371,10 +2402,11 @@ export const useOrderEntryStore = defineStore('orderentry', { ✔ aksbir → ' ' bedeni = GERÇEK adet ✔ backend satırlarında BEDEN → OrderLineID map’i üretilir =========================================================== */ - normalizeOrderLines(lines, pbFallback = 'USD') { + normalizeOrderLines(lines, pbFallback = 'USD', productCache = null) { if (!Array.isArray(lines)) return [] const merged = Object.create(null) + const pc = (productCache && typeof productCache === 'object') ? productCache : {} const makeBaseKey = (model, renk, renk2) => `${model || ''}||${renk || ''}||${renk2 || ''}` @@ -2397,6 +2429,7 @@ export const useOrderEntryStore = defineStore('orderentry', { const model = (raw.model || raw.ItemCode || '').trim() const renk = (raw.renk || raw.ColorCode || '').trim() const renk2 = (raw.renk2 || raw.ItemDim2Code || '').trim() + const meta = pc?.[model] || {} // ❗ BEDEN YOK → bu SADECE üst seviye grup anahtarı const modelKey = `${model}||${renk}||${renk2}` @@ -2416,17 +2449,20 @@ export const useOrderEntryStore = defineStore('orderentry', { const grpKey = groupedKey || detectBedenGroup( - Object.keys(srcMap || {}), - raw.urunAnaGrubu || raw.UrunAnaGrubu || '', - raw.kategori || raw.Kategori || '', + null, + raw.urunAnaGrubu || raw.UrunAnaGrubu || meta.UrunAnaGrubu || meta.ProductGroup || '', + raw.kategori || raw.Kategori || meta.Kategori || '', raw.yetiskinGarson || raw.YETISKIN_GARSON || raw.YetiskinGarson || raw.AskiliYan || raw.ASKILIYAN || raw.askiliyan || + meta.YETISKIN_GARSON || + meta.YetiskinGarson || + meta.AskiliYan || '', - raw.urunAltGrubu || raw.UrunAltGrubu || '' + raw.urunAltGrubu || raw.UrunAltGrubu || meta.UrunAltGrubu || meta.ProductSubGroup || '' ) || 'tak' @@ -2460,6 +2496,7 @@ export const useOrderEntryStore = defineStore('orderentry', { const model = (raw.Model || raw.ItemCode || '').trim() const renk = (raw.ColorCode || '').trim() const renk2 = (raw.ItemDim2Code || '').trim() + const meta = pc?.[model] || {} // ❗ BEDEN HARİÇ — üst seviye grup anahtarı const modelKey = `${model}||${renk}||${renk2}` @@ -2483,13 +2520,16 @@ export const useOrderEntryStore = defineStore('orderentry', { renk, renk2, - urunAnaGrubu: raw.UrunAnaGrubu || 'GENEL', - urunAltGrubu: raw.UrunAltGrubu || '', + urunAnaGrubu: raw.UrunAnaGrubu || meta.UrunAnaGrubu || meta.ProductGroup || 'GENEL', + urunAltGrubu: raw.UrunAltGrubu || meta.UrunAltGrubu || meta.ProductSubGroup || '', kategori: raw.Kategori || raw.YETISKIN_GARSON || raw.YetiskinGarson || raw.yetiskinGarson || + meta.Kategori || + meta.YETISKIN_GARSON || + meta.YetiskinGarson || '', yetiskinGarson: raw.YETISKIN_GARSON || @@ -2498,6 +2538,9 @@ export const useOrderEntryStore = defineStore('orderentry', { raw.AskiliYan || raw.ASKILIYAN || raw.askiliyan || + meta.YETISKIN_GARSON || + meta.YetiskinGarson || + meta.AskiliYan || '', aciklama: raw.LineDescription || '', @@ -2549,11 +2592,9 @@ export const useOrderEntryStore = defineStore('orderentry', { continue } - const bedenList = Object.keys(row.__tmpMap) - // 🔒 TEK VE KESİN KARAR const grpKey = detectBedenGroup( - bedenList, + null, row.urunAnaGrubu, row.kategori || '', row.yetiskinGarson, @@ -3798,26 +3839,46 @@ function resolveGroupFromProductSizeMatchRules( } const kategoriToken = deriveKategoriToken(urunKategori, yetiskinGarson) + const kategoriRaw = normalizeTextForMatch(urunKategori || '') const ana = normalizeTextForMatch(urunAnaGrubu || '') const alt = normalizeRuleAltGroup(urunAltGrubu) - if (!kategoriToken || !ana) return '' + if (!ana) return '' + + const bestScoreGroupKeys = [] + let bestScore = -1 - const candidateGroupKeys = [] for (const rule of productSizeMatchCache.rules) { if (!rule?.urunAnaGrubu || rule.urunAnaGrubu !== ana) continue - if (rule.kategori !== kategoriToken) continue + + const ruleKategori = normalizeTextForMatch(rule.kategori || '') + const catExact = + (kategoriToken && ruleKategori === kategoriToken) || + (kategoriRaw && ruleKategori === kategoriRaw) + const catWildcard = ruleKategori === '' + if (!catExact && !catWildcard) continue + const ruleAlt = normalizeTextForMatch(rule.urunAltGrubu || '') - if (ruleAlt !== alt) continue + const altExact = !!alt && ruleAlt === alt + const altWildcard = ruleAlt === '' + if (!altExact && !altWildcard) continue + + const score = (catExact ? 2 : 0) + (altExact ? 1 : 0) + if (score < bestScore) continue + if (score > bestScore) { + bestScore = score + bestScoreGroupKeys.length = 0 + } + for (const g of (rule.groupKeys || [])) { const key = String(g || '').trim() - if (key && !candidateGroupKeys.includes(key)) { - candidateGroupKeys.push(key) + if (key && !bestScoreGroupKeys.includes(key)) { + bestScoreGroupKeys.push(key) } } } - if (!candidateGroupKeys.length) return '' - return pickBestGroupFromCandidates(candidateGroupKeys, bedenList) + if (!bestScoreGroupKeys.length) return '' + return pickBestGroupFromCandidates(bestScoreGroupKeys, bedenList) } /* ===========================================================