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 productId = query.productId if (!productId) { return { status: 400, message: 'Product ID is required' } } // Helper to extract ID from value (handles both number and object with id) const extractId = (value: any): number | null => { if (typeof value === 'number') return value if (value?.id) return value.id return null } // Fetch transactions for the product const transactionRes: any = await fetchHelper( event, `models/m_transaction?$filter=${string.urlEncode('M_Product_ID eq ' + productId)}&$orderby=${string.urlEncode('MovementDate desc')}`, 'GET', token, null ) if (!transactionRes?.records || transactionRes.records.length === 0) { return data } // Collect unique IDs for batch fetching const locatorIds = new Set() const inOutLineIds = new Set() for (const transaction of transactionRes.records) { const locatorId = extractId(transaction.M_Locator_ID) const inOutLineId = extractId(transaction.M_InOutLine_ID) if (locatorId) locatorIds.add(locatorId) if (inOutLineId) inOutLineIds.add(inOutLineId) } // Fetch product details const productRes: any = await fetchHelper( event, `models/M_Product/${productId}`, 'GET', token, null ) const productInfo = { name: productRes?.Name || '', sku: productRes?.SKU || '' } // Fetch locator details const locatorDetails: Record = {} if (locatorIds.size > 0) { const locatorIdArray = Array.from(locatorIds) const filterParts = locatorIdArray.map(id => `M_Locator_ID eq ${id}`).join(' or ') try { const locatorRes: any = await fetchHelper( event, `models/M_Locator?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_Locator_ID,Value')}`, 'GET', token, null ) if (locatorRes?.records) { for (const locator of locatorRes.records) { locatorDetails[locator.id] = locator.Value || locator.identifier || '' } } } catch (err) { console.error('Error fetching locator details:', err) } } // Fetch inout line details to get M_InOut_ID const inOutLineDetails: Record = {} const inOutIds = new Set() if (inOutLineIds.size > 0) { const inOutLineIdArray = Array.from(inOutLineIds) const batchSize = 50 for (let i = 0; i < inOutLineIdArray.length; i += batchSize) { const batch = inOutLineIdArray.slice(i, i + batchSize) const filterParts = batch.map(id => `M_InOutLine_ID eq ${id}`).join(' or ') try { const inOutLineRes: any = await fetchHelper( event, `models/M_InOutLine?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_InOutLine_ID,M_InOut_ID')}`, 'GET', token, null ) if (inOutLineRes?.records) { for (const line of inOutLineRes.records) { const inOutId = extractId(line.M_InOut_ID) inOutLineDetails[line.id] = inOutId if (inOutId) inOutIds.add(inOutId) } } } catch (err) { console.error('Error fetching inout line details:', err) } } } // Fetch shipment details (M_InOut with C_BPartner and C_Order info) const shipmentDetails: Record = {} if (inOutIds.size > 0) { const inOutIdArray = Array.from(inOutIds) const batchSize = 50 for (let i = 0; i < inOutIdArray.length; i += batchSize) { const batch = inOutIdArray.slice(i, i + batchSize) const filterParts = batch.map(id => `M_InOut_ID eq ${id}`).join(' or ') try { const shipmentRes: any = await fetchHelper( event, `models/M_InOut?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_InOut_ID,DocumentNo,IsSOTrx,MovementType,C_BPartner_ID,C_Order_ID')}`, 'GET', token, null ) if (shipmentRes?.records) { // Collect bpartner and order IDs const bpartnerIds = new Set() const orderIds = new Set() for (const shipment of shipmentRes.records) { const bpartnerId = extractId(shipment.C_BPartner_ID) const orderId = extractId(shipment.C_Order_ID) if (bpartnerId) bpartnerIds.add(bpartnerId) if (orderId) orderIds.add(orderId) shipmentDetails[shipment.id] = { documentNo: shipment.DocumentNo || '', isSOTrx: shipment.IsSOTrx === true || shipment.IsSOTrx === 'Y', movementType: shipment.MovementType || '', bpartnerId: bpartnerId, orderId: orderId, bpartnerName: '', externalOrderId: '' } } // Fetch bpartner names if (bpartnerIds.size > 0) { const bpartnerIdArray = Array.from(bpartnerIds) const bpartnerFilter = bpartnerIdArray.map(id => `C_BPartner_ID eq ${id}`).join(' or ') try { const bpartnerRes: any = await fetchHelper( event, `models/C_BPartner?$filter=${string.urlEncode(bpartnerFilter)}&$select=${string.urlEncode('C_BPartner_ID,Name')}`, 'GET', token, null ) if (bpartnerRes?.records) { const bpartnerMap: Record = {} for (const bp of bpartnerRes.records) { bpartnerMap[bp.id] = bp.Name || '' } // Update shipment details with bpartner names for (const shipmentId in shipmentDetails) { const bpId = shipmentDetails[shipmentId].bpartnerId if (bpId && bpartnerMap[bpId]) { shipmentDetails[shipmentId].bpartnerName = bpartnerMap[bpId] } } } } catch (err) { console.error('Error fetching bpartner details:', err) } } // Fetch order external IDs if (orderIds.size > 0) { const orderIdArray = Array.from(orderIds) const orderFilter = orderIdArray.map(id => `C_Order_ID eq ${id}`).join(' or ') try { const orderRes: any = await fetchHelper( event, `models/C_Order?$filter=${string.urlEncode(orderFilter)}&$select=${string.urlEncode('C_Order_ID,ExternalOrderId')}`, 'GET', token, null ) if (orderRes?.records) { const orderMap: Record = {} for (const order of orderRes.records) { orderMap[order.id] = order.ExternalOrderId || '' } // Update shipment details with external order IDs for (const shipmentId in shipmentDetails) { const ordId = shipmentDetails[shipmentId].orderId if (ordId && orderMap[ordId]) { shipmentDetails[shipmentId].externalOrderId = orderMap[ordId] } } } } catch (err) { console.error('Error fetching order details:', err) } } } } catch (err) { console.error('Error fetching shipment details:', err) } } } // Map transaction records with enriched data const enrichedRecords = transactionRes.records.map((transaction: any) => { const locatorId = extractId(transaction.M_Locator_ID) const inOutLineId = extractId(transaction.M_InOutLine_ID) const inOutId = inOutLineId ? inOutLineDetails[inOutLineId] : null const shipmentInfo = inOutId ? shipmentDetails[inOutId] || {} : {} return { id: transaction.id || transaction.uid, movementDate: transaction.MovementDate || '', movementQty: transaction.MovementQty || 0, movementType: transaction.MovementType?.identifier || transaction.MovementType || '', movementTypeId: transaction.MovementType?.id || '', locator: locatorId ? locatorDetails[locatorId] || '' : '', locatorId: locatorId, productId: extractId(transaction.M_Product_ID), productName: productInfo.name, productSku: productInfo.sku, inOutLineId: inOutLineId, inOutId: inOutId, bpartnerName: shipmentInfo.bpartnerName || '', bpartnerId: shipmentInfo.bpartnerId || null, externalOrderId: shipmentInfo.externalOrderId || '', orderId: shipmentInfo.orderId || null, shipmentDocumentNo: shipmentInfo.documentNo || '', isSOTrx: shipmentInfo.isSOTrx || false, shipmentMovementType: shipmentInfo.movementType || '' } }) data.records = enrichedRecords 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 })