This commit is contained in:
seb
2026-08-23 03:53:08 +02:00
parent 73d256e8a6
commit 5caedbe345
2 changed files with 78 additions and 32 deletions

View File

@@ -1,7 +1,7 @@
import { openSession, discardSession, closeSession } from './session.js'; import { openSession, discardSession, closeSession } from './session.js';
import { getOutgoingWarehouse, getWarehousePlace } from './warehouse.js'; import { getOutgoingWarehouse, getWarehousePlace } from './warehouse.js';
import { reservePositions } from './reserve.js'; import { reservePositions } from './reserve.js';
import { bookStockShortfallsAndRereserve } from './stock-shortage.js'; import { bookStockShortfallsAndRereserve, bookReturnPositions } from './stock-shortage.js';
import { commitPicklists } from './commit.js'; import { commitPicklists } from './commit.js';
import { deliverPicklists } from './deliver.js'; import { deliverPicklists } from './deliver.js';
import { logger } from '../../logger.js'; import { logger } from '../../logger.js';
@@ -29,35 +29,42 @@ export async function deliverOrder(transaction, kBenutzer, kAuftrag, kVersandArt
const kWarenLager = await getOutgoingWarehouse(transaction); const kWarenLager = await getOutgoingWarehouse(transaction);
const kWarenLagerPlatz = await getWarehousePlace(transaction, kWarenLager); const kWarenLagerPlatz = await getWarehousePlace(transaction, kWarenLager);
logger.info(`deliverOrder: kWarenLager=${kWarenLager} kWarenLagerPlatz=${kWarenLagerPlatz}`); logger.info(`deliverOrder: kWarenLager=${kWarenLager} kWarenLagerPlatz=${kWarenLagerPlatz}`);
const kSessionId = await openSession(transaction, kBenutzer);
try { const positiveItems = deliveredItems.filter((i) => i.quantity > 0);
await reservePositions(transaction, kBenutzer, kSessionId, kWarenLager, deliveredItems); const returnItems = deliveredItems.filter((i) => i.quantity < 0);
await bookStockShortfallsAndRereserve(
transaction, // 1. Process returned items: book them back into warehouse stock via Wareneingang
kBenutzer, if (returnItems.length) {
kSessionId, await bookReturnPositions(transaction, kBenutzer, kWarenLagerPlatz, returnItems);
kWarenLager, }
kWarenLagerPlatz,
deliveredItems, // 2. Process positive items: standard JTL picklist/delivery fulfillment
); if (positiveItems.length) {
await commitPicklists(transaction, kBenutzer, kSessionId, kAuftrag); const kSessionId = await openSession(transaction, kBenutzer);
await deliverPicklists(transaction, kBenutzer, kSessionId, kAuftrag, kVersandArt);
logger.info(`deliverOrder: delivered kAuftrag=${kAuftrag} kSessionId=${kSessionId}`);
} catch (err) {
logger.error(`deliverOrder: FAILED kAuftrag=${kAuftrag} kSessionId=${kSessionId}: ${err.message}`);
throw err;
} finally {
// Safe to run unconditionally (success or error): spPicklistenVerwerfen only
// ever removes not-yet-delivered (nStatus < 10) Picklisten for this session.
// Swallow cleanup errors so they never mask an earlier, more relevant error
// (the outer transaction rollback in create-order.js is what actually matters
// on failure).
try { try {
await discardSession(transaction, kBenutzer, kSessionId); await reservePositions(transaction, kBenutzer, kSessionId, kWarenLager, positiveItems);
await closeSession(transaction, kSessionId); await bookStockShortfallsAndRereserve(
} catch { transaction,
// best-effort cleanup only kBenutzer,
kSessionId,
kWarenLager,
kWarenLagerPlatz,
positiveItems,
);
await commitPicklists(transaction, kBenutzer, kSessionId, kAuftrag);
await deliverPicklists(transaction, kBenutzer, kSessionId, kAuftrag, kVersandArt);
logger.info(`deliverOrder: delivered kAuftrag=${kAuftrag} kSessionId=${kSessionId}`);
} catch (err) {
logger.error(`deliverOrder: FAILED kAuftrag=${kAuftrag} kSessionId=${kSessionId}: ${err.message}`);
throw err;
} finally {
try {
await discardSession(transaction, kBenutzer, kSessionId);
await closeSession(transaction, kSessionId);
} catch {
// best-effort cleanup only
}
} }
} }
} }

View File

@@ -21,7 +21,7 @@ async function getReservedQuantity(transaction, kSessionId, kAuftragPosition) {
return reserved; return reserved;
} }
async function getPositionArtikel(transaction, kAuftragPosition) { export async function getPositionArtikel(transaction, kAuftragPosition) {
const result = await new sql.Request(transaction) const result = await new sql.Request(transaction)
.input('kAuftragPosition', sql.Int, kAuftragPosition) .input('kAuftragPosition', sql.Int, kAuftragPosition)
.query(` .query(`
@@ -35,14 +35,22 @@ async function getPositionArtikel(transaction, kAuftragPosition) {
return row?.kArtikel ?? 0; return row?.kArtikel ?? 0;
} }
async function bookWareneingang(transaction, kBenutzer, kWarenLagerPlatz, kArtikel, fehlmenge) { export async function bookWareneingang(
transaction,
kBenutzer,
kWarenLagerPlatz,
kArtikel,
fehlmenge,
comment = POS_SHORTAGE_COMMENT,
buchungsart = BUCHUNGSART_WARENEINGANG,
) {
await new sql.Request(transaction) await new sql.Request(transaction)
.input('kArtikel', sql.Int, kArtikel) .input('kArtikel', sql.Int, kArtikel)
.input('kWarenLagerPlatz', sql.Int, kWarenLagerPlatz) .input('kWarenLagerPlatz', sql.Int, kWarenLagerPlatz)
.input('kBenutzer', sql.Int, kBenutzer) .input('kBenutzer', sql.Int, kBenutzer)
.input('fAnzahl', sql.Float, fehlmenge) .input('fAnzahl', sql.Float, fehlmenge)
.input('cKommentar', sql.NVarChar, POS_SHORTAGE_COMMENT) .input('cKommentar', sql.NVarChar, comment)
.input('kBuchungsart', sql.Int, BUCHUNGSART_WARENEINGANG) .input('kBuchungsart', sql.Int, buchungsart)
.query(` .query(`
DECLARE @kWarenlagerEingang INT; DECLARE @kWarenlagerEingang INT;
EXEC dbo.spWarenlagerEingangSchreiben EXEC dbo.spWarenlagerEingangSchreiben
@@ -69,6 +77,37 @@ async function bookWareneingang(transaction, kBenutzer, kWarenLagerPlatz, kArtik
`); `);
} }
export async function bookReturnPositions(
transaction,
kBenutzer,
kWarenLagerPlatz,
returnPositions,
) {
logger.info(`returnBooking: processing ${returnPositions.length} return position(s) at kWarenLagerPlatz=${kWarenLagerPlatz}`);
for (const { kAuftragPosition, quantity } of returnPositions) {
if (!kAuftragPosition || quantity >= 0) {
continue;
}
const returnQty = Math.abs(quantity);
const kArtikel = await getPositionArtikel(transaction, kAuftragPosition);
logger.info(`returnBooking: kBestellPos=${kAuftragPosition} kArtikel=${kArtikel} returnQty=${returnQty}`);
if (!kArtikel) {
logger.info(`returnBooking: kBestellPos=${kAuftragPosition} no kArtikel (free position / Pfand?), skip return booking`);
continue;
}
await bookWareneingang(
transaction,
kBenutzer,
kWarenLagerPlatz,
kArtikel,
returnQty,
'Korrekturbuchung erstellt durch POS-Abgleich (Retoure)',
BUCHUNGSART_WARENEINGANG,
);
logger.info(`returnBooking: successfully booked return of ${returnQty}x kArtikel=${kArtikel} into kWarenLagerPlatz=${kWarenLagerPlatz}`);
}
}
/** /**
* PosStockPositionService.FehlbestandEinbuchen — book missing stock, then re-reserve. * PosStockPositionService.FehlbestandEinbuchen — book missing stock, then re-reserve.
*/ */