fix(delivery): deliver orders with father-articles and no-payment orders
- Treat an article that has become a father (nIstVater=1) as a free position (kArtikel=0) with the name kept: VersandIntern.vBestellPosOffen joins tArtikel with nIstVater=0, so such positions could never be reserved and failed with "insufficient stock after POS shortage booking" (e.g. Becks 42000030). - Recalculate tAuftragPositionEckdaten before deliverOrder so orders without payments get their positions reserved too (previously only insertPayment triggered the recalculation). Also adds debug logging across the delivery pipeline (reserve, commit, deliver, session, stock-shortage, create-order).
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import sql from 'mssql';
|
||||
import { getPool } from '../db.js';
|
||||
import { getActiveShopId, getActiveShopSubshopId } from '../shop.js';
|
||||
import { logger } from '../logger.js';
|
||||
import { deliverOrder } from './delivery/index.js';
|
||||
|
||||
const config = {
|
||||
@@ -449,8 +450,18 @@ async function insertOrderItem(transaction, kAuftrag, item) {
|
||||
if (sku && positionType !== VERSANDPOSITION_TYPE) {
|
||||
const result = await new sql.Request(transaction)
|
||||
.input('cArtNr', sql.NVarChar, sku)
|
||||
.query('SELECT TOP 1 kArtikel FROM dbo.tArtikel WHERE cArtNr = @cArtNr');
|
||||
kArtikel = result.recordset[0]?.kArtikel ?? null;
|
||||
.query('SELECT TOP 1 kArtikel, nIstVater FROM dbo.tArtikel WHERE cArtNr = @cArtNr');
|
||||
const row = result.recordset[0];
|
||||
kArtikel = row?.kArtikel ?? null;
|
||||
// An article that has become a father (nIstVater = 1) can never be picked/delivered
|
||||
// as a normal article: VersandIntern.vBestellPosOffen joins dbo.tArtikel with
|
||||
// Art.nIstVater = 0, so the reservation SP can never reserve it and the order
|
||||
// fails with "insufficient stock after POS shortage booking". Since the POS still
|
||||
// sells it as a plain SKU, fall back to a free position (kArtikel = 0) with the
|
||||
// name kept, which reserves/delivers like the Pfand lines do.
|
||||
if (row?.nIstVater === 1) {
|
||||
kArtikel = null;
|
||||
}
|
||||
}
|
||||
|
||||
const nType = positionType === VERSANDPOSITION_TYPE ? VERSANDPOSITION_TYPE : (kArtikel ? 1 : 0);
|
||||
@@ -742,6 +753,7 @@ export async function createOrder(order) {
|
||||
if (kAuftragPosition != null && !isVersandposition(item)) {
|
||||
deliveredItems.push({ kAuftragPosition, quantity: toNumber(item.quantity, 1) });
|
||||
}
|
||||
logger.info(`createOrder: item sku="${String(item.sku ?? '').trim()}" type=${item.type} kAuftragPosition=${kAuftragPosition} qty=${toNumber(item.quantity, 1)} -> delivered=${kAuftragPosition != null && !isVersandposition(item)}`);
|
||||
}
|
||||
|
||||
for (const payment of order.payments || []) {
|
||||
@@ -749,6 +761,15 @@ export async function createOrder(order) {
|
||||
await insertPayment(transaction, kAuftrag, payment, order, orderDate, zahlungsartCache);
|
||||
}
|
||||
|
||||
// Positions must be reflected in tAuftragPositionEckdaten before the delivery
|
||||
// reservation runs: VersandIntern.vBestellPosOffen joins tAuftragPositionEckdaten,
|
||||
// and without a populated row the reservation SP sees fAnzahlZuPicken = 0 and
|
||||
// reserves nothing ("insufficient stock after POS shortage booking"). insertPayment
|
||||
// recalculates for paid orders; do it unconditionally here so no-payment orders
|
||||
// (e.g. externalId=264) are delivered correctly too.
|
||||
await recalculateAuftragEckdaten(transaction, kAuftrag);
|
||||
|
||||
logger.info(`createOrder: kAuftrag=${kAuftrag} isOrderDelivered=${isOrderDelivered(order)} deliveredItems=${JSON.stringify(deliveredItems)}`);
|
||||
if (isOrderDelivered(order)) {
|
||||
await deliverOrder(transaction, config.kBenutzer, kAuftrag, kVersandArt, deliveredItems);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user