Get frontend pages loading data again, remove unused components
This commit is contained in:
@@ -97,6 +97,28 @@ router.get('/', async (req, res) => {
|
||||
const pages = Math.ceil(total / limit);
|
||||
|
||||
// Get recent purchase orders
|
||||
let orderByClause;
|
||||
|
||||
if (sortColumn === 'order_date') {
|
||||
orderByClause = `date ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'vendor_name') {
|
||||
orderByClause = `vendor ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'total_cost') {
|
||||
orderByClause = `total_cost ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'total_received') {
|
||||
orderByClause = `total_received ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'total_items') {
|
||||
orderByClause = `total_items ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'total_quantity') {
|
||||
orderByClause = `total_quantity ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'fulfillment_rate') {
|
||||
orderByClause = `fulfillment_rate ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else if (sortColumn === 'status') {
|
||||
orderByClause = `status ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
} else {
|
||||
orderByClause = `date ${sortDirection === 'desc' ? 'DESC' : 'ASC'}`;
|
||||
}
|
||||
|
||||
const { rows: orders } = await pool.query(`
|
||||
WITH po_totals AS (
|
||||
SELECT
|
||||
@@ -128,20 +150,9 @@ router.get('/', async (req, res) => {
|
||||
total_received,
|
||||
fulfillment_rate
|
||||
FROM po_totals
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN $${paramCounter} = 'order_date' THEN date
|
||||
WHEN $${paramCounter} = 'vendor_name' THEN vendor
|
||||
WHEN $${paramCounter} = 'total_cost' THEN total_cost
|
||||
WHEN $${paramCounter} = 'total_received' THEN total_received
|
||||
WHEN $${paramCounter} = 'total_items' THEN total_items
|
||||
WHEN $${paramCounter} = 'total_quantity' THEN total_quantity
|
||||
WHEN $${paramCounter} = 'fulfillment_rate' THEN fulfillment_rate
|
||||
WHEN $${paramCounter} = 'status' THEN status
|
||||
ELSE date
|
||||
END ${sortDirection === 'desc' ? 'DESC' : 'ASC'}
|
||||
LIMIT $${paramCounter + 1} OFFSET $${paramCounter + 2}
|
||||
`, [...params, sortColumn, Number(limit), offset]);
|
||||
ORDER BY ${orderByClause}
|
||||
LIMIT $${paramCounter} OFFSET $${paramCounter + 1}
|
||||
`, [...params, Number(limit), offset]);
|
||||
|
||||
// Get unique vendors for filter options
|
||||
const { rows: vendors } = await pool.query(`
|
||||
@@ -272,7 +283,7 @@ router.get('/cost-analysis', async (req, res) => {
|
||||
try {
|
||||
const pool = req.app.locals.pool;
|
||||
|
||||
const [analysis] = await pool.query(`
|
||||
const { rows: analysis } = await pool.query(`
|
||||
WITH category_costs AS (
|
||||
SELECT
|
||||
c.name as category,
|
||||
@@ -290,11 +301,11 @@ router.get('/cost-analysis', async (req, res) => {
|
||||
SELECT
|
||||
category,
|
||||
COUNT(DISTINCT pid) as unique_products,
|
||||
CAST(AVG(cost_price) AS DECIMAL(15,3)) as avg_cost,
|
||||
CAST(MIN(cost_price) AS DECIMAL(15,3)) as min_cost,
|
||||
CAST(MAX(cost_price) AS DECIMAL(15,3)) as max_cost,
|
||||
CAST(STDDEV(cost_price) AS DECIMAL(15,3)) as cost_variance,
|
||||
CAST(SUM(ordered * cost_price) AS DECIMAL(15,3)) as total_spend
|
||||
ROUND(AVG(cost_price)::numeric, 3) as avg_cost,
|
||||
ROUND(MIN(cost_price)::numeric, 3) as min_cost,
|
||||
ROUND(MAX(cost_price)::numeric, 3) as max_cost,
|
||||
ROUND(STDDEV(cost_price)::numeric, 3) as cost_variance,
|
||||
ROUND(SUM(ordered * cost_price)::numeric, 3) as total_spend
|
||||
FROM category_costs
|
||||
GROUP BY category
|
||||
ORDER BY total_spend DESC
|
||||
@@ -302,17 +313,37 @@ router.get('/cost-analysis', async (req, res) => {
|
||||
|
||||
// Parse numeric values
|
||||
const parsedAnalysis = {
|
||||
categories: analysis.map(cat => ({
|
||||
unique_products: 0,
|
||||
avg_cost: 0,
|
||||
min_cost: 0,
|
||||
max_cost: 0,
|
||||
cost_variance: 0,
|
||||
total_spend_by_category: analysis.map(cat => ({
|
||||
category: cat.category,
|
||||
unique_products: Number(cat.unique_products) || 0,
|
||||
avg_cost: Number(cat.avg_cost) || 0,
|
||||
min_cost: Number(cat.min_cost) || 0,
|
||||
max_cost: Number(cat.max_cost) || 0,
|
||||
cost_variance: Number(cat.cost_variance) || 0,
|
||||
total_spend: Number(cat.total_spend) || 0
|
||||
}))
|
||||
};
|
||||
|
||||
// Calculate aggregated stats if data exists
|
||||
if (analysis.length > 0) {
|
||||
parsedAnalysis.unique_products = analysis.reduce((sum, cat) => sum + Number(cat.unique_products || 0), 0);
|
||||
|
||||
// Calculate weighted average cost
|
||||
const totalProducts = parsedAnalysis.unique_products;
|
||||
if (totalProducts > 0) {
|
||||
parsedAnalysis.avg_cost = analysis.reduce((sum, cat) =>
|
||||
sum + (Number(cat.avg_cost || 0) * Number(cat.unique_products || 0)), 0) / totalProducts;
|
||||
}
|
||||
|
||||
// Find min and max across all categories
|
||||
parsedAnalysis.min_cost = Math.min(...analysis.map(cat => Number(cat.min_cost || 0)));
|
||||
parsedAnalysis.max_cost = Math.max(...analysis.map(cat => Number(cat.max_cost || 0)));
|
||||
|
||||
// Average variance
|
||||
parsedAnalysis.cost_variance = analysis.reduce((sum, cat) =>
|
||||
sum + Number(cat.cost_variance || 0), 0) / analysis.length;
|
||||
}
|
||||
|
||||
res.json(parsedAnalysis);
|
||||
} catch (error) {
|
||||
console.error('Error fetching cost analysis:', error);
|
||||
@@ -325,7 +356,7 @@ router.get('/receiving-status', async (req, res) => {
|
||||
try {
|
||||
const pool = req.app.locals.pool;
|
||||
|
||||
const [status] = await pool.query(`
|
||||
const { rows: status } = await pool.query(`
|
||||
WITH po_totals AS (
|
||||
SELECT
|
||||
po_id,
|
||||
@@ -333,7 +364,7 @@ router.get('/receiving-status', async (req, res) => {
|
||||
receiving_status,
|
||||
SUM(ordered) as total_ordered,
|
||||
SUM(received) as total_received,
|
||||
CAST(SUM(ordered * cost_price) AS DECIMAL(15,3)) as total_cost
|
||||
ROUND(SUM(ordered * cost_price)::numeric, 3) as total_cost
|
||||
FROM purchase_orders
|
||||
WHERE status != ${STATUS.CANCELED}
|
||||
GROUP BY po_id, status, receiving_status
|
||||
@@ -345,8 +376,8 @@ router.get('/receiving-status', async (req, res) => {
|
||||
ROUND(
|
||||
SUM(total_received) / NULLIF(SUM(total_ordered), 0), 3
|
||||
) as fulfillment_rate,
|
||||
CAST(SUM(total_cost) AS DECIMAL(15,3)) as total_value,
|
||||
CAST(AVG(total_cost) AS DECIMAL(15,3)) as avg_cost,
|
||||
ROUND(SUM(total_cost)::numeric, 3) as total_value,
|
||||
ROUND(AVG(total_cost)::numeric, 3) as avg_cost,
|
||||
COUNT(DISTINCT CASE
|
||||
WHEN receiving_status = ${RECEIVING_STATUS.CREATED} THEN po_id
|
||||
END) as pending_count,
|
||||
@@ -364,17 +395,17 @@ router.get('/receiving-status', async (req, res) => {
|
||||
|
||||
// Parse numeric values
|
||||
const parsedStatus = {
|
||||
order_count: Number(status[0].order_count) || 0,
|
||||
total_ordered: Number(status[0].total_ordered) || 0,
|
||||
total_received: Number(status[0].total_received) || 0,
|
||||
fulfillment_rate: Number(status[0].fulfillment_rate) || 0,
|
||||
total_value: Number(status[0].total_value) || 0,
|
||||
avg_cost: Number(status[0].avg_cost) || 0,
|
||||
order_count: Number(status[0]?.order_count) || 0,
|
||||
total_ordered: Number(status[0]?.total_ordered) || 0,
|
||||
total_received: Number(status[0]?.total_received) || 0,
|
||||
fulfillment_rate: Number(status[0]?.fulfillment_rate) || 0,
|
||||
total_value: Number(status[0]?.total_value) || 0,
|
||||
avg_cost: Number(status[0]?.avg_cost) || 0,
|
||||
status_breakdown: {
|
||||
pending: Number(status[0].pending_count) || 0,
|
||||
partial: Number(status[0].partial_count) || 0,
|
||||
completed: Number(status[0].completed_count) || 0,
|
||||
canceled: Number(status[0].canceled_count) || 0
|
||||
pending: Number(status[0]?.pending_count) || 0,
|
||||
partial: Number(status[0]?.partial_count) || 0,
|
||||
completed: Number(status[0]?.completed_count) || 0,
|
||||
canceled: Number(status[0]?.canceled_count) || 0
|
||||
}
|
||||
};
|
||||
|
||||
@@ -390,7 +421,7 @@ router.get('/order-vs-received', async (req, res) => {
|
||||
try {
|
||||
const pool = req.app.locals.pool;
|
||||
|
||||
const [quantities] = await pool.query(`
|
||||
const { rows: quantities } = await pool.query(`
|
||||
SELECT
|
||||
p.product_id,
|
||||
p.title as product,
|
||||
@@ -403,10 +434,10 @@ router.get('/order-vs-received', async (req, res) => {
|
||||
COUNT(DISTINCT po.po_id) as order_count
|
||||
FROM products p
|
||||
JOIN purchase_orders po ON p.product_id = po.product_id
|
||||
WHERE po.date >= DATE_SUB(CURDATE(), INTERVAL 90 DAY)
|
||||
WHERE po.date >= (CURRENT_DATE - INTERVAL '90 days')
|
||||
GROUP BY p.product_id, p.title, p.SKU
|
||||
HAVING order_count > 0
|
||||
ORDER BY ordered_quantity DESC
|
||||
HAVING COUNT(DISTINCT po.po_id) > 0
|
||||
ORDER BY SUM(po.ordered) DESC
|
||||
LIMIT 20
|
||||
`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user