Add product search and template creation functionality to validation step
This commit is contained in:
@@ -566,6 +566,9 @@ router.get('/field-options', async (req, res) => {
|
||||
};
|
||||
});
|
||||
|
||||
// Add debugging to verify category types
|
||||
console.log(`Returning ${result.categories.length} categories with types: ${Array.from(new Set(result.categories.map(c => c.type))).join(', ')}`);
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
console.error('Error fetching import field options:', error);
|
||||
@@ -715,4 +718,232 @@ router.get('/list-uploads', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Search products from production database
|
||||
router.get('/search-products', async (req, res) => {
|
||||
const { q, company, dateRange } = req.query;
|
||||
|
||||
if (!q) {
|
||||
return res.status(400).json({ error: 'Search term is required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const { connection } = await getDbConnection();
|
||||
|
||||
// Build WHERE clause with additional filters
|
||||
let whereClause = `
|
||||
WHERE (
|
||||
p.description LIKE ? OR
|
||||
p.itemnumber LIKE ? OR
|
||||
p.upc LIKE ? OR
|
||||
pc1.name LIKE ? OR
|
||||
s.companyname LIKE ?
|
||||
)`;
|
||||
|
||||
// Add company filter if provided
|
||||
if (company) {
|
||||
whereClause += ` AND p.company = ${connection.escape(company)}`;
|
||||
}
|
||||
|
||||
// Add date range filter if provided
|
||||
if (dateRange) {
|
||||
let dateCondition;
|
||||
const now = new Date();
|
||||
|
||||
switch(dateRange) {
|
||||
case '1week':
|
||||
// Last week: date is after (current date - 7 days)
|
||||
const weekAgo = new Date(now);
|
||||
weekAgo.setDate(now.getDate() - 7);
|
||||
dateCondition = `p.datein >= ${connection.escape(weekAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
case '1month':
|
||||
// Last month: date is after (current date - 30 days)
|
||||
const monthAgo = new Date(now);
|
||||
monthAgo.setDate(now.getDate() - 30);
|
||||
dateCondition = `p.datein >= ${connection.escape(monthAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
case '2months':
|
||||
// Last 2 months: date is after (current date - 60 days)
|
||||
const twoMonthsAgo = new Date(now);
|
||||
twoMonthsAgo.setDate(now.getDate() - 60);
|
||||
dateCondition = `p.datein >= ${connection.escape(twoMonthsAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
case '3months':
|
||||
// Last 3 months: date is after (current date - 90 days)
|
||||
const threeMonthsAgo = new Date(now);
|
||||
threeMonthsAgo.setDate(now.getDate() - 90);
|
||||
dateCondition = `p.datein >= ${connection.escape(threeMonthsAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
case '6months':
|
||||
// Last 6 months: date is after (current date - 180 days)
|
||||
const sixMonthsAgo = new Date(now);
|
||||
sixMonthsAgo.setDate(now.getDate() - 180);
|
||||
dateCondition = `p.datein >= ${connection.escape(sixMonthsAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
case '1year':
|
||||
// Last year: date is after (current date - 365 days)
|
||||
const yearAgo = new Date(now);
|
||||
yearAgo.setDate(now.getDate() - 365);
|
||||
dateCondition = `p.datein >= ${connection.escape(yearAgo.toISOString().slice(0, 10))}`;
|
||||
break;
|
||||
default:
|
||||
// If an unrecognized value is provided, don't add a date condition
|
||||
dateCondition = null;
|
||||
}
|
||||
|
||||
if (dateCondition) {
|
||||
whereClause += ` AND ${dateCondition}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for wildcard search
|
||||
const isWildcardSearch = q === '*';
|
||||
const searchPattern = isWildcardSearch ? '%' : `%${q}%`;
|
||||
const exactPattern = isWildcardSearch ? '%' : q;
|
||||
|
||||
// Search for products based on various fields
|
||||
const query = `
|
||||
SELECT
|
||||
p.pid,
|
||||
p.description AS title,
|
||||
p.notes AS description,
|
||||
p.itemnumber AS sku,
|
||||
p.upc AS barcode,
|
||||
p.harmonized_tariff_code,
|
||||
pcp.price_each AS price,
|
||||
p.sellingprice AS regular_price,
|
||||
CASE
|
||||
WHEN EXISTS (SELECT 1 FROM product_inventory WHERE pid = p.pid AND count > 0)
|
||||
THEN (SELECT ROUND(AVG(costeach), 5) FROM product_inventory WHERE pid = p.pid AND count > 0)
|
||||
ELSE (SELECT costeach FROM product_inventory WHERE pid = p.pid ORDER BY daterec DESC LIMIT 1)
|
||||
END AS cost_price,
|
||||
s.companyname AS vendor,
|
||||
sid.supplier_itemnumber AS vendor_reference,
|
||||
sid.notions_itemnumber AS notions_reference,
|
||||
pc1.name AS brand,
|
||||
p.company AS brand_id,
|
||||
pc2.name AS line,
|
||||
p.line AS line_id,
|
||||
pc3.name AS subline,
|
||||
p.subline AS subline_id,
|
||||
pc4.name AS artist,
|
||||
p.artist AS artist_id,
|
||||
COALESCE(CASE
|
||||
WHEN sid.supplier_id = 92 THEN sid.notions_qty_per_unit
|
||||
ELSE sid.supplier_qty_per_unit
|
||||
END, sid.notions_qty_per_unit) AS moq,
|
||||
p.weight,
|
||||
p.length,
|
||||
p.width,
|
||||
p.height,
|
||||
p.country_of_origin,
|
||||
p.totalsold AS total_sold,
|
||||
p.datein AS first_received,
|
||||
pls.date_sold AS date_last_sold
|
||||
FROM products p
|
||||
LEFT JOIN product_current_prices pcp ON p.pid = pcp.pid AND pcp.active = 1
|
||||
LEFT JOIN supplier_item_data sid ON p.pid = sid.pid
|
||||
LEFT JOIN suppliers s ON sid.supplier_id = s.supplierid
|
||||
LEFT JOIN product_categories pc1 ON p.company = pc1.cat_id
|
||||
LEFT JOIN product_categories pc2 ON p.line = pc2.cat_id
|
||||
LEFT JOIN product_categories pc3 ON p.subline = pc3.cat_id
|
||||
LEFT JOIN product_categories pc4 ON p.artist = pc4.cat_id
|
||||
LEFT JOIN product_last_sold pls ON p.pid = pls.pid
|
||||
${whereClause}
|
||||
GROUP BY p.pid
|
||||
${isWildcardSearch ? 'ORDER BY p.datein DESC' : `
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN p.description LIKE ? THEN 1
|
||||
WHEN p.itemnumber = ? THEN 2
|
||||
WHEN p.upc = ? THEN 3
|
||||
WHEN pc1.name LIKE ? THEN 4
|
||||
WHEN s.companyname LIKE ? THEN 5
|
||||
ELSE 6
|
||||
END
|
||||
`}
|
||||
`;
|
||||
|
||||
// Prepare query parameters based on whether it's a wildcard search
|
||||
let queryParams;
|
||||
if (isWildcardSearch) {
|
||||
queryParams = [
|
||||
searchPattern, // LIKE for description
|
||||
searchPattern, // LIKE for itemnumber
|
||||
searchPattern, // LIKE for upc
|
||||
searchPattern, // LIKE for brand name
|
||||
searchPattern // LIKE for company name
|
||||
];
|
||||
} else {
|
||||
queryParams = [
|
||||
searchPattern, // LIKE for description
|
||||
searchPattern, // LIKE for itemnumber
|
||||
searchPattern, // LIKE for upc
|
||||
searchPattern, // LIKE for brand name
|
||||
searchPattern, // LIKE for company name
|
||||
// For ORDER BY clause
|
||||
searchPattern, // LIKE for description
|
||||
exactPattern, // Exact match for itemnumber
|
||||
exactPattern, // Exact match for upc
|
||||
searchPattern, // LIKE for brand name
|
||||
searchPattern // LIKE for company name
|
||||
];
|
||||
}
|
||||
|
||||
const [results] = await connection.query(query, queryParams);
|
||||
|
||||
res.json(results);
|
||||
} catch (error) {
|
||||
console.error('Error searching products:', error);
|
||||
res.status(500).json({ error: 'Failed to search products' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get product categories for a specific product
|
||||
router.get('/product-categories/:pid', async (req, res) => {
|
||||
try {
|
||||
const { pid } = req.params;
|
||||
|
||||
if (!pid || isNaN(parseInt(pid))) {
|
||||
return res.status(400).json({ error: 'Valid product ID is required' });
|
||||
}
|
||||
|
||||
// Use the getDbConnection function instead of getPool
|
||||
const { connection } = await getDbConnection();
|
||||
|
||||
// Query to get categories for a specific product
|
||||
const query = `
|
||||
SELECT pc.cat_id, pc.name, pc.type, pc.combined_name
|
||||
FROM product_category_index pci
|
||||
JOIN product_categories pc ON pci.cat_id = pc.cat_id
|
||||
WHERE pci.pid = ?
|
||||
ORDER BY pc.type, pc.name
|
||||
`;
|
||||
|
||||
const [rows] = await connection.query(query, [pid]);
|
||||
|
||||
// Add debugging to log category types
|
||||
const categoryTypes = rows.map(row => row.type);
|
||||
const uniqueTypes = [...new Set(categoryTypes)];
|
||||
console.log(`Product ${pid} has ${rows.length} categories with types: ${uniqueTypes.join(', ')}`);
|
||||
console.log('Categories:', rows.map(row => ({ id: row.cat_id, name: row.name, type: row.type })));
|
||||
|
||||
// Format the response to match the expected format in the frontend
|
||||
const categories = rows.map(category => ({
|
||||
value: category.cat_id.toString(),
|
||||
label: category.name,
|
||||
type: category.type,
|
||||
combined_name: category.combined_name
|
||||
}));
|
||||
|
||||
res.json(categories);
|
||||
} catch (error) {
|
||||
console.error('Error fetching product categories:', error);
|
||||
res.status(500).json({
|
||||
error: 'Failed to fetch product categories',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user