Product editor tweaks

This commit is contained in:
2026-01-30 22:21:44 -05:00
parent 003e1ddd61
commit ac39257a51
195 changed files with 1233 additions and 66705 deletions

View File

@@ -1,24 +1,7 @@
const express = require('express');
const { DateTime } = require('luxon');
const router = express.Router();
const { getDbConnection, getPoolStatus } = require('../db/connection');
const {
getTimeRangeConditions,
formatBusinessDate,
getBusinessDayBounds,
_internal: timeHelpers
} = require('../utils/timeUtils');
const TIMEZONE = 'America/New_York';
const BUSINESS_DAY_START_HOUR = timeHelpers?.BUSINESS_DAY_START_HOUR ?? 1;
// Cherry Box order types to exclude when excludeCherryBox=true is passed
// 3 = cherrybox_subscription, 4 = cherrybox_sending, 5 = cherrybox_subscription_renew, 7 = cherrybox_refund
const EXCLUDED_ORDER_TYPES = [3, 4, 5, 7];
const getCherryBoxClause = (exclude) => exclude ? `order_type NOT IN (${EXCLUDED_ORDER_TYPES.join(', ')})` : '1=1';
const getCherryBoxClauseAliased = (alias, exclude) => exclude ? `${alias}.order_type NOT IN (${EXCLUDED_ORDER_TYPES.join(', ')})` : '1=1';
const parseBoolParam = (value) => value === 'true' || value === '1';
const { getTimeRangeConditions, formatBusinessDate, getBusinessDayBounds } = require('../utils/timeUtils');
// Image URL generation utility
const getImageUrls = (pid, iid = 1) => {
@@ -46,15 +29,14 @@ router.get('/stats', async (req, res) => {
try {
const mainOperation = async () => {
const { timeRange, startDate, endDate, excludeCherryBox } = req.query;
const excludeCB = parseBoolParam(excludeCherryBox);
console.log(`[STATS] Getting DB connection... (excludeCherryBox: ${excludeCB})`);
const { timeRange, startDate, endDate } = req.query;
console.log(`[STATS] Getting DB connection...`);
const { connection, release } = await getDbConnection();
console.log(`[STATS] DB connection obtained in ${Date.now() - startTime}ms`);
const { whereClause, params, dateRange } = getTimeRangeConditions(timeRange, startDate, endDate);
// Main order stats query (optionally excludes Cherry Box orders)
// Main order stats query
const mainStatsQuery = `
SELECT
COUNT(*) as orderCount,
@@ -69,32 +51,32 @@ router.get('/stats', async (req, res) => {
SUM(CASE WHEN order_status = 15 THEN 1 ELSE 0 END) as cancelledCount,
SUM(CASE WHEN order_status = 15 THEN summary_total ELSE 0 END) as cancelledTotal
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
`;
const [mainStats] = await connection.execute(mainStatsQuery, params);
const stats = mainStats[0];
// Refunds query (optionally excludes Cherry Box orders)
// Refunds query
const refundsQuery = `
SELECT
COUNT(*) as refundCount,
ABS(SUM(payment_amount)) as refundTotal
FROM order_payment op
JOIN _order o ON op.order_id = o.order_id
WHERE payment_amount < 0 AND o.order_status > 15 AND ${getCherryBoxClauseAliased('o', excludeCB)} AND ${whereClause.replace('date_placed', 'o.date_placed')}
WHERE payment_amount < 0 AND o.order_status > 15 AND ${whereClause.replace('date_placed', 'o.date_placed')}
`;
const [refundStats] = await connection.execute(refundsQuery, params);
// Best revenue day query (optionally excludes Cherry Box orders)
// Best revenue day query
const bestDayQuery = `
SELECT
DATE(date_placed) as date,
SUM(summary_total) as revenue,
COUNT(*) as orders
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
GROUP BY DATE(date_placed)
ORDER BY revenue DESC
LIMIT 1
@@ -102,7 +84,7 @@ router.get('/stats', async (req, res) => {
const [bestDayResult] = await connection.execute(bestDayQuery, params);
// Peak hour query (for single day periods, optionally excludes Cherry Box orders)
// Peak hour query (for single day periods)
let peakHour = null;
if (['today', 'yesterday'].includes(timeRange)) {
const peakHourQuery = `
@@ -110,7 +92,7 @@ router.get('/stats', async (req, res) => {
HOUR(date_placed) as hour,
COUNT(*) as count
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
GROUP BY HOUR(date_placed)
ORDER BY count DESC
LIMIT 1
@@ -130,7 +112,7 @@ router.get('/stats', async (req, res) => {
}
// Brands and categories query - simplified for now since we don't have the category tables
// We'll use a simple approach without company table for now (optionally excludes Cherry Box orders)
// We'll use a simple approach without company table for now
const brandsQuery = `
SELECT
'Various Brands' as brandName,
@@ -140,13 +122,13 @@ router.get('/stats', async (req, res) => {
FROM order_items oi
JOIN _order o ON oi.order_id = o.order_id
JOIN products p ON oi.prod_pid = p.pid
WHERE o.order_status > 15 AND ${getCherryBoxClauseAliased('o', excludeCB)} AND ${whereClause.replace('date_placed', 'o.date_placed')}
WHERE o.order_status > 15 AND ${whereClause.replace('date_placed', 'o.date_placed')}
HAVING revenue > 0
`;
const [brandsResult] = await connection.execute(brandsQuery, params);
// For categories, we'll use a simplified approach (optionally excludes Cherry Box orders)
// For categories, we'll use a simplified approach
const categoriesQuery = `
SELECT
'General' as categoryName,
@@ -156,13 +138,13 @@ router.get('/stats', async (req, res) => {
FROM order_items oi
JOIN _order o ON oi.order_id = o.order_id
JOIN products p ON oi.prod_pid = p.pid
WHERE o.order_status > 15 AND ${getCherryBoxClauseAliased('o', excludeCB)} AND ${whereClause.replace('date_placed', 'o.date_placed')}
WHERE o.order_status > 15 AND ${whereClause.replace('date_placed', 'o.date_placed')}
HAVING revenue > 0
`;
const [categoriesResult] = await connection.execute(categoriesQuery, params);
// Shipping locations query (optionally excludes Cherry Box orders)
// Shipping locations query
const shippingQuery = `
SELECT
ship_country,
@@ -170,7 +152,7 @@ router.get('/stats', async (req, res) => {
ship_method_selected,
COUNT(*) as count
FROM _order
WHERE order_status IN (100, 92) AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status IN (100, 92) AND ${whereClause}
GROUP BY ship_country, ship_state, ship_method_selected
`;
@@ -179,13 +161,13 @@ router.get('/stats', async (req, res) => {
// Process shipping data
const shippingStats = processShippingData(shippingResult, stats.shippedCount);
// Order value range query (optionally excludes Cherry Box orders)
// Order value range query
const orderRangeQuery = `
SELECT
MIN(summary_total) as smallest,
MAX(summary_total) as largest
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
`;
const [orderRangeResult] = await connection.execute(orderRangeQuery, params);
@@ -197,7 +179,7 @@ router.get('/stats', async (req, res) => {
}
// Previous period comparison data
const prevPeriodData = await getPreviousPeriodData(connection, timeRange, startDate, endDate, excludeCB);
const prevPeriodData = await getPreviousPeriodData(connection, timeRange, startDate, endDate);
const response = {
timeRange: dateRange,
@@ -324,14 +306,13 @@ router.get('/stats', async (req, res) => {
router.get('/stats/details', async (req, res) => {
let release;
try {
const { timeRange, startDate, endDate, metric, daily, excludeCherryBox } = req.query;
const excludeCB = parseBoolParam(excludeCherryBox);
const { timeRange, startDate, endDate, metric, daily } = req.query;
const { connection, release: releaseConn } = await getDbConnection();
release = releaseConn;
const { whereClause, params } = getTimeRangeConditions(timeRange, startDate, endDate);
// Daily breakdown query (optionally excludes Cherry Box orders)
// Daily breakdown query
const dailyQuery = `
SELECT
DATE(date_placed) as date,
@@ -340,7 +321,7 @@ router.get('/stats/details', async (req, res) => {
AVG(summary_total) as averageOrderValue,
SUM(stats_prod_pieces) as itemCount
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
GROUP BY DATE(date_placed)
ORDER BY DATE(date_placed)
`;
@@ -368,7 +349,7 @@ router.get('/stats/details', async (req, res) => {
prevParams = [prevStart.toISOString(), prevEnd.toISOString()];
}
// Get previous period daily data (optionally excludes Cherry Box orders)
// Get previous period daily data
const prevQuery = `
SELECT
DATE(date_placed) as date,
@@ -376,7 +357,7 @@ router.get('/stats/details', async (req, res) => {
SUM(summary_total) as prevRevenue,
AVG(summary_total) as prevAvgOrderValue
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${prevWhereClause}
WHERE order_status > 15 AND ${prevWhereClause}
GROUP BY DATE(date_placed)
`;
@@ -433,73 +414,35 @@ router.get('/stats/details', async (req, res) => {
router.get('/financials', async (req, res) => {
let release;
try {
const { timeRange, startDate, endDate, excludeCherryBox } = req.query;
const excludeCB = parseBoolParam(excludeCherryBox);
const { timeRange, startDate, endDate } = req.query;
const { connection, release: releaseConn } = await getDbConnection();
release = releaseConn;
const { whereClause, params, dateRange } = getTimeRangeConditions(timeRange, startDate, endDate);
const financialWhere = whereClause.replace(/date_placed/g, 'date_change');
const formatDebugBound = (value) => {
if (!value) return 'n/a';
const parsed = DateTime.fromSQL(value, { zone: 'UTC-05:00' });
if (!parsed.isValid) {
return `invalid(${value})`;
}
return parsed.setZone(TIMEZONE).toISO();
};
console.log('[FINANCIALS] request params', {
timeRange: timeRange || 'default',
startDate,
endDate,
whereClause: financialWhere,
params,
boundsEastern: Array.isArray(params) ? params.map(formatDebugBound) : [],
});
const financialWhere = whereClause.replace(/date_placed/g, 'DATE_SUB(date_change, INTERVAL 1 HOUR)');
const [totalsRows] = await connection.execute(
buildFinancialTotalsQuery(financialWhere, excludeCB),
buildFinancialTotalsQuery(financialWhere),
params
);
const totals = normalizeFinancialTotals(totalsRows[0]);
console.log('[FINANCIALS] totals query result', {
rows: totalsRows.length,
totals,
});
const [trendRows] = await connection.execute(
buildFinancialTrendQuery(financialWhere, excludeCB),
buildFinancialTrendQuery(financialWhere),
params
);
const trend = trendRows.map(normalizeFinancialTrendRow);
console.log('[FINANCIALS] trend query result', {
rows: trendRows.length,
first: trend[0] || null,
last: trend[trend.length - 1] || null,
});
let previousTotals = null;
let comparison = null;
const previousRange = getPreviousPeriodRange(timeRange, startDate, endDate);
if (previousRange) {
console.log('[FINANCIALS] previous range params', {
timeRange: timeRange || 'default',
prevWhere: previousRange.whereClause.replace(/date_placed/g, 'date_change'),
params: previousRange.params,
boundsEastern: Array.isArray(previousRange.params)
? previousRange.params.map(formatDebugBound)
: [],
});
const prevWhere = previousRange.whereClause.replace(/date_placed/g, 'date_change');
const prevWhere = previousRange.whereClause.replace(/date_placed/g, 'DATE_SUB(date_change, INTERVAL 1 HOUR)');
const [previousRows] = await connection.execute(
buildFinancialTotalsQuery(prevWhere, excludeCB),
buildFinancialTotalsQuery(prevWhere),
previousRange.params
);
previousTotals = normalizeFinancialTotals(previousRows[0]);
@@ -515,37 +458,12 @@ router.get('/financials', async (req, res) => {
};
}
const trendDebugSample = trend.slice(-3).map((item) => ({
date: item.date,
timestamp: item.timestamp,
income: item.income,
grossSales: item.grossSales,
}));
const debugInfo = {
serverTimeUtc: new Date().toISOString(),
timeRange: timeRange || 'default',
params,
boundsEastern: Array.isArray(params) ? params.map(formatDebugBound) : [],
trendCount: trend.length,
trendSample: trendDebugSample,
previousRange: previousRange
? {
params: previousRange.params,
boundsEastern: Array.isArray(previousRange.params)
? previousRange.params.map(formatDebugBound)
: [],
}
: null,
};
res.json({
dateRange,
totals,
previousTotals,
comparison,
trend,
debug: debugInfo,
});
} catch (error) {
console.error('Error in /financials:', error);
@@ -559,14 +477,12 @@ router.get('/financials', async (req, res) => {
router.get('/products', async (req, res) => {
let release;
try {
const { timeRange, startDate, endDate, excludeCherryBox } = req.query;
const excludeCB = parseBoolParam(excludeCherryBox);
const { timeRange, startDate, endDate } = req.query;
const { connection, release: releaseConn } = await getDbConnection();
release = releaseConn;
const { whereClause, params } = getTimeRangeConditions(timeRange, startDate, endDate);
// Products query (optionally excludes Cherry Box orders)
const productsQuery = `
SELECT
p.pid,
@@ -578,7 +494,7 @@ router.get('/products', async (req, res) => {
FROM order_items oi
JOIN _order o ON oi.order_id = o.order_id
JOIN products p ON oi.prod_pid = p.pid
WHERE o.order_status > 15 AND ${getCherryBoxClauseAliased('o', excludeCB)} AND ${whereClause.replace('date_placed', 'o.date_placed')}
WHERE o.order_status > 15 AND ${whereClause.replace('date_placed', 'o.date_placed')}
GROUP BY p.pid, p.description
ORDER BY totalRevenue DESC
LIMIT 500
@@ -621,8 +537,7 @@ router.get('/products', async (req, res) => {
router.get('/projection', async (req, res) => {
let release;
try {
const { timeRange, startDate, endDate, excludeCherryBox } = req.query;
const excludeCB = parseBoolParam(excludeCherryBox);
const { timeRange, startDate, endDate } = req.query;
// Only provide projections for incomplete periods
if (!['today', 'thisWeek', 'thisMonth'].includes(timeRange)) {
@@ -635,20 +550,19 @@ router.get('/projection', async (req, res) => {
// Get current period data
const { whereClause, params } = getTimeRangeConditions(timeRange, startDate, endDate);
// Current period query (optionally excludes Cherry Box orders)
const currentQuery = `
SELECT
SUM(summary_total) as currentRevenue,
COUNT(*) as currentOrders
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCB)} AND ${whereClause}
WHERE order_status > 15 AND ${whereClause}
`;
const [currentResult] = await connection.execute(currentQuery, params);
const current = currentResult[0];
// Get historical data for the same period type
const historicalQuery = await getHistoricalProjectionData(connection, timeRange, excludeCB);
const historicalQuery = await getHistoricalProjectionData(connection, timeRange);
// Calculate projection based on current progress and historical patterns
const periodProgress = calculatePeriodProgress(timeRange);
@@ -748,55 +662,47 @@ function processShippingData(shippingResult, totalShipped) {
}
function calculatePeriodProgress(timeRange) {
if (!['today', 'thisWeek', 'thisMonth'].includes(timeRange)) {
return 100;
const now = new Date();
const easternTime = new Date(now.getTime() - (5 * 60 * 60 * 1000)); // UTC-5
switch (timeRange) {
case 'today': {
const { start } = getBusinessDayBounds('today');
const businessStart = new Date(start);
const businessEnd = new Date(businessStart);
businessEnd.setDate(businessEnd.getDate() + 1);
businessEnd.setHours(0, 59, 59, 999); // 12:59 AM next day
const elapsed = easternTime.getTime() - businessStart.getTime();
const total = businessEnd.getTime() - businessStart.getTime();
return Math.min(100, Math.max(0, (elapsed / total) * 100));
}
case 'thisWeek': {
const startOfWeek = new Date(easternTime);
startOfWeek.setDate(easternTime.getDate() - easternTime.getDay()); // Sunday
startOfWeek.setHours(1, 0, 0, 0); // 1 AM business day start
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(endOfWeek.getDate() + 7);
const elapsed = easternTime.getTime() - startOfWeek.getTime();
const total = endOfWeek.getTime() - startOfWeek.getTime();
return Math.min(100, Math.max(0, (elapsed / total) * 100));
}
case 'thisMonth': {
const startOfMonth = new Date(easternTime.getFullYear(), easternTime.getMonth(), 1, 1, 0, 0, 0);
const endOfMonth = new Date(easternTime.getFullYear(), easternTime.getMonth() + 1, 1, 0, 59, 59, 999);
const elapsed = easternTime.getTime() - startOfMonth.getTime();
const total = endOfMonth.getTime() - startOfMonth.getTime();
return Math.min(100, Math.max(0, (elapsed / total) * 100));
}
default:
return 100;
}
const now = DateTime.now().setZone(TIMEZONE);
let range;
try {
range = timeHelpers.getRangeForTimeRange(timeRange, now);
} catch (error) {
console.error(`[STATS] Failed to derive range for ${timeRange}:`, error);
return 100;
}
if (!range?.start || !range?.end) {
return 100;
}
const total = range.end.toMillis() - range.start.toMillis();
if (total <= 0) {
return 100;
}
const elapsed = Math.min(
Math.max(now.toMillis() - range.start.toMillis(), 0),
total
);
return Math.min(100, Math.max(0, (elapsed / total) * 100));
}
function buildFinancialTotalsQuery(whereClause, excludeCherryBox = false) {
// Optionally join to _order to exclude Cherry Box orders
if (excludeCherryBox) {
return `
SELECT
COALESCE(SUM(r.sale_amount), 0) as grossSales,
COALESCE(SUM(r.refund_amount), 0) as refunds,
COALESCE(SUM(r.shipping_collected_amount + r.small_order_fee_amount + r.rush_fee_amount), 0) as shippingFees,
COALESCE(SUM(r.tax_collected_amount), 0) as taxCollected,
COALESCE(SUM(r.discount_total_amount), 0) as discounts,
COALESCE(SUM(r.cogs_amount), 0) as cogs
FROM report_sales_data r
JOIN _order o ON r.order_id = o.order_id
WHERE ${whereClause.replace(/date_change/g, 'r.date_change')}
AND r.action IN (1, 2, 3)
AND ${getCherryBoxClauseAliased('o', true)}
`;
}
function buildFinancialTotalsQuery(whereClause) {
return `
SELECT
COALESCE(SUM(sale_amount), 0) as grossSales,
@@ -811,37 +717,10 @@ function buildFinancialTotalsQuery(whereClause, excludeCherryBox = false) {
`;
}
function buildFinancialTrendQuery(whereClause, excludeCherryBox = false) {
const businessDayOffset = BUSINESS_DAY_START_HOUR;
// Optionally join to _order to exclude Cherry Box orders
if (excludeCherryBox) {
return `
SELECT
DATE_FORMAT(
DATE_SUB(r.date_change, INTERVAL ${businessDayOffset} HOUR),
'%Y-%m-%d'
) as businessDate,
SUM(r.sale_amount) as grossSales,
SUM(r.refund_amount) as refunds,
SUM(r.shipping_collected_amount + r.small_order_fee_amount + r.rush_fee_amount) as shippingFees,
SUM(r.tax_collected_amount) as taxCollected,
SUM(r.discount_total_amount) as discounts,
SUM(r.cogs_amount) as cogs
FROM report_sales_data r
JOIN _order o ON r.order_id = o.order_id
WHERE ${whereClause.replace(/date_change/g, 'r.date_change')}
AND r.action IN (1, 2, 3)
AND ${getCherryBoxClauseAliased('o', true)}
GROUP BY businessDate
ORDER BY businessDate ASC
`;
}
function buildFinancialTrendQuery(whereClause) {
return `
SELECT
DATE_FORMAT(
DATE_SUB(date_change, INTERVAL ${businessDayOffset} HOUR),
'%Y-%m-%d'
) as businessDate,
DATE(DATE_SUB(date_change, INTERVAL 1 HOUR)) as date,
SUM(sale_amount) as grossSales,
SUM(refund_amount) as refunds,
SUM(shipping_collected_amount + small_order_fee_amount + rush_fee_amount) as shippingFees,
@@ -851,8 +730,8 @@ function buildFinancialTrendQuery(whereClause, excludeCherryBox = false) {
FROM report_sales_data
WHERE ${whereClause}
AND action IN (1, 2, 3)
GROUP BY businessDate
ORDER BY businessDate ASC
GROUP BY DATE(DATE_SUB(date_change, INTERVAL 1 HOUR))
ORDER BY date ASC
`;
}
@@ -893,44 +772,16 @@ function normalizeFinancialTrendRow(row = {}) {
const profit = income - cogs;
const margin = income !== 0 ? (profit / income) * 100 : 0;
let timestamp = null;
let dateValue = row.businessDate || row.date || null;
let dateValue = null;
const resolveBusinessDayStart = (value) => {
if (!value) {
return null;
}
let dt;
if (value instanceof Date) {
dt = DateTime.fromJSDate(value, { zone: TIMEZONE });
} else if (typeof value === 'string') {
dt = DateTime.fromISO(value, { zone: TIMEZONE });
if (!dt.isValid) {
dt = DateTime.fromSQL(value, { zone: TIMEZONE });
}
}
if (!dt || !dt.isValid) {
return null;
}
const hour = BUSINESS_DAY_START_HOUR;
return dt.set({
hour,
minute: 0,
second: 0,
millisecond: 0,
});
};
const businessDayStart = resolveBusinessDayStart(dateValue);
if (businessDayStart) {
timestamp = businessDayStart.toUTC().toISO();
dateValue = businessDayStart.toISO();
} else if (row.date instanceof Date) {
timestamp = new Date(row.date.getTime()).toISOString();
if (row.date instanceof Date) {
dateValue = row.date.toISOString().slice(0, 10);
} else if (typeof row.date === 'string') {
timestamp = new Date(`${row.date}T00:00:00Z`).toISOString();
dateValue = row.date;
}
if (typeof dateValue === 'string') {
timestamp = new Date(`${dateValue}T06:00:00.000Z`).toISOString();
}
return {
@@ -994,7 +845,7 @@ function getPreviousPeriodRange(timeRange, startDate, endDate) {
return getTimeRangeConditions('custom', prevStart.toISOString(), prevEnd.toISOString());
}
async function getPreviousPeriodData(connection, timeRange, startDate, endDate, excludeCherryBox = false) {
async function getPreviousPeriodData(connection, timeRange, startDate, endDate) {
// Calculate previous period dates
let prevWhereClause, prevParams;
@@ -1016,14 +867,13 @@ async function getPreviousPeriodData(connection, timeRange, startDate, endDate,
prevParams = [prevStart.toISOString(), prevEnd.toISOString()];
}
// Previous period query (optionally excludes Cherry Box orders)
const prevQuery = `
SELECT
COUNT(*) as orderCount,
SUM(summary_total) as revenue,
AVG(summary_total) as averageOrderValue
FROM _order
WHERE order_status > 15 AND ${getCherryBoxClause(excludeCherryBox)} AND ${prevWhereClause}
WHERE order_status > 15 AND ${prevWhereClause}
`;
const [prevResult] = await connection.execute(prevQuery, prevParams);
@@ -1049,8 +899,8 @@ function getPreviousTimeRange(timeRange) {
return map[timeRange] || timeRange;
}
async function getHistoricalProjectionData(connection, timeRange, excludeCherryBox = false) {
// Get historical data for projection calculations (optionally excludes Cherry Box orders)
async function getHistoricalProjectionData(connection, timeRange) {
// Get historical data for projection calculations
// This is a simplified version - you could make this more sophisticated
const historicalQuery = `
SELECT
@@ -1058,7 +908,6 @@ async function getHistoricalProjectionData(connection, timeRange, excludeCherryB
COUNT(*) as orders
FROM _order
WHERE order_status > 15
AND ${getCherryBoxClause(excludeCherryBox)}
AND date_placed >= DATE_SUB(NOW(), INTERVAL 30 DAY)
AND date_placed < DATE_SUB(NOW(), INTERVAL 1 DAY)
`;