Fix product performance grouped JSON build

This commit is contained in:
M_Kececi
2026-07-04 13:45:43 +03:00
parent 60b2f76537
commit 4c56062ef4
3 changed files with 73 additions and 30 deletions
+39 -12
View File
@@ -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 {
+1 -1
View File
@@ -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