Dashboard tweaks, add bulk /check-upcs endpoint for import validation

This commit is contained in:
2026-07-27 13:47:06 -04:00
parent 6c973f0a9d
commit 4e4a09ee3f
5 changed files with 345 additions and 179 deletions
+70
View File
@@ -1931,6 +1931,76 @@ router.post('/generate-upc', async (req, res) => {
}
});
// Bulk "does this UPC already exist" check for the import validator.
// The one-at-a-time alternative is /search-products?q=<upc>, but that runs a
// five-column LIKE '%q%' scan across ten joined tables (~6s each) and every call
// queues on the single shared connection from getDbConnection() — a 20-product
// batch takes minutes. This answers the whole batch with one indexed IN() lookup
// on idx_upc. Matches /check-upc-and-generate-sku's semantics: `upc` only, not upc_2.
const MAX_UPCS_PER_CHECK = 500;
router.get('/check-upcs', async (req, res) => {
const { upcs } = req.query;
if (!upcs) {
return res.status(400).json({ error: 'upcs query parameter is required' });
}
// Dedupe and keep only well-formed barcodes — anything else can't match the
// column anyway, and dropping it keeps the IN() list tight.
const upcList = [...new Set(
String(upcs).split(',').map(s => s.trim()).filter(s => /^\d{8,14}$/.test(s))
)];
if (upcList.length === 0) {
return res.json({ found: {}, checked: 0 });
}
if (upcList.length > MAX_UPCS_PER_CHECK) {
return res.status(400).json({
error: `Too many UPCs (${upcList.length}); send at most ${MAX_UPCS_PER_CHECK} per request`
});
}
try {
const { connection } = await getDbConnection();
const placeholders = upcList.map(() => '?').join(',');
const [rows] = await connection.query(
`SELECT pid, upc, itemnumber, description FROM products WHERE upc IN (${placeholders})`,
upcList
);
// idx_upc is non-unique, so a UPC can legitimately hit more than one product.
// Report the lowest pid (the original) and say how many share it.
const found = {};
for (const row of rows) {
const key = String(row.upc);
const existing = found[key];
if (!existing) {
found[key] = {
pid: row.pid,
itemNumber: row.itemnumber,
title: row.description,
matchCount: 1
};
continue;
}
existing.matchCount += 1;
if (row.pid < existing.pid) {
existing.pid = row.pid;
existing.itemNumber = row.itemnumber;
existing.title = row.description;
}
}
return res.json({ found, checked: upcList.length });
} catch (error) {
console.error('Error checking UPCs:', error);
return res.status(500).json({ error: 'Failed to check UPCs', details: error.message });
}
});
// Endpoint to check UPC and generate item number
router.get('/check-upc-and-generate-sku', async (req, res) => {
const { upc, supplierId } = req.query;