Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -5,11 +5,35 @@ import api from 'src/services/api'
|
||||
export const useOrderProductionItemStore = defineStore('orderproductionitems', {
|
||||
state: () => ({
|
||||
items: [],
|
||||
header: null,
|
||||
products: [],
|
||||
colorOptionsByCode: {},
|
||||
secondColorOptionsByKey: {},
|
||||
loading: false,
|
||||
saving: false,
|
||||
error: null
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async fetchHeader (orderHeaderID) {
|
||||
if (!orderHeaderID) {
|
||||
this.header = null
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const res = await api.get(`/order/get/${encodeURIComponent(orderHeaderID)}`)
|
||||
this.header = res?.data?.header || null
|
||||
} catch (err) {
|
||||
this.header = null
|
||||
this.error = err?.response?.data || err?.message || 'Siparis bilgisi alinamadi'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async fetchItems (orderHeaderID) {
|
||||
if (!orderHeaderID) {
|
||||
this.items = []
|
||||
@@ -25,10 +49,99 @@ export const useOrderProductionItemStore = defineStore('orderproductionitems', {
|
||||
this.items = Array.isArray(data) ? data : []
|
||||
} catch (err) {
|
||||
this.items = []
|
||||
this.error = err?.response?.data || err?.message || 'Liste alınamadı'
|
||||
this.error = err?.response?.data || err?.message || 'Liste alinamadi'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async fetchProducts () {
|
||||
this.error = null
|
||||
try {
|
||||
const res = await api.get('/products')
|
||||
const data = res?.data
|
||||
this.products = Array.isArray(data) ? data : []
|
||||
} catch (err) {
|
||||
this.products = []
|
||||
this.error = err?.response?.data || err?.message || 'Urun listesi alinamadi'
|
||||
}
|
||||
},
|
||||
async fetchColors (productCode) {
|
||||
const code = String(productCode || '').trim()
|
||||
if (!code) return []
|
||||
|
||||
if (this.colorOptionsByCode[code]) {
|
||||
return this.colorOptionsByCode[code]
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await api.get('/product-colors', { params: { code } })
|
||||
const data = res?.data
|
||||
const list = Array.isArray(data) ? data : []
|
||||
this.colorOptionsByCode[code] = list
|
||||
return list
|
||||
} catch (err) {
|
||||
this.error = err?.response?.data || err?.message || 'Renk listesi alinamadi'
|
||||
return []
|
||||
}
|
||||
},
|
||||
async fetchSecondColors (productCode, colorCode) {
|
||||
const code = String(productCode || '').trim()
|
||||
const color = String(colorCode || '').trim()
|
||||
if (!code || !color) return []
|
||||
|
||||
const key = `${code}::${color}`
|
||||
if (this.secondColorOptionsByKey[key]) {
|
||||
return this.secondColorOptionsByKey[key]
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await api.get('/product-secondcolor', { params: { code, color } })
|
||||
const data = res?.data
|
||||
const list = Array.isArray(data) ? data : []
|
||||
this.secondColorOptionsByKey[key] = list
|
||||
return list
|
||||
} catch (err) {
|
||||
this.error = err?.response?.data || err?.message || '2. renk listesi alinamadi'
|
||||
return []
|
||||
}
|
||||
},
|
||||
async validateUpdates (orderHeaderID, lines) {
|
||||
if (!orderHeaderID) return { missingCount: 0, missing: [] }
|
||||
|
||||
this.saving = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const res = await api.post(
|
||||
`/orders/production-items/${encodeURIComponent(orderHeaderID)}/validate`,
|
||||
{ lines }
|
||||
)
|
||||
return res?.data || { missingCount: 0, missing: [] }
|
||||
} catch (err) {
|
||||
this.error = err?.response?.data || err?.message || 'Kontrol basarisiz'
|
||||
throw err
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
},
|
||||
async applyUpdates (orderHeaderID, lines, insertMissing) {
|
||||
if (!orderHeaderID) return { updated: 0, inserted: 0 }
|
||||
|
||||
this.saving = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const res = await api.post(
|
||||
`/orders/production-items/${encodeURIComponent(orderHeaderID)}/apply`,
|
||||
{ lines, insertMissing }
|
||||
)
|
||||
return res?.data || { updated: 0, inserted: 0 }
|
||||
} catch (err) {
|
||||
this.error = err?.response?.data || err?.message || 'Guncelleme basarisiz'
|
||||
throw err
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1701,14 +1701,15 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
: {}
|
||||
|
||||
/* ===== SAME COMBO → UPDATE ===== */
|
||||
if (sameCombo) {
|
||||
rows[idx] = {
|
||||
...prev,
|
||||
...newRow,
|
||||
id: prev.id,
|
||||
OrderLineID: prev.OrderLineID || null,
|
||||
lineIdMap: preservedLineIdMap
|
||||
}
|
||||
if (sameCombo) {
|
||||
rows[idx] = {
|
||||
...prev,
|
||||
...newRow,
|
||||
_dirty: true,
|
||||
id: prev.id,
|
||||
OrderLineID: prev.OrderLineID || null,
|
||||
lineIdMap: preservedLineIdMap
|
||||
}
|
||||
|
||||
this.summaryRows = rows
|
||||
this.orders = rows
|
||||
@@ -1761,12 +1762,13 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
comboLineIds: { ...(prev.comboLineIds || {}) }
|
||||
}
|
||||
|
||||
const insertedRow = {
|
||||
...newRow,
|
||||
id: crypto.randomUUID(),
|
||||
OrderLineID: null,
|
||||
lineIdMap: {}
|
||||
}
|
||||
const insertedRow = {
|
||||
...newRow,
|
||||
_dirty: true,
|
||||
id: crypto.randomUUID(),
|
||||
OrderLineID: null,
|
||||
lineIdMap: {}
|
||||
}
|
||||
|
||||
rows.splice(idx, 1, insertedRow)
|
||||
|
||||
@@ -1835,13 +1837,14 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
const price = Number(newRow?.fiyat ?? prev?.fiyat ?? 0)
|
||||
const totalTutar = Number((totalAdet * price).toFixed(2))
|
||||
|
||||
rows[dupIdx] = {
|
||||
...prev,
|
||||
...newRow,
|
||||
rows[dupIdx] = {
|
||||
...prev,
|
||||
...newRow,
|
||||
_dirty: true,
|
||||
|
||||
// kritik korumalar
|
||||
id: prev.id,
|
||||
OrderLineID: prev.OrderLineID || null,
|
||||
// kritik korumalar
|
||||
id: prev.id,
|
||||
OrderLineID: prev.OrderLineID || null,
|
||||
lineIdMap: { ...(prev.lineIdMap || {}) },
|
||||
|
||||
// MERGED bedenMap
|
||||
@@ -1869,12 +1872,13 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
}
|
||||
|
||||
// dup yoksa (veya dup delete satırıydı) → yeni satır
|
||||
rows.push({
|
||||
...newRow,
|
||||
id: newRow.id || crypto.randomUUID(),
|
||||
OrderLineID: null,
|
||||
lineIdMap: { ...(newRow.lineIdMap || {}) }
|
||||
})
|
||||
rows.push({
|
||||
...newRow,
|
||||
_dirty: true,
|
||||
id: newRow.id || crypto.randomUUID(),
|
||||
OrderLineID: null,
|
||||
lineIdMap: { ...(newRow.lineIdMap || {}) }
|
||||
})
|
||||
|
||||
this.summaryRows = rows
|
||||
this.orders = rows
|
||||
@@ -2633,7 +2637,12 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
// 🧪 PRE-VALIDATE — prItemVariant ön kontrol
|
||||
// - invalid varsa CREATE/UPDATE ÇALIŞMAZ
|
||||
// =======================================================
|
||||
const v = await api.post('/order/validate', { header, lines })
|
||||
const linesToValidate =
|
||||
isNew
|
||||
? lines
|
||||
: lines.filter(l => l._deleteSignal === true || l._dirty === true || !l.OrderLineID)
|
||||
|
||||
const v = await api.post('/order/validate', { header, lines: linesToValidate })
|
||||
const invalid = v?.data?.invalid || []
|
||||
|
||||
if (invalid.length > 0) {
|
||||
@@ -2969,10 +2978,12 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
// ComboKey stabil kalsın diye bedenKey kullan
|
||||
const comboKey = buildComboKey(row, bedenKey)
|
||||
|
||||
const makeLine = () => ({
|
||||
OrderLineID: orderLineId || '',
|
||||
ClientKey: makeLineClientKey(row, grpKey, bedenKey),
|
||||
ComboKey: comboKey,
|
||||
const makeLine = () => ({
|
||||
OrderLineID: orderLineId || '',
|
||||
ClientKey: makeLineClientKey(row, grpKey, bedenKey),
|
||||
ComboKey: comboKey,
|
||||
_dirty: row?._dirty === true,
|
||||
_deleteSignal: isDeleteSignal === true,
|
||||
|
||||
SortOrder: 0,
|
||||
ItemTypeCode: 1,
|
||||
@@ -3040,26 +3051,30 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
||||
DOVCode: ''
|
||||
})
|
||||
|
||||
const existing = lineByCombo.get(comboKey)
|
||||
const existing = lineByCombo.get(comboKey)
|
||||
|
||||
if (!existing) {
|
||||
const ln = makeLine()
|
||||
lineByCombo.set(comboKey, ln)
|
||||
lines.push(ln)
|
||||
return
|
||||
}
|
||||
if (!existing) {
|
||||
const ln = makeLine()
|
||||
lineByCombo.set(comboKey, ln)
|
||||
lines.push(ln)
|
||||
return
|
||||
}
|
||||
|
||||
/* DELETE */
|
||||
if (isDeleteSignal) {
|
||||
if (orderLineId && !existing.OrderLineID) {
|
||||
existing.OrderLineID = orderLineId
|
||||
if (isDeleteSignal) {
|
||||
if (orderLineId && !existing.OrderLineID) {
|
||||
existing.OrderLineID = orderLineId
|
||||
}
|
||||
existing._deleteSignal = true
|
||||
existing.Qty1 = 0
|
||||
return
|
||||
}
|
||||
existing.Qty1 = 0
|
||||
return
|
||||
}
|
||||
|
||||
/* MERGE */
|
||||
existing.Qty1 += qty
|
||||
/* MERGE */
|
||||
existing.Qty1 += qty
|
||||
if (row?._dirty === true) {
|
||||
existing._dirty = true
|
||||
}
|
||||
|
||||
if (this.mode === 'edit' && orderLineId && !existing.OrderLineID) {
|
||||
existing.OrderLineID = orderLineId
|
||||
@@ -3346,66 +3361,56 @@ export function normalizeBeden(v) {
|
||||
- Keeps frontend aksbir bucket for accessory lines
|
||||
=========================================================== */
|
||||
export function detectBedenGroup(bedenList, urunAnaGrubu = '', urunKategori = '') {
|
||||
const list = Array.isArray(bedenList) ? bedenList : []
|
||||
const ana = normalizeTextForMatch(urunAnaGrubu)
|
||||
const alt = normalizeTextForMatch(urunKategori)
|
||||
const list = Array.isArray(bedenList) && bedenList.length > 0
|
||||
? bedenList.map(v => (v || '').toString().trim().toUpperCase())
|
||||
: [' ']
|
||||
|
||||
// Frontend compatibility: accessory-only products should stay in aksbir.
|
||||
const accessoryGroups = [
|
||||
'AKSESUAR', 'KRAVAT', 'PAPYON', 'KEMER', 'CORAP',
|
||||
'FULAR', 'MENDIL', 'KASKOL', 'ASKI', 'YAKA', 'KOL DUGMESI'
|
||||
const ana = (urunAnaGrubu || '')
|
||||
.toUpperCase()
|
||||
.trim()
|
||||
.replace(/\(.*?\)/g, '')
|
||||
.replace(/[^A-ZÇĞİÖŞÜ0-9\s]/g, '')
|
||||
.replace(/\s+/g, ' ')
|
||||
|
||||
const kat = (urunKategori || '').toUpperCase().trim()
|
||||
// 🔸 Aksesuar ise "aksbir"
|
||||
const aksesuarGruplari = [
|
||||
'AKSESUAR','KRAVAT','PAPYON','KEMER','CORAP','ÇORAP',
|
||||
'FULAR','MENDIL','MENDİL','KASKOL','ASKI',
|
||||
'YAKA','KOL DUGMESI','KOL DÜĞMESİ'
|
||||
]
|
||||
const clothingGroups = ['GOMLEK', 'CEKET', 'PANTOLON', 'MONT', 'YELEK', 'TAKIM', 'TSHIRT']
|
||||
const giyimGruplari = ['GÖMLEK','CEKET','PANTOLON','MONT','YELEK','TAKIM','TSHIRT','TİŞÖRT']
|
||||
// 🔸 Pantolon özel durumu
|
||||
if (
|
||||
accessoryGroups.some(g => ana.includes(g) || alt.includes(g)) &&
|
||||
!clothingGroups.some(g => ana.includes(g))
|
||||
) {
|
||||
return 'aksbir'
|
||||
aksesuarGruplari.some(g => ana.includes(g) || kat.includes(g)) &&
|
||||
!giyimGruplari.some(g => ana.includes(g))
|
||||
) return 'aksbir'
|
||||
|
||||
if (ana.includes('PANTOLON') && kat.includes('YETİŞKİN')) return 'pan'
|
||||
// 🔸 Tamamen numerik (örneğin 39-44 arası) → ayakkabı
|
||||
const allNumeric = list.every(v => /^\d+$/.test(v))
|
||||
if (allNumeric) {
|
||||
const nums = list.map(v => parseInt(v, 10)).filter(Boolean)
|
||||
const diffs = nums.slice(1).map((v, i) => v - nums[i])
|
||||
if (diffs.every(d => d === 1) && nums[0] >= 35 && nums[0] <= 46) return 'ayk'
|
||||
}
|
||||
|
||||
if (ana.includes('AYAKKABI') || alt.includes('AYAKKABI')) {
|
||||
return 'ayk'
|
||||
}
|
||||
// 🔸 Yaş grubu (çocuk/garson)
|
||||
if (kat.includes('GARSON') || kat.includes('ÇOCUK')) return 'yas'
|
||||
|
||||
let hasYasNumeric = false
|
||||
let hasAykNumeric = false
|
||||
let hasPanNumeric = false
|
||||
// 🔸 Harfli beden varsa doğrudan "gom" (gömlek, üst giyim)
|
||||
const harfliBedenler = ['XS','S','M','L','XL','XXL','3XL','4XL']
|
||||
if (list.some(b => harfliBedenler.includes(b))) return 'gom'
|
||||
|
||||
for (const raw of list) {
|
||||
const b = safeTrimUpperJs(raw)
|
||||
|
||||
switch (b) {
|
||||
case 'XS':
|
||||
case 'S':
|
||||
case 'M':
|
||||
case 'L':
|
||||
case 'XL':
|
||||
case '2XL':
|
||||
case '3XL':
|
||||
case '4XL':
|
||||
case '5XL':
|
||||
case '6XL':
|
||||
case '7XL':
|
||||
return 'gom'
|
||||
}
|
||||
|
||||
const n = parseNumericSizeJs(b)
|
||||
if (n == null) continue
|
||||
|
||||
if (n >= 2 && n <= 14) hasYasNumeric = true
|
||||
if (n >= 39 && n <= 45) hasAykNumeric = true
|
||||
if (n >= 38 && n <= 68) hasPanNumeric = true
|
||||
}
|
||||
|
||||
if (hasAykNumeric) return 'ayk'
|
||||
if (ana.includes('PANTOLON')) return 'pan'
|
||||
if (hasPanNumeric) return 'pan'
|
||||
if (alt.includes('COCUK') || alt.includes('GARSON')) return 'yas'
|
||||
if (hasYasNumeric) return 'yas'
|
||||
|
||||
// 🔸 Varsayılan: takım elbise
|
||||
return 'tak'
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function toSummaryRowFromForm(form) {
|
||||
if (!form) return null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user