175 lines
5.1 KiB
JavaScript
175 lines
5.1 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import api from 'src/services/api'
|
|
|
|
function toText (value) {
|
|
return String(value ?? '').trim()
|
|
}
|
|
|
|
function toNumber (value) {
|
|
const n = parseFlexibleNumber(value)
|
|
return Number.isFinite(n) ? Number(n.toFixed(2)) : 0
|
|
}
|
|
|
|
function parseFlexibleNumber (value) {
|
|
if (typeof value === 'number') return value
|
|
const text = String(value ?? '').trim().replace(/\s/g, '')
|
|
if (!text) return 0
|
|
|
|
const lastComma = text.lastIndexOf(',')
|
|
const lastDot = text.lastIndexOf('.')
|
|
let normalized = text
|
|
|
|
if (lastComma >= 0 && lastDot >= 0) {
|
|
// Keep the last separator as decimal, remove the other as thousand.
|
|
if (lastComma > lastDot) {
|
|
normalized = text.replace(/\./g, '').replace(',', '.')
|
|
} else {
|
|
normalized = text.replace(/,/g, '')
|
|
}
|
|
} else if (lastComma >= 0) {
|
|
normalized = text.replace(/\./g, '').replace(',', '.')
|
|
} else {
|
|
normalized = text.replace(/,/g, '')
|
|
}
|
|
|
|
const n = Number(normalized)
|
|
return Number.isFinite(n) ? n : 0
|
|
}
|
|
|
|
function mapRow (raw, index, baseIndex = 0) {
|
|
return {
|
|
id: baseIndex + index + 1,
|
|
productCode: toText(raw?.ProductCode),
|
|
stockQty: toNumber(raw?.StockQty),
|
|
stockEntryDate: toText(raw?.StockEntryDate),
|
|
lastPricingDate: toText(raw?.LastPricingDate),
|
|
askiliYan: toText(raw?.AskiliYan),
|
|
kategori: toText(raw?.Kategori),
|
|
urunIlkGrubu: toText(raw?.UrunIlkGrubu),
|
|
urunAnaGrubu: toText(raw?.UrunAnaGrubu),
|
|
urunAltGrubu: toText(raw?.UrunAltGrubu),
|
|
icerik: toText(raw?.Icerik),
|
|
karisim: toText(raw?.Karisim),
|
|
marka: toText(raw?.Marka),
|
|
brandGroupSelection: toText(raw?.BrandGroupSec),
|
|
costPrice: toNumber(raw?.CostPrice),
|
|
expenseForBasePrice: 0,
|
|
basePriceUsd: 0,
|
|
basePriceTry: 0,
|
|
usd1: 0,
|
|
usd2: 0,
|
|
usd3: 0,
|
|
usd4: 0,
|
|
usd5: 0,
|
|
usd6: 0,
|
|
eur1: 0,
|
|
eur2: 0,
|
|
eur3: 0,
|
|
eur4: 0,
|
|
eur5: 0,
|
|
eur6: 0,
|
|
try1: 0,
|
|
try2: 0,
|
|
try3: 0,
|
|
try4: 0,
|
|
try5: 0,
|
|
try6: 0
|
|
}
|
|
}
|
|
|
|
export const useProductPricingStore = defineStore('product-pricing-store', {
|
|
state: () => ({
|
|
rows: [],
|
|
loading: false,
|
|
error: '',
|
|
hasMore: true
|
|
}),
|
|
|
|
actions: {
|
|
async fetchRows (options = {}) {
|
|
this.loading = true
|
|
this.error = ''
|
|
const limit = Number(options?.limit) > 0 ? Number(options.limit) : 500
|
|
const afterProductCode = toText(options?.afterProductCode)
|
|
const append = Boolean(options?.append)
|
|
const baseIndex = append ? this.rows.length : 0
|
|
const startedAt = Date.now()
|
|
console.info('[product-pricing][frontend] request:start', {
|
|
at: new Date(startedAt).toISOString(),
|
|
timeout_ms: 180000,
|
|
limit,
|
|
after_product_code: afterProductCode || null,
|
|
append
|
|
})
|
|
try {
|
|
const params = { limit }
|
|
if (afterProductCode) params.after_product_code = afterProductCode
|
|
const res = await api.request({
|
|
method: 'GET',
|
|
url: '/pricing/products',
|
|
params,
|
|
timeout: 180000
|
|
})
|
|
const traceId = res?.headers?.['x-trace-id'] || null
|
|
const hasMoreHeader = String(res?.headers?.['x-has-more'] || '').toLowerCase()
|
|
const nextCursorHeader = toText(res?.headers?.['x-next-cursor'])
|
|
const data = Array.isArray(res?.data) ? res.data : []
|
|
const mapped = data.map((x, i) => mapRow(x, i, baseIndex))
|
|
if (append) {
|
|
const merged = [...this.rows]
|
|
const seen = new Set(this.rows.map((x) => x?.productCode))
|
|
for (const row of mapped) {
|
|
const key = row?.productCode
|
|
if (key && seen.has(key)) continue
|
|
merged.push(row)
|
|
if (key) seen.add(key)
|
|
}
|
|
this.rows = merged
|
|
} else {
|
|
this.rows = mapped
|
|
}
|
|
this.hasMore = hasMoreHeader ? hasMoreHeader === 'true' : mapped.length === limit
|
|
console.info('[product-pricing][frontend] request:success', {
|
|
trace_id: traceId,
|
|
duration_ms: Date.now() - startedAt,
|
|
row_count: this.rows.length,
|
|
fetched_count: mapped.length,
|
|
has_more: this.hasMore,
|
|
next_cursor: nextCursorHeader || null
|
|
})
|
|
return {
|
|
traceId,
|
|
fetched: mapped.length,
|
|
hasMore: this.hasMore,
|
|
nextCursor: nextCursorHeader
|
|
}
|
|
} catch (err) {
|
|
if (!append) this.rows = []
|
|
this.hasMore = false
|
|
const msg = err?.response?.data || err?.message || 'Urun fiyatlandirma listesi alinamadi'
|
|
this.error = toText(msg)
|
|
console.error('[product-pricing][frontend] request:error', {
|
|
trace_id: err?.response?.headers?.['x-trace-id'] || null,
|
|
duration_ms: Date.now() - startedAt,
|
|
timeout_ms: err?.config?.timeout ?? null,
|
|
status: err?.response?.status || null,
|
|
message: this.error
|
|
})
|
|
throw err
|
|
} finally {
|
|
this.loading = false
|
|
}
|
|
},
|
|
|
|
updateCell (row, field, val) {
|
|
if (!row || !field) return
|
|
row[field] = toNumber(val)
|
|
},
|
|
|
|
updateBrandGroupSelection (row, val) {
|
|
if (!row) return
|
|
row.brandGroupSelection = toText(val)
|
|
}
|
|
}
|
|
})
|