Add more columns and column selector to product table
This commit is contained in:
@@ -23,17 +23,17 @@ router.get('/', async (req, res) => {
|
||||
const sortDirection = req.query.sortDirection === 'desc' ? 'DESC' : 'ASC';
|
||||
|
||||
// Build the WHERE clause
|
||||
const conditions = ['visible = true'];
|
||||
const conditions = ['p.visible = true'];
|
||||
const params = [];
|
||||
|
||||
if (search) {
|
||||
conditions.push('(title LIKE ? OR SKU LIKE ?)');
|
||||
conditions.push('(p.title LIKE ? OR p.SKU LIKE ?)');
|
||||
params.push(`%${search}%`, `%${search}%`);
|
||||
}
|
||||
|
||||
if (category !== 'all') {
|
||||
conditions.push(`
|
||||
product_id IN (
|
||||
p.product_id IN (
|
||||
SELECT pc.product_id
|
||||
FROM product_categories pc
|
||||
JOIN categories c ON pc.category_id = c.id
|
||||
@@ -44,42 +44,42 @@ router.get('/', async (req, res) => {
|
||||
}
|
||||
|
||||
if (vendor !== 'all') {
|
||||
conditions.push('vendor = ?');
|
||||
conditions.push('p.vendor = ?');
|
||||
params.push(vendor);
|
||||
}
|
||||
|
||||
if (stockStatus !== 'all') {
|
||||
switch (stockStatus) {
|
||||
case 'out_of_stock':
|
||||
conditions.push('stock_quantity = 0');
|
||||
conditions.push('p.stock_quantity = 0');
|
||||
break;
|
||||
case 'low_stock':
|
||||
conditions.push('stock_quantity > 0 AND stock_quantity <= 5');
|
||||
conditions.push('p.stock_quantity > 0 AND p.stock_quantity <= 5');
|
||||
break;
|
||||
case 'in_stock':
|
||||
conditions.push('stock_quantity > 5');
|
||||
conditions.push('p.stock_quantity > 5');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minPrice > 0) {
|
||||
conditions.push('price >= ?');
|
||||
conditions.push('p.price >= ?');
|
||||
params.push(minPrice);
|
||||
}
|
||||
|
||||
if (maxPrice) {
|
||||
conditions.push('price <= ?');
|
||||
conditions.push('p.price <= ?');
|
||||
params.push(maxPrice);
|
||||
}
|
||||
|
||||
// Get total count for pagination
|
||||
const [countResult] = await pool.query(
|
||||
`SELECT COUNT(*) as total FROM products WHERE ${conditions.join(' AND ')}`,
|
||||
`SELECT COUNT(*) as total FROM products p WHERE ${conditions.join(' AND ')}`,
|
||||
params
|
||||
);
|
||||
const total = countResult[0].total;
|
||||
|
||||
// Get paginated results
|
||||
// Get paginated results with metrics
|
||||
const query = `
|
||||
SELECT
|
||||
p.product_id,
|
||||
@@ -89,15 +89,50 @@ router.get('/', async (req, res) => {
|
||||
p.price,
|
||||
p.regular_price,
|
||||
p.cost_price,
|
||||
p.landing_cost_price,
|
||||
p.barcode,
|
||||
p.vendor,
|
||||
p.vendor_reference,
|
||||
p.brand,
|
||||
p.visible,
|
||||
p.managing_stock,
|
||||
p.replenishable,
|
||||
p.moq,
|
||||
p.uom,
|
||||
p.image,
|
||||
GROUP_CONCAT(c.name) as categories
|
||||
GROUP_CONCAT(DISTINCT c.name) as categories,
|
||||
|
||||
-- Metrics from product_metrics
|
||||
pm.daily_sales_avg,
|
||||
pm.weekly_sales_avg,
|
||||
pm.monthly_sales_avg,
|
||||
pm.avg_quantity_per_order,
|
||||
pm.number_of_orders,
|
||||
pm.first_sale_date,
|
||||
pm.last_sale_date,
|
||||
pm.days_of_inventory,
|
||||
pm.weeks_of_inventory,
|
||||
pm.reorder_point,
|
||||
pm.safety_stock,
|
||||
pm.avg_margin_percent,
|
||||
pm.total_revenue,
|
||||
pm.inventory_value,
|
||||
pm.cost_of_goods_sold,
|
||||
pm.gross_profit,
|
||||
pm.gmroi,
|
||||
pm.avg_lead_time_days,
|
||||
pm.last_purchase_date,
|
||||
pm.last_received_date,
|
||||
pm.abc_class,
|
||||
pm.stock_status,
|
||||
pm.turnover_rate,
|
||||
pm.current_lead_time,
|
||||
pm.target_lead_time,
|
||||
pm.lead_time_status
|
||||
FROM products p
|
||||
LEFT JOIN product_categories pc ON p.product_id = pc.product_id
|
||||
LEFT JOIN categories c ON pc.category_id = c.id
|
||||
LEFT JOIN product_metrics pm ON p.product_id = pm.product_id
|
||||
WHERE ${conditions.join(' AND ')}
|
||||
GROUP BY p.product_id
|
||||
ORDER BY ${sortColumn} ${sortDirection}
|
||||
@@ -106,10 +141,38 @@ router.get('/', async (req, res) => {
|
||||
|
||||
const [rows] = await pool.query(query, [...params, limit, offset]);
|
||||
|
||||
// Transform the categories string into an array
|
||||
// Transform the categories string into an array and parse numeric values
|
||||
const productsWithCategories = rows.map(product => ({
|
||||
...product,
|
||||
categories: product.categories ? product.categories.split(',') : []
|
||||
categories: product.categories ? [...new Set(product.categories.split(','))] : [],
|
||||
// Parse numeric values
|
||||
price: parseFloat(product.price) || 0,
|
||||
regular_price: parseFloat(product.regular_price) || 0,
|
||||
cost_price: parseFloat(product.cost_price) || 0,
|
||||
landing_cost_price: parseFloat(product.landing_cost_price) || 0,
|
||||
stock_quantity: parseInt(product.stock_quantity) || 0,
|
||||
moq: parseInt(product.moq) || 1,
|
||||
uom: parseInt(product.uom) || 1,
|
||||
// Parse metrics
|
||||
daily_sales_avg: parseFloat(product.daily_sales_avg) || null,
|
||||
weekly_sales_avg: parseFloat(product.weekly_sales_avg) || null,
|
||||
monthly_sales_avg: parseFloat(product.monthly_sales_avg) || null,
|
||||
avg_quantity_per_order: parseFloat(product.avg_quantity_per_order) || null,
|
||||
number_of_orders: parseInt(product.number_of_orders) || null,
|
||||
days_of_inventory: parseInt(product.days_of_inventory) || null,
|
||||
weeks_of_inventory: parseInt(product.weeks_of_inventory) || null,
|
||||
reorder_point: parseInt(product.reorder_point) || null,
|
||||
safety_stock: parseInt(product.safety_stock) || null,
|
||||
avg_margin_percent: parseFloat(product.avg_margin_percent) || null,
|
||||
total_revenue: parseFloat(product.total_revenue) || null,
|
||||
inventory_value: parseFloat(product.inventory_value) || null,
|
||||
cost_of_goods_sold: parseFloat(product.cost_of_goods_sold) || null,
|
||||
gross_profit: parseFloat(product.gross_profit) || null,
|
||||
gmroi: parseFloat(product.gmroi) || null,
|
||||
turnover_rate: parseFloat(product.turnover_rate) || null,
|
||||
avg_lead_time_days: parseInt(product.avg_lead_time_days) || null,
|
||||
current_lead_time: parseInt(product.current_lead_time) || null,
|
||||
target_lead_time: parseInt(product.target_lead_time) || null
|
||||
}));
|
||||
|
||||
// Get unique categories and vendors for filters
|
||||
|
||||
@@ -79,7 +79,7 @@ const pool = initPool({
|
||||
app.locals.pool = pool;
|
||||
|
||||
// Routes
|
||||
app.use('/api/dashboard/products', productsRouter);
|
||||
app.use('/api/products', productsRouter);
|
||||
app.use('/api/dashboard', dashboardRouter);
|
||||
app.use('/api/orders', ordersRouter);
|
||||
app.use('/api/csv', csvRouter);
|
||||
|
||||
Reference in New Issue
Block a user