import { string } from 'alga-js' import refreshTokenHelper from "../../utils/refreshTokenHelper" import forceLogoutHelper from "../../utils/forceLogoutHelper" import errorHandlingHelper from "../../utils/errorHandlingHelper" import getTokenHelper from "../../utils/getTokenHelper" import fetchHelper from "../../utils/fetchHelper" const handleFunc = async (event: any, authToken: any = null) => { let data: any = {} const token = authToken ?? await getTokenHelper(event) const body = await readBody(event) const searchTerm = body?.search || '' if (!searchTerm) { throw createError({ statusCode: 400, statusMessage: 'Search term is required' }) } // Search by Value, SKU, or UPC const filter = string.urlEncode( `(Value eq '${searchTerm}' OR SKU eq '${searchTerm}' OR UPC eq '${searchTerm}') AND (isActive eq true)` ) const res: any = await event.context.fetch( `models/m_product?$filter=${filter}`, 'GET', token, null ) if (res?.records && res.records.length > 0) { const product = res.records[0] // Fetch storages for this product with locator and warehouse info expanded const storagesRes: any = await fetchHelper( event, `models/m_storage?$filter=${string.urlEncode('M_Product_ID eq ' + product.id)}&$expand=${string.urlEncode('M_Locator_ID,M_Warehouse')}&$select=${string.urlEncode('QtyOnHand,M_Locator_ID')}&$top=1000`, 'GET', token, null ) const storages = Array.isArray(storagesRes?.records) ? storagesRes.records : [] // Aggregate total qty on hand and per-locator quantities let qtyonhand = 0 const locatorMap: Record = {} let warehouseIdFromStorage = null for (const s of storages) { const qty = Number(s?.QtyOnHand ?? 0) if (!qty) continue qtyonhand += qty const locObj = s?.M_Locator_ID || s?.m_locator_id || {} const locId = locObj?.id ?? String(locObj) ?? 'unknown' const locCode = locObj?.Value || locObj?.identifier || locObj?.Name || locObj?.value || String(locId) // Extract warehouse ID from M_Warehouse array const warehouseArray = s?.M_Warehouse || s?.m_warehouse || [] const locWarehouseId = Array.isArray(warehouseArray) && warehouseArray.length > 0 ? warehouseArray[0]?.id : null // Capture warehouse ID from first locator with inventory if (!warehouseIdFromStorage && locWarehouseId) { warehouseIdFromStorage = locWarehouseId } if (!locatorMap[locId]) { locatorMap[locId] = { id: locId, code: locCode, qtyOnHand: 0, warehouseId: locWarehouseId } } locatorMap[locId].qtyOnHand += qty } let locators = Object.values(locatorMap) .filter(l => l.qtyOnHand > 0) .sort((a, b) => b.qtyOnHand - a.qtyOnHand) // If no locators with qty, fetch all locators for the warehouse based on product's organization let availableLocators: any[] = [] if (locators.length === 0) { const warehouseId = body?.warehouseId const productOrgId = product.AD_Org_ID?.id || product.AD_Org_ID if (warehouseId && productOrgId) { const locatorsRes: any = await fetchHelper( event, `models/m_locator?$filter=${string.urlEncode('M_Warehouse_ID eq ' + warehouseId + ' AND AD_Org_ID eq ' + productOrgId + ' AND IsActive eq true')}&$orderby=${string.urlEncode('IsDefault desc, PriorityNo desc')}`, 'GET', token, null ) if (locatorsRes?.records && locatorsRes.records.length > 0) { availableLocators = locatorsRes.records.map((loc: any) => ({ id: loc.id, code: loc.Value || loc.identifier || loc.Name, qtyOnHand: 0, isDefault: loc.IsDefault || false, warehouseId: loc.M_Warehouse_ID?.id || loc.M_Warehouse_ID })) // Use the default locator or first locator const defaultLocator = availableLocators.find(l => l.isDefault) || availableLocators[0] if (defaultLocator) { locators = [defaultLocator] } } } } // Extract warehouse ID - prioritize from storage, then availableLocators, then fallback let warehouseIdForProduct = warehouseIdFromStorage || body?.warehouseId if (!warehouseIdForProduct && availableLocators.length > 0 && availableLocators[0].warehouseId) { warehouseIdForProduct = availableLocators[0].warehouseId } data = { id: product.id, Name: product.Name, Value: product.Value, SKU: product.SKU, UPC: product.UPC, Description: product.Description, qtyonhand: qtyonhand, qtyreserved: product.QtyReserved || 0, qtyavailable: product.QtyAvailable || 0, qtyordered: product.QtyOrdered || 0, // Sales orders (customer orders) qtypurchased: product.QtyOrdered_PO || 0, // Purchase orders Weight: product.Weight || 0, ShelfWidth: product.ShelfWidth || 0, ShelfHeight: product.ShelfHeight || 0, ShelfDepth: product.ShelfDepth || 0, Strapi_Product_documentId: product.Strapi_Product_documentId || null, AD_Org_ID: product.AD_Org_ID || null, M_Warehouse_ID: warehouseIdForProduct, locators: locators, availableLocators: availableLocators } } else { throw createError({ statusCode: 404, statusMessage: 'Product not found' }) } 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) throw createError({ statusCode: err?.statusCode || 500, statusMessage: err?.statusMessage || 'Error searching product', data: data }) } } return data })