Fix product performance grouped JSON build
This commit is contained in:
@@ -3239,16 +3239,16 @@ SELECT (
|
||||
'image_product_code', image_product_code,
|
||||
'image_color_code', image_color_code,
|
||||
'image_yaka_kodu', image_yaka_kodu,
|
||||
'product_code', CASE WHEN $%d = 'product_code' THEN group_value ELSE product_code END,
|
||||
'color_code', CASE WHEN $%d = 'color_code' THEN group_value ELSE color_code END,
|
||||
'yaka_kodu', CASE WHEN $%d = 'yaka_kodu' THEN group_value ELSE yaka_kodu END,
|
||||
'item_description', item_description,
|
||||
'kategori', CASE WHEN $%d = 'kategori' THEN group_value ELSE kategori END,
|
||||
'askili_yan', CASE WHEN $%d = 'askili_yan' THEN group_value ELSE askili_yan END,
|
||||
'urun_ilk_grubu', CASE WHEN $%d = 'urun_ilk_grubu' THEN group_value ELSE urun_ilk_grubu END,
|
||||
'urun_ana_grubu', CASE WHEN $%d = 'urun_ana_grubu' THEN group_value ELSE urun_ana_grubu END,
|
||||
'urun_alt_grubu', CASE WHEN $%d = 'urun_alt_grubu' THEN group_value ELSE urun_alt_grubu END,
|
||||
'market_key', CASE WHEN $%d = 'market_key' THEN group_value ELSE market_key END
|
||||
'product_code', CASE WHEN $%d = 'product_code' THEN group_value ELSE '' END,
|
||||
'color_code', CASE WHEN $%d = 'color_code' THEN group_value ELSE '' END,
|
||||
'yaka_kodu', CASE WHEN $%d = 'yaka_kodu' THEN group_value ELSE '' END,
|
||||
'item_description', CASE WHEN $%d = 'item_description' THEN group_value ELSE '' END,
|
||||
'kategori', CASE WHEN $%d = 'kategori' THEN group_value ELSE '' END,
|
||||
'askili_yan', CASE WHEN $%d = 'askili_yan' THEN group_value ELSE '' END,
|
||||
'urun_ilk_grubu', CASE WHEN $%d = 'urun_ilk_grubu' THEN group_value ELSE '' END,
|
||||
'urun_ana_grubu', CASE WHEN $%d = 'urun_ana_grubu' THEN group_value ELSE '' END,
|
||||
'urun_alt_grubu', CASE WHEN $%d = 'urun_alt_grubu' THEN group_value ELSE '' END,
|
||||
'market_key', CASE WHEN $%d = 'market_key' THEN group_value ELSE '' END
|
||||
)
|
||||
|| jsonb_build_object(
|
||||
'stock_qty', stock_qty,
|
||||
@@ -3377,7 +3377,7 @@ FROM (
|
||||
GROUP BY COALESCE(%s, '')
|
||||
) g
|
||||
ORDER BY group_value
|
||||
`, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, groupExpr, groupExpr, whereSQL, groupExpr)
|
||||
`, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, groupExpr, groupExpr, whereSQL, groupExpr)
|
||||
args = append(args, field)
|
||||
return queryProductPerformanceJSONRows(ctx, pg, query, args...)
|
||||
}
|
||||
@@ -3678,6 +3678,7 @@ func appendProductPerformanceGroupedRows(out *[]map[string]any, sourceRows []map
|
||||
|
||||
func makeProductPerformanceGroupedRow(key string, level int, field, value string, rows []map[string]any) map[string]any {
|
||||
row := aggregateProductPerformanceRows(rows, field)
|
||||
clearProductPerformanceGroupDimensions(row, field, value)
|
||||
row["__group"] = true
|
||||
row["row_key"] = "group|" + key
|
||||
row["key"] = key
|
||||
@@ -3686,7 +3687,6 @@ func makeProductPerformanceGroupedRow(key string, level int, field, value string
|
||||
row["group_value"] = value
|
||||
row["label"] = value
|
||||
row["count"] = len(rows)
|
||||
row[field] = value
|
||||
row["recommendation"] = fmt.Sprintf("%d satır", len(rows))
|
||||
|
||||
image := firstProductPerformanceImageSource(rows)
|
||||
@@ -3696,6 +3696,33 @@ func makeProductPerformanceGroupedRow(key string, level int, field, value string
|
||||
return row
|
||||
}
|
||||
|
||||
var productPerformanceGroupDimensionFields = map[string]bool{
|
||||
"product_code": true,
|
||||
"color_yaka": true,
|
||||
"color_code": true,
|
||||
"yaka_kodu": true,
|
||||
"item_description": true,
|
||||
"kategori": true,
|
||||
"askili_yan": true,
|
||||
"urun_ilk_grubu": true,
|
||||
"urun_ana_grubu": true,
|
||||
"urun_alt_grubu": true,
|
||||
"market_key": true,
|
||||
"country": true,
|
||||
"customer_segment": true,
|
||||
"customer_code": true,
|
||||
"customer_name": true,
|
||||
}
|
||||
|
||||
func clearProductPerformanceGroupDimensions(row map[string]any, groupField, groupValue string) {
|
||||
for field := range productPerformanceGroupDimensionFields {
|
||||
row[field] = ""
|
||||
}
|
||||
if productPerformanceGroupDimensionFields[groupField] {
|
||||
row[groupField] = groupValue
|
||||
}
|
||||
}
|
||||
|
||||
func aggregateProductPerformanceRows(rows []map[string]any, groupField string) map[string]any {
|
||||
out := map[string]any{}
|
||||
for _, row := range rows {
|
||||
|
||||
@@ -273,7 +273,7 @@ func GetProductPerformanceGroupedHandler(pg *sql.DB) http.HandlerFunc {
|
||||
groupLevels := splitCSVQuery(r.URL.Query().Get("group_levels"))
|
||||
limit := intQuery(r, "limit", 50000)
|
||||
expanded := map[string]bool{}
|
||||
const maxExpandedGroupKeys = 200
|
||||
const maxExpandedGroupKeys = 260
|
||||
addExpandedKey := func(key string) {
|
||||
key = strings.TrimSpace(key)
|
||||
if key != "" && len(expanded) < maxExpandedGroupKeys {
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
class="period-selector bg-white q-px-xs q-py-none"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
v-model="detailLevelMenuOpen"
|
||||
dense
|
||||
outline
|
||||
color="primary"
|
||||
@@ -1560,6 +1561,7 @@ const selectedPeriods = ref(['90', '180', '360', 'total'])
|
||||
const selectedDetailMainGroup = ref('')
|
||||
const imageUrlByKey = ref({})
|
||||
const imageListByKey = ref({})
|
||||
const imageFailedKeys = ref(new Set())
|
||||
const imageDialog = ref(false)
|
||||
const imageDialogUrls = ref([])
|
||||
const imageDialogTitle = ref('')
|
||||
@@ -1579,6 +1581,7 @@ const imagePrimeLoading = ref(false)
|
||||
const filterBusy = ref(false)
|
||||
const bulkExpandLoading = ref(false)
|
||||
const generalRowsLoaded = ref(false)
|
||||
const detailLevelMenuOpen = ref(false)
|
||||
let backendGroupedTimer = null
|
||||
let imagePrimeActiveRequests = 0
|
||||
|
||||
@@ -2940,9 +2943,9 @@ function sortValueForColumnName (row, columnName) {
|
||||
function makeGroupRow (key, level, groupDef, value, groupRows) {
|
||||
const imageSource = groupRows.find(row => row?.product_code) || {}
|
||||
const aggregate = aggregateGroupFields(groupRows, groupDef.key)
|
||||
const colorSummary = groupDef.key === 'color_code' ? value : distinctSummary(groupRows, 'color_code')
|
||||
const yakaSummary = groupDef.key === 'yaka_kodu' ? value : distinctSummary(groupRows, 'yaka_kodu')
|
||||
const colorDescriptionSummary = distinctSummary(groupRows, 'color_description')
|
||||
const colorSummary = groupDef.key === 'color_code' ? value : ''
|
||||
const yakaSummary = groupDef.key === 'yaka_kodu' ? value : ''
|
||||
const colorDescriptionSummary = groupDef.key === 'color_code' ? distinctSummary(groupRows, 'color_description') : ''
|
||||
return {
|
||||
__group: true,
|
||||
row_key: `group|${key}`,
|
||||
@@ -2956,21 +2959,21 @@ function makeGroupRow (key, level, groupDef, value, groupRows) {
|
||||
image_color_code: imageSource.color_code || '',
|
||||
image_color_description: imageSource.color_description || '',
|
||||
image_yaka_kodu: imageSource.yaka_kodu || '',
|
||||
product_code: groupDef.key === 'product_code' ? value : distinctSummary(groupRows, 'product_code'),
|
||||
product_code: groupDef.key === 'product_code' ? value : '',
|
||||
color_code: colorSummary,
|
||||
color_description: colorDescriptionSummary,
|
||||
yaka_kodu: yakaSummary,
|
||||
item_description: distinctSummary(groupRows, 'item_description'),
|
||||
kategori: groupDef.key === 'kategori' ? value : distinctSummary(groupRows, 'kategori'),
|
||||
urun_ilk_grubu: groupDef.key === 'urun_ilk_grubu' ? value : distinctSummary(groupRows, 'urun_ilk_grubu'),
|
||||
askili_yan: groupDef.key === 'askili_yan' ? value : distinctSummary(groupRows, 'askili_yan'),
|
||||
urun_ana_grubu: groupDef.key === 'urun_ana_grubu' ? value : distinctSummary(groupRows, 'urun_ana_grubu'),
|
||||
urun_alt_grubu: groupDef.key === 'urun_alt_grubu' ? value : distinctSummary(groupRows, 'urun_alt_grubu'),
|
||||
market_key: groupDef.key === 'market_key' ? value : distinctSummary(groupRows, 'market_key'),
|
||||
country: groupDef.key === 'country' ? value : distinctSummary(groupRows, 'country'),
|
||||
customer_segment: groupDef.key === 'customer_segment' ? value : distinctSummary(groupRows, 'customer_segment'),
|
||||
customer_code: groupDef.key === 'customer_code' ? value : distinctSummary(groupRows, 'customer_code'),
|
||||
customer_name: groupDef.key === 'customer_name' ? value : distinctSummary(groupRows, 'customer_name'),
|
||||
item_description: groupDef.key === 'item_description' ? value : '',
|
||||
kategori: groupDef.key === 'kategori' ? value : '',
|
||||
urun_ilk_grubu: groupDef.key === 'urun_ilk_grubu' ? value : '',
|
||||
askili_yan: groupDef.key === 'askili_yan' ? value : '',
|
||||
urun_ana_grubu: groupDef.key === 'urun_ana_grubu' ? value : '',
|
||||
urun_alt_grubu: groupDef.key === 'urun_alt_grubu' ? value : '',
|
||||
market_key: groupDef.key === 'market_key' ? value : '',
|
||||
country: groupDef.key === 'country' ? value : '',
|
||||
customer_segment: groupDef.key === 'customer_segment' ? value : '',
|
||||
customer_code: groupDef.key === 'customer_code' ? value : '',
|
||||
customer_name: groupDef.key === 'customer_name' ? value : '',
|
||||
stock_qty: sumRows(groupRows, 'stock_qty'),
|
||||
sales_qty_90d: sumRows(groupRows, 'sales_qty_90d'),
|
||||
sales_qty_180d: sumRows(groupRows, 'sales_qty_180d'),
|
||||
@@ -3392,6 +3395,8 @@ function toggleGroup (key) {
|
||||
}
|
||||
|
||||
async function collapseAllProductGroups () {
|
||||
if (bulkExpandLoading.value) return
|
||||
detailLevelMenuOpen.value = false
|
||||
const tabPrefix = `tab:${activeTab.value}|`
|
||||
expandedGroups.value = Object.fromEntries(
|
||||
Object.entries(expandedGroups.value).filter(([key]) => !key.startsWith(tabPrefix))
|
||||
@@ -3407,6 +3412,8 @@ async function collapseAllProductGroups () {
|
||||
}
|
||||
|
||||
async function expandSelectedProductGroups () {
|
||||
if (bulkExpandLoading.value) return
|
||||
detailLevelMenuOpen.value = false
|
||||
const keys = productAutoExpandKeys.value
|
||||
const maxKeys = Math.min(maxBulkExpandKeys, maxBackendExpandedKeysForTab(activeTab.value))
|
||||
const expandableKeys = keys.slice(0, maxKeys)
|
||||
@@ -4055,6 +4062,7 @@ function resolveProductImageUrl (item) {
|
||||
async function fetchProductImagesForRow (row) {
|
||||
if (!hasProductVariantImageKey(row)) return []
|
||||
const key = productImageKey(row)
|
||||
if (imageFailedKeys.value.has(key)) return []
|
||||
if (Object.prototype.hasOwnProperty.call(imageListByKey.value, key)) {
|
||||
return imageListByKey.value[key]
|
||||
}
|
||||
@@ -4083,6 +4091,11 @@ async function fetchProductImagesForRow (row) {
|
||||
const list = Array.isArray(resp?.data) ? resp.data : []
|
||||
const urls = list.map(resolveProductImageUrl).filter(Boolean)
|
||||
performanceStore.setImageCache(key, urls)
|
||||
if (urls.length && imageFailedKeys.value.has(key)) {
|
||||
const nextFailed = new Set(imageFailedKeys.value)
|
||||
nextFailed.delete(key)
|
||||
imageFailedKeys.value = nextFailed
|
||||
}
|
||||
imageListByKey.value = { ...imageListByKey.value, [key]: urls }
|
||||
imageUrlByKey.value = { ...imageUrlByKey.value, [key]: urls[0] || '' }
|
||||
return urls
|
||||
@@ -4097,12 +4110,14 @@ async function fetchProductImagesForRow (row) {
|
||||
function getCachedProductImageUrl (row) {
|
||||
if (!canShowProductImage(row)) return ''
|
||||
const key = productImageKey(row)
|
||||
if (imageFailedKeys.value.has(key)) return ''
|
||||
return imageUrlByKey.value[key] || performanceStore.imageUrl(key) || ''
|
||||
}
|
||||
|
||||
function markProductImageFailed (row) {
|
||||
const key = productImageKey(row)
|
||||
if (!key) return
|
||||
imageFailedKeys.value = new Set([...imageFailedKeys.value, key])
|
||||
performanceStore.setImageCache(key, [])
|
||||
imageListByKey.value = { ...imageListByKey.value, [key]: [] }
|
||||
imageUrlByKey.value = { ...imageUrlByKey.value, [key]: '' }
|
||||
@@ -4119,7 +4134,7 @@ async function primeProductImages (sourceRows) {
|
||||
if (!canShowProductImage(row)) continue
|
||||
const key = productImageKey(row)
|
||||
const code = String(row?.image_product_code || row?.product_code || '').trim()
|
||||
if (!key || !code || seen.has(key) || Object.prototype.hasOwnProperty.call(imageListByKey.value, key) || performanceStore.hasImageKey(key)) continue
|
||||
if (!key || !code || imageFailedKeys.value.has(key) || seen.has(key) || Object.prototype.hasOwnProperty.call(imageListByKey.value, key) || performanceStore.hasImageKey(key)) continue
|
||||
seen.add(key)
|
||||
items.push({
|
||||
key,
|
||||
@@ -4136,8 +4151,9 @@ async function primeProductImages (sourceRows) {
|
||||
const nextUrls = { ...imageUrlByKey.value }
|
||||
for (const item of items) {
|
||||
const urls = batch?.lists?.[item.key] || performanceStore.imageList(item.key) || []
|
||||
if (!urls.length) imageFailedKeys.value = new Set([...imageFailedKeys.value, item.key])
|
||||
nextLists[item.key] = urls
|
||||
nextUrls[item.key] = batch?.urls?.[item.key] || urls[0] || ''
|
||||
nextUrls[item.key] = imageFailedKeys.value.has(item.key) ? '' : (batch?.urls?.[item.key] || urls[0] || '')
|
||||
}
|
||||
imageListByKey.value = nextLists
|
||||
imageUrlByKey.value = nextUrls
|
||||
|
||||
Reference in New Issue
Block a user