Optimize getInventory method in FalukantService by replacing nested includes with a single SQL query for improved performance. Add error handling for invalid branchId input.
This commit is contained in:
@@ -1547,46 +1547,62 @@ class FalukantService extends BaseService {
|
||||
}
|
||||
|
||||
async getInventory(hashedUserId, branchId) {
|
||||
// PERFORMANCE: Diese Route war langsam wegen doppelter/verschachtelter Includes (Branch->Stocks->Region + Inventory->Stock->Branch->Region).
|
||||
// Wir holen stattdessen genau die benötigten Felder in EINER aggregierenden SQL-Query.
|
||||
const u = await getFalukantUserOrFail(hashedUserId);
|
||||
const f = branchId ? { id: branchId, falukantUserId: u.id } : { falukantUserId: u.id };
|
||||
const br = await Branch.findAll({
|
||||
where: f,
|
||||
include: [
|
||||
{ model: FalukantStock, as: 'stocks', include: [{ model: FalukantStockType, as: 'stockType' }] },
|
||||
{ model: RegionData, as: 'region', include: [{ model: RegionType, as: 'regionType' }] }
|
||||
]
|
||||
});
|
||||
const stockIds = br.flatMap(b => b.stocks.map(s => s.id));
|
||||
const inv = await Inventory.findAll({
|
||||
where: { stockId: stockIds },
|
||||
include: [
|
||||
{
|
||||
model: FalukantStock,
|
||||
as: 'stock',
|
||||
include: [
|
||||
{
|
||||
model: Branch,
|
||||
as: 'branch',
|
||||
include: [{ model: RegionData, as: 'region', include: [{ model: RegionType, as: 'regionType' }] }]
|
||||
},
|
||||
{ model: FalukantStockType, as: 'stockType' }
|
||||
]
|
||||
},
|
||||
{ model: ProductType, as: 'productType' }
|
||||
]
|
||||
});
|
||||
const grouped = inv.reduce((acc, i) => {
|
||||
const r = i.stock.branch.region;
|
||||
const k = `${r.id}-${i.productType.id}-${i.quality}`;
|
||||
acc[k] = acc[k] || { region: r, product: i.productType, quality: i.quality, totalQuantity: 0 };
|
||||
acc[k].totalQuantity += i.quantity;
|
||||
return acc;
|
||||
}, {});
|
||||
return Object.values(grouped).sort((a, b) => {
|
||||
if (a.region.id !== b.region.id) return a.region.id - b.region.id;
|
||||
if (a.product.id !== b.product.id) return a.product.id - b.product.id;
|
||||
return a.quality - b.quality;
|
||||
});
|
||||
const branchIdInt = branchId == null ? null : parseInt(branchId, 10);
|
||||
if (branchId != null && Number.isNaN(branchIdInt)) {
|
||||
throw new Error('Invalid branchId');
|
||||
}
|
||||
|
||||
const rows = await sequelize.query(
|
||||
`
|
||||
SELECT
|
||||
r.id AS region_id,
|
||||
r.name AS region_name,
|
||||
rt.id AS region_type_id,
|
||||
rt.label_tr AS region_type_label_tr,
|
||||
p.id AS product_id,
|
||||
p.label_tr AS product_label_tr,
|
||||
p.sell_cost AS product_sell_cost,
|
||||
i.quality AS quality,
|
||||
SUM(i.quantity)::int AS total_quantity
|
||||
FROM falukant_data.inventory i
|
||||
JOIN falukant_data.stock s ON s.id = i.stock_id
|
||||
JOIN falukant_data.branch b ON b.id = s.branch_id
|
||||
JOIN falukant_data.region r ON r.id = b.region_id
|
||||
LEFT JOIN falukant_type.region rt ON rt.id = r.region_type_id
|
||||
JOIN falukant_type.product p ON p.id = i.product_id
|
||||
WHERE b.falukant_user_id = :falukantUserId
|
||||
AND (:branchId::int IS NULL OR b.id = :branchId::int)
|
||||
GROUP BY
|
||||
r.id, r.name, rt.id, rt.label_tr,
|
||||
p.id, p.label_tr, p.sell_cost,
|
||||
i.quality
|
||||
ORDER BY r.id, p.id, i.quality
|
||||
`,
|
||||
{
|
||||
replacements: { falukantUserId: u.id, branchId: branchIdInt },
|
||||
type: sequelize.QueryTypes.SELECT
|
||||
}
|
||||
);
|
||||
|
||||
return (rows || []).map(r => ({
|
||||
region: {
|
||||
id: r.region_id,
|
||||
name: r.region_name,
|
||||
regionType: r.region_type_id
|
||||
? { id: r.region_type_id, labelTr: r.region_type_label_tr }
|
||||
: null
|
||||
},
|
||||
product: {
|
||||
id: r.product_id,
|
||||
labelTr: r.product_label_tr,
|
||||
sellCost: r.product_sell_cost
|
||||
},
|
||||
quality: r.quality,
|
||||
totalQuantity: r.total_quantity
|
||||
}));
|
||||
}
|
||||
|
||||
async sellProduct(hashedUserId, branchId, productId, quality, quantity) {
|
||||
|
||||
Reference in New Issue
Block a user