Compare commits
2 Commits
73d256e8a6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe0d2e43f4 | ||
|
|
5caedbe345 |
@@ -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);
|
||||||
@@ -60,4 +66,5 @@ export async function deliverOrder(transaction, kBenutzer, kAuftrag, kVersandArt
|
|||||||
// best-effort cleanup only
|
// best-effort cleanup only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -36,6 +36,21 @@ SELECT TOP (@limit)
|
|||||||
FROM dbo.tkategorieartikel ka
|
FROM dbo.tkategorieartikel ka
|
||||||
WHERE ka.kArtikel = a.kArtikel
|
WHERE ka.kArtikel = a.kArtikel
|
||||||
) AS categoryIds,
|
) AS categoryIds,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM dbo.tKategorieArtikel ka2
|
||||||
|
INNER JOIN dbo.tArtikel a2 ON a2.kArtikel = ka2.kArtikel AND a2.cAktiv = 'Y'
|
||||||
|
INNER JOIN dbo.tArtikelBeschreibung ab2 ON ab2.kArtikel = a2.kArtikel AND ab2.kSprache = @languageId
|
||||||
|
WHERE ka2.kKategorie = (
|
||||||
|
SELECT TOP 1 ka1.kKategorie
|
||||||
|
FROM dbo.tKategorieArtikel ka1
|
||||||
|
WHERE ka1.kArtikel = a.kArtikel
|
||||||
|
)
|
||||||
|
AND (
|
||||||
|
ab2.cName < ab.cName
|
||||||
|
OR (ab2.cName = ab.cName AND a2.kArtikel < a.kArtikel)
|
||||||
|
)
|
||||||
|
) AS sort,
|
||||||
a.nIstVater AS isParent,
|
a.nIstVater AS isParent,
|
||||||
a.kVaterArtikel AS parentArticleId,
|
a.kVaterArtikel AS parentArticleId,
|
||||||
CASE WHEN a.kStueckliste <> 0 THEN '1' ELSE '0' END AS isCompositeProduct,
|
CASE WHEN a.kStueckliste <> 0 THEN '1' ELSE '0' END AS isCompositeProduct,
|
||||||
@@ -204,6 +219,7 @@ export async function getProductList({ cursor = 0, limit = 20 } = {}) {
|
|||||||
price: basePrice,
|
price: basePrice,
|
||||||
created_at: formatDateTime(product.createdAt),
|
created_at: formatDateTime(product.createdAt),
|
||||||
lastChanged: String(product.lastChanged),
|
lastChanged: String(product.lastChanged),
|
||||||
|
sort: String(product.sort ?? 0),
|
||||||
categories_id: categoryIds[0] ?? '0',
|
categories_id: categoryIds[0] ?? '0',
|
||||||
categories: categoryIds.map((categoryId) => ({ categoryId })),
|
categories: categoryIds.map((categoryId) => ({ categoryId })),
|
||||||
prices,
|
prices,
|
||||||
|
|||||||
Reference in New Issue
Block a user