import { string } from 'alga-js' import refreshTokenHelper from "../../../utils/refreshTokenHelper" import forceLogoutHelper from "../../../utils/forceLogoutHelper" import errorHandlingHelper from "../../../utils/errorHandlingHelper" import fetchHelper from "../../../utils/fetchHelper" import getTokenHelper from "../../../utils/getTokenHelper" const handleFunc = async (event: any, authToken: any = null) => { let data: any = { records: [], 'row-count': 0 } const token = authToken ?? await getTokenHelper(event) const query = getQuery(event) const orgId = query?.org_id as string if (!orgId) { return { status: 400, message: 'Organization ID is required', records: [], 'row-count': 0 } } // Build filter for products owned by organization const orgFilter = string.urlEncode(`AD_Org_ID eq ${orgId} and IsActive eq true`) // Step 1: Fetch all locators for this organization first // This is more efficient than querying by IDs later const locatorMap = new Map() try { const locatorOrgFilter = string.urlEncode(`AD_Org_ID eq ${orgId}`) const locatorRes: any = await fetchHelper( event, `models/m_locator?$filter=${locatorOrgFilter}&$expand=M_LocatorType_ID&$top=5000`, 'GET', token, null ) if (locatorRes?.records) { for (const locator of locatorRes.records) { locatorMap.set(locator.id, locator) } } console.log('[qty-on-hand-by-locator] Loaded', locatorMap.size, 'locators for org', orgId) } catch (err) { console.error('[qty-on-hand-by-locator] Error fetching locators:', err) // Continue without locator details - we'll still show products } // Step 2: Fetch products with storage data const res: any = await fetchHelper( event, `models/m_product?$select=${string.urlEncode('M_Product_ID,Name,SKU,UPC,Value,mpn,AD_Org_ID')}&$expand=M_Storage,AD_Org_ID($select=Name)&$filter=${orgFilter}&$orderby=${string.urlEncode('Name asc')}&$top=5000`, 'GET', token, null ) if (!res?.records) { return data } // Group records by product + locator (X, Y, Z) and aggregate qtyOnHand // Key format: productId_locatorX_locatorY_locatorZ const groupedMap = new Map() for (const product of res.records) { const storages = product?.M_Storage || [] const productId = product.M_Product_ID || product.id const orgName = product.AD_Org_ID?.Name || '' const orgIdVal = product.AD_Org_ID?.id || orgId if (Array.isArray(storages) && storages.length > 0) { for (const storage of storages) { const locatorId = storage?.M_Locator_ID?.id const locator = locatorId ? locatorMap.get(locatorId) : null const qtyOnHand = Number(storage?.QtyOnHand || 0) const locatorX = locator?.X || '' const locatorY = locator?.Y || '' const locatorZ = locator?.Z || '' // Create a unique key for product + locator coordinates const groupKey = `${productId}_${locatorX}_${locatorY}_${locatorZ}` if (groupedMap.has(groupKey)) { // Add to existing group const existing = groupedMap.get(groupKey) existing.qtyOnHand += qtyOnHand } else { // Create new group entry groupedMap.set(groupKey, { id: `${productId}_${locatorId || 'no_locator'}`, productId: productId, locatorId: locatorId || null, name: product.Name || '', sku: product.SKU || '', ean: product.UPC || '', value: product.Value || '', mpn: product.mpn || '', qtyOnHand: qtyOnHand, locatorX: locatorX, locatorY: locatorY, locatorZ: locatorZ, locatorValue: locator?.Value || '', locatorPriority: locator?.PriorityNo ?? null, locatorTypeId: locator?.M_LocatorType_ID?.id || null, locatorTypeName: locator?.M_LocatorType_ID?.Name || '', organization: orgName, organizationId: orgIdVal }) } } } else { // Product has no storage entries - include with null locator data const groupKey = `${productId}_no_storage` if (!groupedMap.has(groupKey)) { groupedMap.set(groupKey, { id: `${productId}_no_storage`, productId: productId, locatorId: null, name: product.Name || '', sku: product.SKU || '', ean: product.UPC || '', value: product.Value || '', mpn: product.mpn || '', qtyOnHand: 0, locatorX: '', locatorY: '', locatorZ: '', locatorValue: '', locatorPriority: null, locatorTypeId: null, locatorTypeName: '', organization: orgName, organizationId: orgIdVal }) } } } const transformedRecords = Array.from(groupedMap.values()) data = { status: 200, records: transformedRecords, 'row-count': transformedRecords.length } return data } export default defineEventHandler(async (event) => { let data: any = {} try { data = await handleFunc(event) } catch (err: any) { try { let authToken: any = await refreshTokenHelper(event) data = await handleFunc(event, authToken) } catch (error: any) { data = errorHandlingHelper(err?.data ?? err, error?.data ?? error) forceLogoutHelper(event, data) } } return data })