Refactor inventory handling in FalukantService: Update product transport logic to retrieve all stocks for a branch, improving inventory checks and ensuring accurate transport cost calculations. Implement locking during inventory updates to maintain data integrity during transactions.
This commit is contained in:
@@ -994,33 +994,33 @@ class FalukantService extends BaseService {
|
|||||||
// Produkt-Transport oder leerer Transport (nur Fahrzeuge bewegen)?
|
// Produkt-Transport oder leerer Transport (nur Fahrzeuge bewegen)?
|
||||||
const isEmptyTransport = !productId || !quantity || quantity <= 0;
|
const isEmptyTransport = !productId || !quantity || quantity <= 0;
|
||||||
|
|
||||||
let inventory = [];
|
let sourceStockIds = [];
|
||||||
let available = 0;
|
let available = 0;
|
||||||
let maxByInventory = 0;
|
let maxByInventory = 0;
|
||||||
let hardMax = 0;
|
let hardMax = 0;
|
||||||
let requested = 0;
|
let requested = 0;
|
||||||
let transportCost = 0.1; // Minimale Kosten für leeren Transport
|
let transportCost = 0.1; // Minimale Kosten für leeren Transport
|
||||||
|
let productIdForTransport = productId;
|
||||||
|
|
||||||
if (!isEmptyTransport) {
|
if (!isEmptyTransport) {
|
||||||
// Produkt-Transport: Inventar prüfen
|
// Produkt-Transport: alle Stocks der Quell-Niederlassung (wie getInventory)
|
||||||
const stock = await FalukantStock.findOne({ where: { branchId: sourceBranch.id } });
|
const sourceStocks = await FalukantStock.findAll({ where: { branchId: sourceBranch.id }, attributes: ['id'] });
|
||||||
if (!stock) {
|
if (!sourceStocks?.length) {
|
||||||
throw new Error('Stock not found');
|
throw new Error('Stock not found');
|
||||||
}
|
}
|
||||||
|
sourceStockIds = sourceStocks.map((s) => s.id);
|
||||||
|
|
||||||
inventory = await Inventory.findAll({
|
const inventoryCheck = await Inventory.findAll({
|
||||||
where: { stockId: stock.id },
|
where: {
|
||||||
|
stockId: { [Op.in]: sourceStockIds },
|
||||||
|
productId,
|
||||||
|
},
|
||||||
include: [
|
include: [
|
||||||
{
|
{ model: ProductType, as: 'productType', required: true, where: { id: productId }, attributes: ['id', 'sellCost'] },
|
||||||
model: ProductType,
|
|
||||||
as: 'productType',
|
|
||||||
required: true,
|
|
||||||
where: { id: productId },
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
available = inventory.reduce((sum, i) => sum + i.quantity, 0);
|
available = inventoryCheck.reduce((sum, i) => sum + i.quantity, 0);
|
||||||
if (available <= 0) {
|
if (available <= 0) {
|
||||||
throw new PreconditionError('noInventory');
|
throw new PreconditionError('noInventory');
|
||||||
}
|
}
|
||||||
@@ -1034,7 +1034,7 @@ class FalukantService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transportkosten: 1 % des Warenwerts, mindestens 0,1
|
// Transportkosten: 1 % des Warenwerts, mindestens 0,1
|
||||||
const productType = inventory[0]?.productType;
|
const productType = inventoryCheck[0]?.productType;
|
||||||
const unitValue = productType?.sellCost || 0;
|
const unitValue = productType?.sellCost || 0;
|
||||||
const totalValue = unitValue * requested;
|
const totalValue = unitValue * requested;
|
||||||
transportCost = Math.max(0.1, totalValue * 0.01);
|
transportCost = Math.max(0.1, totalValue * 0.01);
|
||||||
@@ -1090,15 +1090,28 @@ class FalukantService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inventar in der Quell-Niederlassung reduzieren (nur bei Produkt-Transport)
|
// Inventar in der Quell-Niederlassung reduzieren (nur bei Produkt-Transport)
|
||||||
if (!isEmptyTransport && inventory.length > 0) {
|
// Innerhalb der Transaktion mit Lock laden, damit aktuelle Mengen verwendet werden
|
||||||
|
if (!isEmptyTransport && sourceStockIds.length > 0) {
|
||||||
|
const inventoryRows = await Inventory.findAll({
|
||||||
|
where: {
|
||||||
|
stockId: { [Op.in]: sourceStockIds },
|
||||||
|
productId: productIdForTransport,
|
||||||
|
},
|
||||||
|
order: [['id', 'ASC']],
|
||||||
|
lock: true, // SELECT ... FOR UPDATE
|
||||||
|
transaction: tx,
|
||||||
|
});
|
||||||
|
|
||||||
let left = requested;
|
let left = requested;
|
||||||
for (const inv of inventory) {
|
for (const inv of inventoryRows) {
|
||||||
if (left <= 0) break;
|
if (left <= 0) break;
|
||||||
if (inv.quantity <= left) {
|
const qty = Number(inv.quantity) || 0;
|
||||||
left -= inv.quantity;
|
if (qty <= 0) continue;
|
||||||
|
if (qty <= left) {
|
||||||
|
left -= qty;
|
||||||
await inv.destroy({ transaction: tx });
|
await inv.destroy({ transaction: tx });
|
||||||
} else {
|
} else {
|
||||||
await inv.update({ quantity: inv.quantity - left }, { transaction: tx });
|
await inv.update({ quantity: qty - left }, { transaction: tx });
|
||||||
left = 0;
|
left = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user