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,17 +29,28 @@ 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 positiveItems = deliveredItems.filter((i) => i.quantity > 0);
const returnItems = deliveredItems.filter((i) => i.quantity < 0);
// 1. Process returned items: book them back into warehouse stock via Wareneingang
if (returnItems.length) {
await bookReturnPositions(transaction, kBenutzer, kWarenLagerPlatz, returnItems);
}
// 2. Process positive items: standard JTL picklist/delivery fulfillment
if (positiveItems.length) {
const kSessionId = await openSession(transaction, kBenutzer); const kSessionId = await openSession(transaction, kBenutzer);
try { try {
await reservePositions(transaction, kBenutzer, kSessionId, kWarenLager, deliveredItems); await reservePositions(transaction, kBenutzer, kSessionId, kWarenLager, positiveItems);
await bookStockShortfallsAndRereserve( await bookStockShortfallsAndRereserve(
transaction, transaction,
kBenutzer, kBenutzer,
kSessionId, kSessionId,
kWarenLager, kWarenLager,
kWarenLagerPlatz, kWarenLagerPlatz,
deliveredItems, positiveItems,
); );
await commitPicklists(transaction, kBenutzer, kSessionId, kAuftrag); await commitPicklists(transaction, kBenutzer, kSessionId, kAuftrag);
await deliverPicklists(transaction, kBenutzer, kSessionId, kAuftrag, kVersandArt); await deliverPicklists(transaction, kBenutzer, kSessionId, kAuftrag, kVersandArt);
@@ -48,11 +59,6 @@ export async function deliverOrder(transaction, kBenutzer, kAuftrag, kVersandArt
logger.error(`deliverOrder: FAILED kAuftrag=${kAuftrag} kSessionId=${kSessionId}: ${err.message}`); logger.error(`deliverOrder: FAILED kAuftrag=${kAuftrag} kSessionId=${kSessionId}: ${err.message}`);
throw err; throw err;
} finally { } 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 discardSession(transaction, kBenutzer, kSessionId);
await closeSession(transaction, kSessionId); await closeSession(transaction, kSessionId);
@@ -61,3 +67,4 @@ export async function deliverOrder(transaction, kBenutzer, kAuftrag, kVersandArt
} }
} }
} }
}

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.
*/ */