const express = require('express'); const router = express.Router(); // Get all orders with pagination, filtering, and sorting router.get('/', async (req, res) => { const pool = req.app.locals.pool; try { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 50; const offset = (page - 1) * limit; const search = req.query.search || ''; const status = req.query.status || 'all'; const fromDate = req.query.fromDate ? new Date(req.query.fromDate) : null; const toDate = req.query.toDate ? new Date(req.query.toDate) : null; const minAmount = parseFloat(req.query.minAmount) || 0; const maxAmount = req.query.maxAmount ? parseFloat(req.query.maxAmount) : null; const sortColumn = req.query.sortColumn || 'date'; const sortDirection = req.query.sortDirection === 'desc' ? 'DESC' : 'ASC'; // Build the WHERE clause const conditions = ['o1.canceled = false']; const params = []; if (search) { conditions.push('(o1.order_number LIKE ? OR o1.customer LIKE ?)'); params.push(`%${search}%`, `%${search}%`); } if (status !== 'all') { conditions.push('o1.status = ?'); params.push(status); } if (fromDate) { conditions.push('DATE(o1.date) >= DATE(?)'); params.push(fromDate.toISOString()); } if (toDate) { conditions.push('DATE(o1.date) <= DATE(?)'); params.push(toDate.toISOString()); } if (minAmount > 0) { conditions.push('total_amount >= ?'); params.push(minAmount); } if (maxAmount) { conditions.push('total_amount <= ?'); params.push(maxAmount); } // Get total count for pagination const [countResult] = await pool.query(` SELECT COUNT(DISTINCT o1.order_number) as total FROM orders o1 LEFT JOIN ( SELECT order_number, SUM(price * quantity) as total_amount FROM orders GROUP BY order_number ) totals ON o1.order_number = totals.order_number WHERE ${conditions.join(' AND ')} `, params); const total = countResult[0].total; // Get paginated results const query = ` SELECT o1.order_number, o1.customer, o1.date, o1.status, 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 FROM orders o1 JOIN orders o2 ON o1.order_number = o2.order_number WHERE ${conditions.join(' AND ')} GROUP BY o1.order_number, o1.customer, o1.date, o1.status, o1.payment_method, o1.shipping_method ORDER BY ${ sortColumn === 'items_count' || sortColumn === 'total_amount' ? `${sortColumn} ${sortDirection}` : `o1.${sortColumn} ${sortDirection}` } LIMIT ? OFFSET ? `; const [rows] = await pool.query(query, [...params, limit, offset]); // Get order statistics const [stats] = 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 FROM orders WHERE canceled = false AND DATE(date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) ), PreviousStats AS ( SELECT COUNT(DISTINCT order_number) as prev_orders, CAST(SUM(price * quantity) AS DECIMAL(15,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) ), OrderValues AS ( SELECT order_number, CAST(SUM(price * quantity) AS DECIMAL(15,3)) as order_value FROM orders WHERE canceled = false AND DATE(date) >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY order_number ) SELECT cs.total_orders, cs.total_revenue, CASE WHEN ps.prev_orders > 0 THEN ((cs.total_orders - ps.prev_orders) / ps.prev_orders * 100) ELSE 0 END as order_growth, CASE WHEN ps.prev_revenue > 0 THEN ((cs.total_revenue - ps.prev_revenue) / ps.prev_revenue * 100) ELSE 0 END as revenue_growth, CASE WHEN cs.total_orders > 0 THEN CAST((cs.total_revenue / cs.total_orders) AS DECIMAL(15,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)) 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 => ({ ...row, total_amount: parseFloat(row.total_amount) || 0, items_count: parseInt(row.items_count) || 0, date: row.date })), pagination: { total, pages: Math.ceil(total / limit), currentPage: page, limit }, stats: { totalOrders: parseInt(orderStats.total_orders) || 0, totalRevenue: parseFloat(orderStats.total_revenue) || 0, orderGrowth: parseFloat(orderStats.order_growth) || 0, revenueGrowth: parseFloat(orderStats.revenue_growth) || 0, averageOrderValue: parseFloat(orderStats.average_order_value) || 0, aovGrowth: orderStats.prev_average_order_value > 0 ? ((orderStats.average_order_value - orderStats.prev_average_order_value) / orderStats.prev_average_order_value * 100) : 0, conversionRate: 2.5, // Placeholder - would need actual visitor data conversionGrowth: 0.5 // Placeholder - would need actual visitor data } }); } catch (error) { console.error('Error fetching orders:', error); res.status(500).json({ error: 'Failed to fetch orders' }); } }); // Get a single order with its items router.get('/:orderNumber', async (req, res) => { const pool = req.app.locals.pool; try { // Get order details const [orderRows] = await pool.query(` SELECT DISTINCT o1.order_number, o1.customer, o1.date, o1.status, o1.payment_method, o1.shipping_method, 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 FROM orders o1 JOIN orders o2 ON o1.order_number = o2.order_number WHERE o1.order_number = ? AND o1.canceled = false GROUP BY o1.order_number, o1.customer, o1.date, o1.status, o1.payment_method, o1.shipping_method, o1.shipping_address, o1.billing_address `, [req.params.orderNumber]); if (orderRows.length === 0) { return res.status(404).json({ error: 'Order not found' }); } // Get order items const [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 FROM orders o JOIN products p ON o.pid = p.pid WHERE o.order_number = ? AND o.canceled = false `, [req.params.orderNumber]); const order = { ...orderRows[0], total_amount: parseFloat(orderRows[0].total_amount) || 0, items_count: parseInt(orderRows[0].items_count) || 0, items: itemRows.map(item => ({ ...item, price: parseFloat(item.price) || 0, total: parseFloat(item.total) || 0, quantity: parseInt(item.quantity) || 0 })) }; res.json(order); } catch (error) { console.error('Error fetching order:', error); res.status(500).json({ error: 'Failed to fetch order' }); } }); module.exports = router;