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" const handleFunc = async (event: any, authToken: any = null) => { let data: any = { records: [] } const token = authToken ?? await getTokenHelper(event) const query = getQuery(event) const searchTerm = query.search || query.q || '' const limit = parseInt(query.limit as string) || 20 if (!searchTerm || (searchTerm as string).length < 2) { return data } // Escape single quotes in search term const escapedSearchTerm = (searchTerm as string).replace(/'/g, "''") // Search by Value, Name, SKU, MPN (mpn), or UPC — all partial, case-insensitive const lowerSearchTerm = escapedSearchTerm.toLowerCase() let searchFilter = `(contains(tolower(Value),'${lowerSearchTerm}') OR contains(tolower(Name),'${lowerSearchTerm}') OR contains(tolower(SKU),'${lowerSearchTerm}') OR contains(tolower(mpn),'${lowerSearchTerm}') OR contains(tolower(UPC),'${lowerSearchTerm}') OR contains(tolower(fnsku),'${lowerSearchTerm}'))` // Filter by organization if provided const orgId = query.orgId if (orgId) { searchFilter = `(${searchFilter}) AND (AD_Org_ID eq ${orgId} OR AD_Org_ID eq 0)` } // Opt-in BOM exclusion (mobile pages expose it as a checkbox) — off by default so the // shared callers (sales order import, transactions) still see BOM/kit products. // IsBOM (standard flag) is filtered server-side; isJtlBom (custom column) is filtered // in JS. Every record is returned with `isBOM` / `isJtlBom` so callers can tag kits — // that needs the full record (no lean $select): adding the optional custom column to // $select would 500 envs that lack it, and the result set is capped at `limit` anyway. const excludeBom = query.excludeBom === 'true' || query.excludeBom === '1' if (excludeBom) { searchFilter = `${searchFilter} AND (IsBOM eq false)` } const res: any = await fetchHelper( event, `models/m_product?$filter=${string.urlEncode(searchFilter)}&$top=${limit}&$orderby=${string.urlEncode('Name asc')}`, 'GET', token, null ) if (res?.records) { const isJtlBom = (r: any) => (r.isJtlBom ?? r.IsJtlBom) === true || (r.isJtlBom ?? r.IsJtlBom) === 'Y' const isBom = (r: any) => (r.IsBOM ?? r.isBOM) === true || (r.IsBOM ?? r.isBOM) === 'Y' let records = res.records if (excludeBom) { records = records.filter((r: any) => !isJtlBom(r)) } // Map m_product_id to id for consistency data.records = records.map((r: any) => ({ id: r.m_product_id || r.M_Product_ID || r.id, Value: r.Value, Name: r.Name, SKU: r.SKU, MPN: r.mpn, UPC: r.UPC, FNSKU: r.fnsku, imageUrl: r.ImageURL || null, isBOM: isBom(r), isJtlBom: isJtlBom(r), isActive: (r.IsActive ?? r.isActive) !== false && (r.IsActive ?? r.isActive) !== 'N', orgId: r.AD_Org_ID?.id ?? null, orgName: r.AD_Org_ID?.identifier || '', categoryName: r.M_Product_Category_ID?.identifier || '' })) } 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 })