u
This commit is contained in:
184
src/utils/orderLedger.js
Normal file
184
src/utils/orderLedger.js
Normal file
@@ -0,0 +1,184 @@
|
||||
import { ledger as defaultLedgerApi, shipment as defaultShipmentApi } from '../api';
|
||||
import warehouseAutomat from '../automats/warehouseAutomat';
|
||||
|
||||
/**
|
||||
* Fetches ledger entries for an order by inspecting:
|
||||
* 1. All lines of the order's shipments (each shipment line id is a manifestarticle_id)
|
||||
* 2. All lines of the order itself (in case order lines have direct ledger bookings)
|
||||
*
|
||||
* @param {number|string} orderId
|
||||
* @param {Object} [options]
|
||||
* @param {Array<object>} [options.shipments] Preloaded shipments
|
||||
* @param {Array<object>} [options.lines] Order lines
|
||||
* @param {Object} [options.ledgerApi]
|
||||
* @param {Object} [options.shipmentApi]
|
||||
* @returns {Promise<Array<object>>} Flattened, correlated and sorted ledger entries
|
||||
*/
|
||||
export async function fetchOrderLedgerEntries(orderId, {
|
||||
shipments = null,
|
||||
lines = null,
|
||||
ledgerApi = defaultLedgerApi,
|
||||
shipmentApi = defaultShipmentApi,
|
||||
} = {}) {
|
||||
let shipmentList = shipments;
|
||||
if (!shipmentList && orderId) {
|
||||
try {
|
||||
const res = await shipmentApi.listByOrder(orderId);
|
||||
shipmentList = Array.isArray(res?.shipments) ? res.shipments : [];
|
||||
} catch (err) {
|
||||
console.warn('[orderLedger] Failed to fetch shipments for order:', err);
|
||||
shipmentList = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure shipments have their lines loaded
|
||||
if (Array.isArray(shipmentList)) {
|
||||
shipmentList = await Promise.all(
|
||||
shipmentList.map(async (sh) => {
|
||||
if (Array.isArray(sh.lines) && sh.lines.length > 0) return sh;
|
||||
if (!sh.id) return sh;
|
||||
try {
|
||||
const detailRes = await shipmentApi.get(sh.id);
|
||||
const detail = detailRes?.shipment ?? detailRes;
|
||||
return detail?.lines ? detail : sh;
|
||||
} catch {
|
||||
return sh;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Collect target lines to check for ledger bookings
|
||||
const targets = [];
|
||||
const seenIds = new Set();
|
||||
|
||||
for (const sh of shipmentList || []) {
|
||||
const docNum = sh.number || `Lieferschein #${sh.id}`;
|
||||
for (const sLine of sh.lines || []) {
|
||||
if (sLine?.id && !seenIds.has(sLine.id)) {
|
||||
seenIds.add(sLine.id);
|
||||
targets.push({
|
||||
manifestarticleId: sLine.id,
|
||||
sku: sLine.sku || null,
|
||||
name: sLine.name || null,
|
||||
lineAmount: sLine.amount ?? null,
|
||||
documentNumber: docNum,
|
||||
documentType: 'shipment',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const oLine of lines || []) {
|
||||
if (oLine?.id && !seenIds.has(oLine.id)) {
|
||||
seenIds.add(oLine.id);
|
||||
targets.push({
|
||||
manifestarticleId: oLine.id,
|
||||
sku: oLine.sku || null,
|
||||
name: oLine.name || null,
|
||||
lineAmount: oLine.amount ?? null,
|
||||
documentNumber: null,
|
||||
documentType: 'order',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (targets.length === 0) return [];
|
||||
|
||||
// Query ledger entries for each manifestarticleId in parallel
|
||||
const results = await Promise.all(
|
||||
targets.map(async (t) => {
|
||||
try {
|
||||
const res = await ledgerApi.listByManifestarticleId(t.manifestarticleId);
|
||||
const entries = Array.isArray(res?.ledger) ? res.ledger : [];
|
||||
return { target: t, entries };
|
||||
} catch (err) {
|
||||
console.warn(`[orderLedger] Failed to fetch ledger for line ${t.manifestarticleId}:`, err);
|
||||
return { target: t, entries: [] };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const warehouses = warehouseAutomat.state.warehouses || [];
|
||||
const allEntries = [];
|
||||
|
||||
for (const { target, entries } of results) {
|
||||
if (!entries || entries.length === 0) continue;
|
||||
|
||||
const docEntries = entries.filter((e) => {
|
||||
const type = String(e.transaction_type || '').toUpperCase();
|
||||
return type !== 'WAREHOUSE';
|
||||
});
|
||||
const warehouseEntries = entries.filter((e) => {
|
||||
const type = String(e.transaction_type || '').toUpperCase();
|
||||
return type === 'WAREHOUSE';
|
||||
});
|
||||
|
||||
if (docEntries.length > 0) {
|
||||
docEntries.forEach((docEntry, idx) => {
|
||||
const matchingWh =
|
||||
warehouseEntries.find(
|
||||
(w) =>
|
||||
w.warehouse_id != null &&
|
||||
(w.transaction_text === docEntry.transaction_text ||
|
||||
Math.abs(new Date(w.created_at) - new Date(docEntry.created_at)) < 15000)
|
||||
) || warehouseEntries[idx] || null;
|
||||
|
||||
const warehouseId = matchingWh?.warehouse_id ?? docEntry.warehouse_id ?? null;
|
||||
const wh = warehouseId != null
|
||||
? warehouses.find((w) => Number(w.id) === Number(warehouseId))
|
||||
: null;
|
||||
const warehouseName = wh?.name || (warehouseId != null ? `Lager #${warehouseId}` : '–');
|
||||
|
||||
const rawAmount = matchingWh?.amount ?? docEntry.amount;
|
||||
const mengeVerbucht = rawAmount != null
|
||||
? (Number(rawAmount) > 0 ? `+${rawAmount}` : String(rawAmount))
|
||||
: '–';
|
||||
|
||||
allEntries.push({
|
||||
id: docEntry.id,
|
||||
created_at: docEntry.created_at,
|
||||
sku: docEntry.sku || target.sku || '–',
|
||||
name: target.name || '–',
|
||||
lineAmount: target.lineAmount != null ? String(target.lineAmount) : '–',
|
||||
documentNumber: target.documentNumber,
|
||||
warehouseName,
|
||||
warehouseId,
|
||||
mengeVerbucht,
|
||||
rawAmount: rawAmount != null ? Number(rawAmount) : null,
|
||||
transaction_type: docEntry.transaction_type,
|
||||
transaction_text: docEntry.transaction_text || '–',
|
||||
});
|
||||
});
|
||||
} else if (warehouseEntries.length > 0) {
|
||||
for (const w of warehouseEntries) {
|
||||
const wh = w.warehouse_id != null
|
||||
? warehouses.find((item) => Number(item.id) === Number(w.warehouse_id))
|
||||
: null;
|
||||
const warehouseName = wh?.name || (w.warehouse_id != null ? `Lager #${w.warehouse_id}` : '–');
|
||||
const rawAmount = w.amount;
|
||||
const mengeVerbucht = rawAmount != null
|
||||
? (Number(rawAmount) > 0 ? `+${rawAmount}` : String(rawAmount))
|
||||
: '–';
|
||||
|
||||
allEntries.push({
|
||||
id: w.id,
|
||||
created_at: w.created_at,
|
||||
sku: w.sku || target.sku || '–',
|
||||
name: target.name || '–',
|
||||
lineAmount: target.lineAmount != null ? String(target.lineAmount) : '–',
|
||||
documentNumber: target.documentNumber,
|
||||
warehouseName,
|
||||
warehouseId: w.warehouse_id,
|
||||
mengeVerbucht,
|
||||
rawAmount: rawAmount != null ? Number(rawAmount) : null,
|
||||
transaction_type: w.transaction_type,
|
||||
transaction_text: w.transaction_text || '–',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allEntries.sort((a, b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
|
||||
return allEntries;
|
||||
}
|
||||
Reference in New Issue
Block a user