import { string } from 'alga-js' export const useOpenShipments = () => { const openShipments = ref([]) const isLoading = ref(false) const error = ref(null) const lastFetched = ref(null) // Shipment list — direct-Postgres endpoint (server/api/inouts/open-to-commission-list.get.ts), // the same query the dashboard "Offene Aufträge" card and the commissioning modal already use. // It already applies the iscommissioned/isactive/movementtype/docstatus + fulfillment-order // filter server-side, so there's no client-side re-filtering needed here anymore. const fetchShipmentList = async (): Promise => { const res: any = await $fetch('/api/inouts/open-to-commission-list', { headers: useRequestHeaders(['cookie']) }) return res?.records || [] } // Line items for the barcode-scan search (searchProductInOpenShipments in // integrations/commission.vue), fetched in ONE call for every shipment at once. // M_Product_ID here is a to-one FK expand on the TOP-LEVEL m_inoutline list — // not a child expand under m_inout — so it doesn't hit the synchronized // DefaultQueryConverter path that made the old $expand=m_inoutline($expand=m_product_id) // under m_inout expensive (see the "iDempiere REST load rules" recipe). const fetchLinesByInoutId = async (inoutIds: number[]): Promise> => { const linesByInoutId: Record = {} if (inoutIds.length === 0) return linesByInoutId const filter = string.urlEncode(`M_InOut_ID in (${inoutIds.join(',')})`) const res: any = await $fetch( `/api/filters/m_inoutline/${filter}&$expand=M_Product_ID&$top=3000`, { headers: useRequestHeaders(['cookie']) } ) for (const line of (res?.records || [])) { const inoutId = line?.M_InOut_ID?.id ?? line?.m_inout_id?.id ?? line?.M_InOut_ID ?? line?.m_inout_id if (!inoutId) continue ;(linesByInoutId[inoutId] ||= []).push(line) } return linesByInoutId } // Main fetch function const fetchOpenShipments = async () => { isLoading.value = true error.value = null try { const records = await fetchShipmentList() const linesByInoutId = await fetchLinesByInoutId(records.map((r: any) => r.id)) openShipments.value = records.map((r: any) => ({ id: r.id, DocumentNo: r.documentNo, MovementDate: r.movementDate, POReference: r.poReference, totalQty: r.totalQty, orderNo: r.orderNo, orderId: r.orderId, AD_Org_ID: { Name: r.orgName, identifier: r.orgName }, C_BPartner_ID: { identifier: r.partnerName }, C_BPartner_Location_ID: r.locationName ? { Name: r.locationName, identifier: r.locationName } : null, M_Shipper_ID: r.shipperName ? { identifier: r.shipperName } : null, m_inoutline: linesByInoutId[r.id] || [] })) lastFetched.value = new Date() } catch (err: any) { console.error('Error fetching open shipments:', err) error.value = err?.message || 'Failed to fetch open shipments' } finally { isLoading.value = false } } // Refresh data (for manual refresh or after commission) const refresh = () => { return fetchOpenShipments() } // Remove a shipment from the list (e.g., after it's been commissioned) const removeShipment = (shipmentId: number) => { openShipments.value = openShipments.value.filter(s => s.id !== shipmentId) } return { openShipments, isLoading, error, lastFetched, fetchOpenShipments, refresh, removeShipment } }