Merge branch 'master' into add-product-upload-page

This commit is contained in:
2025-02-23 15:40:54 -05:00
parent 3f16413769
commit f628774267
47 changed files with 4674 additions and 3199 deletions

View File

@@ -20,39 +20,46 @@ router.get('/', async (req, res) => {
// Build the WHERE clause
const conditions = ['o1.canceled = false'];
const params = [];
let paramCounter = 1;
if (search) {
conditions.push('(o1.order_number LIKE ? OR o1.customer LIKE ?)');
params.push(`%${search}%`, `%${search}%`);
conditions.push(`(o1.order_number ILIKE $${paramCounter} OR o1.customer ILIKE $${paramCounter})`);
params.push(`%${search}%`);
paramCounter++;
}
if (status !== 'all') {
conditions.push('o1.status = ?');
conditions.push(`o1.status = $${paramCounter}`);
params.push(status);
paramCounter++;
}
if (fromDate) {
conditions.push('DATE(o1.date) >= DATE(?)');
conditions.push(`DATE(o1.date) >= DATE($${paramCounter})`);
params.push(fromDate.toISOString());
paramCounter++;
}
if (toDate) {
conditions.push('DATE(o1.date) <= DATE(?)');
conditions.push(`DATE(o1.date) <= DATE($${paramCounter})`);
params.push(toDate.toISOString());
paramCounter++;
}
if (minAmount > 0) {
conditions.push('total_amount >= ?');
conditions.push(`total_amount >= $${paramCounter}`);
params.push(minAmount);
paramCounter++;
}
if (maxAmount) {
conditions.push('total_amount <= ?');
conditions.push(`total_amount <= $${paramCounter}`);
params.push(maxAmount);
paramCounter++;
}
// Get total count for pagination
const [countResult] = await pool.query(`
const { rows: [countResult] } = await pool.query(`
SELECT COUNT(DISTINCT o1.order_number) as total
FROM orders o1
LEFT JOIN (
@@ -63,7 +70,7 @@ router.get('/', async (req, res) => {
WHERE ${conditions.join(' AND ')}
`, params);
const total = countResult[0].total;
const total = countResult.total;
// Get paginated results
const query = `
@@ -75,7 +82,7 @@ router.get('/', async (req, res) => {
o1.payment_method,
o1.shipping_method,
COUNT(o2.pid) as items_count,
CAST(SUM(o2.price * o2.quantity) AS DECIMAL(15,3)) as total_amount
ROUND(SUM(o2.price * o2.quantity)::numeric, 3) as total_amount
FROM orders o1
JOIN orders o2 ON o1.order_number = o2.order_number
WHERE ${conditions.join(' AND ')}
@@ -91,36 +98,37 @@ router.get('/', async (req, res) => {
? `${sortColumn} ${sortDirection}`
: `o1.${sortColumn} ${sortDirection}`
}
LIMIT ? OFFSET ?
LIMIT $${paramCounter} OFFSET $${paramCounter + 1}
`;
const [rows] = await pool.query(query, [...params, limit, offset]);
params.push(limit, offset);
const { rows } = await pool.query(query, params);
// Get order statistics
const [stats] = await pool.query(`
const { rows: [orderStats] } = await pool.query(`
WITH CurrentStats AS (
SELECT
COUNT(DISTINCT order_number) as total_orders,
CAST(SUM(price * quantity) AS DECIMAL(15,3)) as total_revenue
ROUND(SUM(price * quantity)::numeric, 3) as total_revenue
FROM orders
WHERE canceled = false
AND DATE(date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND DATE(date) >= CURRENT_DATE - INTERVAL '30 days'
),
PreviousStats AS (
SELECT
COUNT(DISTINCT order_number) as prev_orders,
CAST(SUM(price * quantity) AS DECIMAL(15,3)) as prev_revenue
ROUND(SUM(price * quantity)::numeric, 3) as prev_revenue
FROM orders
WHERE canceled = false
AND DATE(date) BETWEEN DATE_SUB(CURDATE(), INTERVAL 60 DAY) AND DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND DATE(date) BETWEEN CURRENT_DATE - INTERVAL '60 days' AND CURRENT_DATE - INTERVAL '30 days'
),
OrderValues AS (
SELECT
order_number,
CAST(SUM(price * quantity) AS DECIMAL(15,3)) as order_value
ROUND(SUM(price * quantity)::numeric, 3) as order_value
FROM orders
WHERE canceled = false
AND DATE(date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
AND DATE(date) >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY order_number
)
SELECT
@@ -128,29 +136,27 @@ router.get('/', async (req, res) => {
cs.total_revenue,
CASE
WHEN ps.prev_orders > 0
THEN ((cs.total_orders - ps.prev_orders) / ps.prev_orders * 100)
THEN ROUND(((cs.total_orders - ps.prev_orders)::numeric / ps.prev_orders * 100), 1)
ELSE 0
END as order_growth,
CASE
WHEN ps.prev_revenue > 0
THEN ((cs.total_revenue - ps.prev_revenue) / ps.prev_revenue * 100)
THEN ROUND(((cs.total_revenue - ps.prev_revenue)::numeric / ps.prev_revenue * 100), 1)
ELSE 0
END as revenue_growth,
CASE
WHEN cs.total_orders > 0
THEN CAST((cs.total_revenue / cs.total_orders) AS DECIMAL(15,3))
THEN ROUND((cs.total_revenue::numeric / cs.total_orders), 3)
ELSE 0
END as average_order_value,
CASE
WHEN ps.prev_orders > 0
THEN CAST((ps.prev_revenue / ps.prev_orders) AS DECIMAL(15,3))
THEN ROUND((ps.prev_revenue::numeric / ps.prev_orders), 3)
ELSE 0
END as prev_average_order_value
FROM CurrentStats cs
CROSS JOIN PreviousStats ps
`);
const orderStats = stats[0];
res.json({
orders: rows.map(row => ({
@@ -189,7 +195,7 @@ router.get('/:orderNumber', async (req, res) => {
const pool = req.app.locals.pool;
try {
// Get order details
const [orderRows] = await pool.query(`
const { rows: orderRows } = await pool.query(`
SELECT DISTINCT
o1.order_number,
o1.customer,
@@ -200,10 +206,10 @@ router.get('/:orderNumber', async (req, res) => {
o1.shipping_address,
o1.billing_address,
COUNT(o2.pid) as items_count,
CAST(SUM(o2.price * o2.quantity) AS DECIMAL(15,3)) as total_amount
ROUND(SUM(o2.price * o2.quantity)::numeric, 3) as total_amount
FROM orders o1
JOIN orders o2 ON o1.order_number = o2.order_number
WHERE o1.order_number = ? AND o1.canceled = false
WHERE o1.order_number = $1 AND o1.canceled = false
GROUP BY
o1.order_number,
o1.customer,
@@ -220,17 +226,17 @@ router.get('/:orderNumber', async (req, res) => {
}
// Get order items
const [itemRows] = await pool.query(`
const { rows: itemRows } = await pool.query(`
SELECT
o.pid,
p.title,
p.SKU,
o.quantity,
o.price,
CAST((o.price * o.quantity) AS DECIMAL(15,3)) as total
ROUND((o.price * o.quantity)::numeric, 3) as total
FROM orders o
JOIN products p ON o.pid = p.pid
WHERE o.order_number = ? AND o.canceled = false
WHERE o.order_number = $1 AND o.canceled = false
`, [req.params.orderNumber]);
const order = {