Fix time periods on financial overview, remove some logging

This commit is contained in:
2025-09-21 23:47:05 -04:00
parent 5d46a2a7e5
commit 2ff325a132
18 changed files with 426 additions and 445 deletions

View File

@@ -12,6 +12,7 @@
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.18.2", "express": "^4.18.2",
"luxon": "^3.5.0",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"mysql2": "^3.6.5", "mysql2": "^3.6.5",
"ssh2": "^1.14.0" "ssh2": "^1.14.0"
@@ -826,6 +827,15 @@
"url": "https://github.com/sponsors/wellwelwel" "url": "https://github.com/sponsors/wellwelwel"
} }
}, },
"node_modules/luxon": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz",
"integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==",
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",

View File

@@ -14,7 +14,8 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"ssh2": "^1.14.0", "ssh2": "^1.14.0",
"mysql2": "^3.6.5", "mysql2": "^3.6.5",
"compression": "^1.7.4" "compression": "^1.7.4",
"luxon": "^3.5.0"
}, },
"devDependencies": { "devDependencies": {
"nodemon": "^3.0.1" "nodemon": "^3.0.1"

View File

@@ -1,7 +1,17 @@
const express = require('express'); const express = require('express');
const { DateTime } = require('luxon');
const router = express.Router(); const router = express.Router();
const { getDbConnection, getPoolStatus } = require('../db/connection'); const { getDbConnection, getPoolStatus } = require('../db/connection');
const { getTimeRangeConditions, formatBusinessDate, getBusinessDayBounds } = require('../utils/timeUtils'); 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;
// Image URL generation utility // Image URL generation utility
const getImageUrls = (pid, iid = 1) => { const getImageUrls = (pid, iid = 1) => {
@@ -421,6 +431,24 @@ router.get('/financials', async (req, res) => {
const { whereClause, params, dateRange } = getTimeRangeConditions(timeRange, startDate, endDate); const { whereClause, params, dateRange } = getTimeRangeConditions(timeRange, startDate, endDate);
const financialWhere = whereClause.replace(/date_placed/g, 'date_change'); 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 [totalsRows] = await connection.execute( const [totalsRows] = await connection.execute(
buildFinancialTotalsQuery(financialWhere), buildFinancialTotalsQuery(financialWhere),
params params
@@ -428,6 +456,11 @@ router.get('/financials', async (req, res) => {
const totals = normalizeFinancialTotals(totalsRows[0]); const totals = normalizeFinancialTotals(totalsRows[0]);
console.log('[FINANCIALS] totals query result', {
rows: totalsRows.length,
totals,
});
const [trendRows] = await connection.execute( const [trendRows] = await connection.execute(
buildFinancialTrendQuery(financialWhere), buildFinancialTrendQuery(financialWhere),
params params
@@ -435,11 +468,25 @@ router.get('/financials', async (req, res) => {
const trend = trendRows.map(normalizeFinancialTrendRow); 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 previousTotals = null;
let comparison = null; let comparison = null;
const previousRange = getPreviousPeriodRange(timeRange, startDate, endDate); const previousRange = getPreviousPeriodRange(timeRange, startDate, endDate);
if (previousRange) { 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_change');
const [previousRows] = await connection.execute( const [previousRows] = await connection.execute(
buildFinancialTotalsQuery(prevWhere), buildFinancialTotalsQuery(prevWhere),
@@ -458,12 +505,37 @@ 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({ res.json({
dateRange, dateRange,
totals, totals,
previousTotals, previousTotals,
comparison, comparison,
trend, trend,
debug: debugInfo,
}); });
} catch (error) { } catch (error) {
console.error('Error in /financials:', error); console.error('Error in /financials:', error);
@@ -662,44 +734,35 @@ function processShippingData(shippingResult, totalShipped) {
} }
function calculatePeriodProgress(timeRange) { function calculatePeriodProgress(timeRange) {
const now = new Date(); if (!['today', 'thisWeek', 'thisMonth'].includes(timeRange)) {
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; 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) { function buildFinancialTotalsQuery(whereClause) {
@@ -718,9 +781,13 @@ function buildFinancialTotalsQuery(whereClause) {
} }
function buildFinancialTrendQuery(whereClause) { function buildFinancialTrendQuery(whereClause) {
const businessDayOffset = BUSINESS_DAY_START_HOUR;
return ` return `
SELECT SELECT
DATE(date_change) as date, DATE_FORMAT(
DATE_SUB(date_change, INTERVAL ${businessDayOffset} HOUR),
'%Y-%m-%d'
) as businessDate,
SUM(sale_amount) as grossSales, SUM(sale_amount) as grossSales,
SUM(refund_amount) as refunds, SUM(refund_amount) as refunds,
SUM(shipping_collected_amount + small_order_fee_amount + rush_fee_amount) as shippingFees, SUM(shipping_collected_amount + small_order_fee_amount + rush_fee_amount) as shippingFees,
@@ -730,8 +797,8 @@ function buildFinancialTrendQuery(whereClause) {
FROM report_sales_data FROM report_sales_data
WHERE ${whereClause} WHERE ${whereClause}
AND action IN (1, 2, 3) AND action IN (1, 2, 3)
GROUP BY DATE(date_change) GROUP BY businessDate
ORDER BY date ASC ORDER BY businessDate ASC
`; `;
} }
@@ -772,15 +839,48 @@ function normalizeFinancialTrendRow(row = {}) {
const profit = income - cogs; const profit = income - cogs;
const margin = income !== 0 ? (profit / income) * 100 : 0; const margin = income !== 0 ? (profit / income) * 100 : 0;
let timestamp = null; let timestamp = null;
let dateValue = row.businessDate || row.date || null;
if (row.date instanceof Date) { 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(); timestamp = new Date(row.date.getTime()).toISOString();
} else if (typeof row.date === 'string') { } else if (typeof row.date === 'string') {
timestamp = new Date(`${row.date}T00:00:00Z`).toISOString(); timestamp = new Date(`${row.date}T00:00:00Z`).toISOString();
} }
return { return {
date: row.date, date: dateValue,
grossSales, grossSales,
refunds, refunds,
shippingFees, shippingFees,

View File

@@ -1,217 +1,219 @@
// Time utilities for handling business day logic and time ranges const { DateTime } = require('luxon');
// Business day is 1am-12:59am Eastern time (UTC-5)
const getBusinessDayBounds = (timeRange) => { const TIMEZONE = 'America/New_York';
const now = new Date(); const DB_TIMEZONE = 'UTC-05:00';
const easternTime = new Date(now.getTime() - (5 * 60 * 60 * 1000)); // UTC-5 const BUSINESS_DAY_START_HOUR = 1; // 1 AM Eastern
const WEEK_START_DAY = 7; // Sunday (Luxon uses 1 = Monday, 7 = Sunday)
const DB_DATETIME_FORMAT = 'yyyy-LL-dd HH:mm:ss';
const isDateTime = (value) => DateTime.isDateTime(value);
const ensureDateTime = (value, { zone = TIMEZONE } = {}) => {
if (!value) return null;
if (isDateTime(value)) {
return value.setZone(zone);
}
if (value instanceof Date) {
return DateTime.fromJSDate(value, { zone });
}
if (typeof value === 'number') {
return DateTime.fromMillis(value, { zone });
}
if (typeof value === 'string') {
let dt = DateTime.fromISO(value, { zone, setZone: true });
if (!dt.isValid) {
dt = DateTime.fromSQL(value, { zone });
}
return dt.isValid ? dt : null;
}
return null;
};
const getNow = () => DateTime.now().setZone(TIMEZONE);
const getDayStart = (input = getNow()) => {
const dt = ensureDateTime(input);
if (!dt || !dt.isValid) {
const fallback = getNow();
return fallback.set({
hour: BUSINESS_DAY_START_HOUR,
minute: 0,
second: 0,
millisecond: 0
});
}
const sameDayStart = dt.set({
hour: BUSINESS_DAY_START_HOUR,
minute: 0,
second: 0,
millisecond: 0
});
return dt.hour < BUSINESS_DAY_START_HOUR
? sameDayStart.minus({ days: 1 })
: sameDayStart;
};
const getDayEnd = (input = getNow()) => {
return getDayStart(input).plus({ days: 1 }).minus({ milliseconds: 1 });
};
const getWeekStart = (input = getNow()) => {
const dt = ensureDateTime(input);
if (!dt || !dt.isValid) {
return getDayStart();
}
const startOfWeek = dt.set({ weekday: WEEK_START_DAY }).startOf('day');
const normalized = startOfWeek > dt ? startOfWeek.minus({ weeks: 1 }) : startOfWeek;
return normalized.set({
hour: BUSINESS_DAY_START_HOUR,
minute: 0,
second: 0,
millisecond: 0
});
};
const getRangeForTimeRange = (timeRange = 'today', now = getNow()) => {
const current = ensureDateTime(now);
if (!current || !current.isValid) {
throw new Error('Invalid reference time for range calculation');
}
switch (timeRange) { switch (timeRange) {
case 'today': { case 'today': {
const start = new Date(easternTime); return {
start.setHours(1, 0, 0, 0); // 1 AM start of business day start: getDayStart(current),
end: getDayEnd(current)
const end = new Date(start); };
end.setDate(end.getDate() + 1);
end.setHours(0, 59, 59, 999); // 12:59 AM next day
return { start, end };
} }
case 'yesterday': { case 'yesterday': {
const start = new Date(easternTime); const target = current.minus({ days: 1 });
start.setDate(start.getDate() - 1); return {
start.setHours(1, 0, 0, 0); start: getDayStart(target),
end: getDayEnd(target)
const end = new Date(start); };
end.setDate(end.getDate() + 1);
end.setHours(0, 59, 59, 999);
return { start, end };
} }
case 'thisWeek': {
const start = new Date(easternTime);
start.setDate(easternTime.getDate() - easternTime.getDay()); // Sunday
start.setHours(1, 0, 0, 0);
const end = new Date(easternTime);
end.setDate(end.getDate() + 1);
end.setHours(0, 59, 59, 999);
return { start, end };
}
case 'lastWeek': {
const start = new Date(easternTime);
start.setDate(easternTime.getDate() - easternTime.getDay() - 7); // Previous Sunday
start.setHours(1, 0, 0, 0);
const end = new Date(start);
end.setDate(end.getDate() + 7);
end.setHours(0, 59, 59, 999);
return { start, end };
}
case 'thisMonth': {
const start = new Date(easternTime.getFullYear(), easternTime.getMonth(), 1, 1, 0, 0, 0);
const end = new Date(easternTime);
end.setDate(end.getDate() + 1);
end.setHours(0, 59, 59, 999);
return { start, end };
}
case 'lastMonth': {
const start = new Date(easternTime.getFullYear(), easternTime.getMonth() - 1, 1, 1, 0, 0, 0);
const end = new Date(easternTime.getFullYear(), easternTime.getMonth(), 1, 0, 59, 59, 999);
return { start, end };
}
case 'last7days': {
const end = new Date(easternTime);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 7);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'last30days': {
const end = new Date(easternTime);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 30);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'last90days': {
const end = new Date(easternTime);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 90);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'previous7days': {
const end = new Date(easternTime);
end.setDate(end.getDate() - 1);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 6);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'previous30days': {
const end = new Date(easternTime);
end.setDate(end.getDate() - 1);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 29);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'previous90days': {
const end = new Date(easternTime);
end.setDate(end.getDate() - 1);
end.setHours(0, 59, 59, 999);
const start = new Date(end);
start.setDate(start.getDate() - 89);
start.setHours(1, 0, 0, 0);
return { start, end };
}
case 'twoDaysAgo': { case 'twoDaysAgo': {
const start = new Date(easternTime); const target = current.minus({ days: 2 });
start.setDate(start.getDate() - 2); return {
start.setHours(1, 0, 0, 0); start: getDayStart(target),
end: getDayEnd(target)
const end = new Date(start); };
end.setDate(end.getDate() + 1); }
end.setHours(0, 59, 59, 999); case 'thisWeek': {
return {
return { start, end }; start: getWeekStart(current),
end: getDayEnd(current)
};
}
case 'lastWeek': {
const lastWeek = current.minus({ weeks: 1 });
const weekStart = getWeekStart(lastWeek);
const weekEnd = weekStart.plus({ days: 6 });
return {
start: weekStart,
end: getDayEnd(weekEnd)
};
}
case 'thisMonth': {
const dayStart = getDayStart(current);
const monthStart = dayStart.startOf('month').set({ hour: BUSINESS_DAY_START_HOUR });
return {
start: monthStart,
end: getDayEnd(current)
};
}
case 'lastMonth': {
const lastMonth = current.minus({ months: 1 });
const monthStart = lastMonth
.startOf('month')
.set({ hour: BUSINESS_DAY_START_HOUR, minute: 0, second: 0, millisecond: 0 });
const monthEnd = monthStart.plus({ months: 1 }).minus({ days: 1 });
return {
start: monthStart,
end: getDayEnd(monthEnd)
};
}
case 'last7days': {
const dayStart = getDayStart(current);
return {
start: dayStart.minus({ days: 6 }),
end: getDayEnd(current)
};
}
case 'last30days': {
const dayStart = getDayStart(current);
return {
start: dayStart.minus({ days: 29 }),
end: getDayEnd(current)
};
}
case 'last90days': {
const dayStart = getDayStart(current);
return {
start: dayStart.minus({ days: 89 }),
end: getDayEnd(current)
};
}
case 'previous7days': {
const currentPeriodStart = getDayStart(current).minus({ days: 6 });
const previousEndDay = currentPeriodStart.minus({ days: 1 });
const previousStartDay = previousEndDay.minus({ days: 6 });
return {
start: getDayStart(previousStartDay),
end: getDayEnd(previousEndDay)
};
}
case 'previous30days': {
const currentPeriodStart = getDayStart(current).minus({ days: 29 });
const previousEndDay = currentPeriodStart.minus({ days: 1 });
const previousStartDay = previousEndDay.minus({ days: 29 });
return {
start: getDayStart(previousStartDay),
end: getDayEnd(previousEndDay)
};
}
case 'previous90days': {
const currentPeriodStart = getDayStart(current).minus({ days: 89 });
const previousEndDay = currentPeriodStart.minus({ days: 1 });
const previousStartDay = previousEndDay.minus({ days: 89 });
return {
start: getDayStart(previousStartDay),
end: getDayEnd(previousEndDay)
};
} }
default: default:
throw new Error(`Unknown time range: ${timeRange}`); throw new Error(`Unknown time range: ${timeRange}`);
} }
}; };
const getTimeRangeConditions = (timeRange, startDate, endDate) => { const toDatabaseSqlString = (dt) => {
if (timeRange === 'custom' && startDate && endDate) { const normalized = ensureDateTime(dt);
// Custom date range if (!normalized || !normalized.isValid) {
const start = new Date(startDate); throw new Error('Invalid datetime provided for SQL conversion');
const end = new Date(endDate);
// Convert to UTC-5 (Eastern time)
const startUTC5 = new Date(start.getTime() - (5 * 60 * 60 * 1000));
const endUTC5 = new Date(end.getTime() - (5 * 60 * 60 * 1000));
return {
whereClause: 'date_placed >= ? AND date_placed <= ?',
params: [
startUTC5.toISOString().slice(0, 19).replace('T', ' '),
endUTC5.toISOString().slice(0, 19).replace('T', ' ')
],
dateRange: {
start: startDate,
end: endDate,
label: `${formatBusinessDate(start)} - ${formatBusinessDate(end)}`
} }
}; const dbTime = normalized.setZone(DB_TIMEZONE, { keepLocalTime: true });
} return dbTime.toFormat(DB_DATETIME_FORMAT);
if (!timeRange) {
timeRange = 'today';
}
const { start, end } = getBusinessDayBounds(timeRange);
// Convert to MySQL datetime format (UTC-5)
const startStr = start.toISOString().slice(0, 19).replace('T', ' ');
const endStr = end.toISOString().slice(0, 19).replace('T', ' ');
return {
whereClause: 'date_placed >= ? AND date_placed <= ?',
params: [startStr, endStr],
dateRange: {
start: start.toISOString(),
end: end.toISOString(),
label: getTimeRangeLabel(timeRange)
}
};
}; };
const formatBusinessDate = (date) => { const formatBusinessDate = (input) => {
return date.toLocaleDateString('en-US', { const dt = ensureDateTime(input);
month: 'short', if (!dt || !dt.isValid) return '';
day: 'numeric', return dt.setZone(TIMEZONE).toFormat('LLL d, yyyy');
year: 'numeric'
});
}; };
const getTimeRangeLabel = (timeRange) => { const getTimeRangeLabel = (timeRange) => {
const labels = { const labels = {
today: 'Today', today: 'Today',
yesterday: 'Yesterday', yesterday: 'Yesterday',
twoDaysAgo: 'Two Days Ago',
thisWeek: 'This Week', thisWeek: 'This Week',
lastWeek: 'Last Week', lastWeek: 'Last Week',
thisMonth: 'This Month', thisMonth: 'This Month',
@@ -221,32 +223,75 @@ const getTimeRangeLabel = (timeRange) => {
last90days: 'Last 90 Days', last90days: 'Last 90 Days',
previous7days: 'Previous 7 Days', previous7days: 'Previous 7 Days',
previous30days: 'Previous 30 Days', previous30days: 'Previous 30 Days',
previous90days: 'Previous 90 Days', previous90days: 'Previous 90 Days'
twoDaysAgo: 'Two Days Ago'
}; };
return labels[timeRange] || timeRange; return labels[timeRange] || timeRange;
}; };
// Helper to convert MySQL datetime to JavaScript Date const getTimeRangeConditions = (timeRange, startDate, endDate) => {
if (timeRange === 'custom' && startDate && endDate) {
const start = ensureDateTime(startDate);
const end = ensureDateTime(endDate);
if (!start || !start.isValid || !end || !end.isValid) {
throw new Error('Invalid custom date range provided');
}
return {
whereClause: 'date_placed >= ? AND date_placed <= ?',
params: [toDatabaseSqlString(start), toDatabaseSqlString(end)],
dateRange: {
start: start.toUTC().toISO(),
end: end.toUTC().toISO(),
label: `${formatBusinessDate(start)} - ${formatBusinessDate(end)}`
}
};
}
const normalizedRange = timeRange || 'today';
const range = getRangeForTimeRange(normalizedRange);
return {
whereClause: 'date_placed >= ? AND date_placed <= ?',
params: [toDatabaseSqlString(range.start), toDatabaseSqlString(range.end)],
dateRange: {
start: range.start.toUTC().toISO(),
end: range.end.toUTC().toISO(),
label: getTimeRangeLabel(normalizedRange)
}
};
};
const getBusinessDayBounds = (timeRange) => {
const range = getRangeForTimeRange(timeRange);
return {
start: range.start.toJSDate(),
end: range.end.toJSDate()
};
};
const parseBusinessDate = (mysqlDatetime) => { const parseBusinessDate = (mysqlDatetime) => {
if (!mysqlDatetime || mysqlDatetime === '0000-00-00 00:00:00') { if (!mysqlDatetime || mysqlDatetime === '0000-00-00 00:00:00') {
return null; return null;
} }
// MySQL datetime is stored in UTC-5, so we need to add 5 hours to get UTC const dt = DateTime.fromSQL(mysqlDatetime, { zone: DB_TIMEZONE });
const date = new Date(mysqlDatetime + ' UTC'); if (!dt.isValid) {
date.setHours(date.getHours() + 5); console.error('[timeUtils] Failed to parse MySQL datetime:', mysqlDatetime, dt.invalidExplanation);
return date; return null;
}
return dt.toUTC().toJSDate();
}; };
// Helper to format date for MySQL queries const formatMySQLDate = (input) => {
const formatMySQLDate = (date) => { if (!input) return null;
if (!date) return null;
// Convert to UTC-5 for storage const dt = ensureDateTime(input, { zone: 'utc' });
const utc5Date = new Date(date.getTime() - (5 * 60 * 60 * 1000)); if (!dt || !dt.isValid) return null;
return utc5Date.toISOString().slice(0, 19).replace('T', ' ');
return dt.setZone(DB_TIMEZONE).toFormat(DB_DATETIME_FORMAT);
}; };
module.exports = { module.exports = {
@@ -255,5 +300,13 @@ module.exports = {
formatBusinessDate, formatBusinessDate,
getTimeRangeLabel, getTimeRangeLabel,
parseBusinessDate, parseBusinessDate,
formatMySQLDate formatMySQLDate,
// Expose helpers for tests or advanced consumers
_internal: {
getDayStart,
getDayEnd,
getWeekStart,
getRangeForTimeRange,
BUSINESS_DAY_START_HOUR
}
}; };

View File

@@ -186,7 +186,6 @@ export const AnalyticsDashboard = () => {
const result = await response.json(); const result = await response.json();
if (!result?.data?.rows) { if (!result?.data?.rows) {
console.log("No result data received");
return; return;
} }

View File

@@ -761,7 +761,6 @@ const FinancialOverview = () => {
} }
const grossSalesValue = toNumber((point as { grossSales?: number }).grossSales); const grossSalesValue = toNumber((point as { grossSales?: number }).grossSales);
const refundsValue = toNumber((point as { refunds?: number }).refunds);
const shippingFeesValue = toNumber((point as { shippingFees?: number }).shippingFees); const shippingFeesValue = toNumber((point as { shippingFees?: number }).shippingFees);
const taxCollectedValue = toNumber((point as { taxCollected?: number }).taxCollected); const taxCollectedValue = toNumber((point as { taxCollected?: number }).taxCollected);
const discountsValue = toNumber((point as { discounts?: number }).discounts); const discountsValue = toNumber((point as { discounts?: number }).discounts);

View File

@@ -225,13 +225,6 @@ const GorgiasOverview = () => {
.then(res => res.data?.data?.data?.data || []), .then(res => res.data?.data?.data?.data || []),
]); ]);
console.log('Raw API responses:', {
overview,
channelStats,
agentStats,
satisfaction,
});
setData({ setData({
overview, overview,
channels: channelStats, channels: channelStats,
@@ -270,8 +263,6 @@ const GorgiasOverview = () => {
return acc; return acc;
}, {}); }, {});
console.log('Processed stats:', stats);
// Process satisfaction data // Process satisfaction data
const satisfactionStats = (data.satisfaction || []).reduce((acc, item) => { const satisfactionStats = (data.satisfaction || []).reduce((acc, item) => {
if (item.name !== 'response_distribution') { if (item.name !== 'response_distribution') {
@@ -285,8 +276,6 @@ const GorgiasOverview = () => {
return acc; return acc;
}, {}); }, {});
console.log('Processed satisfaction stats:', satisfactionStats);
// Process channel data // Process channel data
const channels = data.channels?.map(line => ({ const channels = data.channels?.map(line => ({
name: line[0]?.value || '', name: line[0]?.value || '',
@@ -295,8 +284,6 @@ const GorgiasOverview = () => {
delta: line[3]?.value || 0 delta: line[3]?.value || 0
})) || []; })) || [];
console.log('Processed channels:', channels);
// Process agent data // Process agent data
const agents = data.agents?.map(line => ({ const agents = data.agents?.map(line => ({
name: line[0]?.value || '', name: line[0]?.value || '',
@@ -306,8 +293,6 @@ const GorgiasOverview = () => {
delta: line[4]?.value || 0 delta: line[4]?.value || 0
})) || []; })) || [];
console.log('Processed agents:', agents);
if (error) { if (error) {
return ( return (
<Card className="h-full bg-white dark:bg-gray-900/60 backdrop-blur-sm"> <Card className="h-full bg-white dark:bg-gray-900/60 backdrop-blur-sm">

View File

@@ -256,16 +256,6 @@ const MiniStatCards = ({
: stats.revenue; : stats.revenue;
const prevRevenue = stats.prevPeriodRevenue; // Previous period's total revenue const prevRevenue = stats.prevPeriodRevenue; // Previous period's total revenue
console.log('[MiniStatCards RevenueTrend Debug]', {
periodProgress: stats.periodProgress,
currentRevenue,
smartProjection: projection?.projectedRevenue,
simpleProjection: stats.projectedRevenue,
actualRevenue: stats.revenue,
prevRevenue,
isProjected: stats.periodProgress < 100
});
if (!currentRevenue || !prevRevenue) return null; if (!currentRevenue || !prevRevenue) return null;
// Calculate absolute difference percentage // Calculate absolute difference percentage
@@ -273,12 +263,6 @@ const MiniStatCards = ({
const diff = Math.abs(currentRevenue - prevRevenue); const diff = Math.abs(currentRevenue - prevRevenue);
const percentage = (diff / prevRevenue) * 100; const percentage = (diff / prevRevenue) * 100;
console.log('[MiniStatCards RevenueTrend Result]', {
trend,
percentage,
calculation: `(|${currentRevenue} - ${prevRevenue}| / ${prevRevenue}) * 100 = ${percentage}%`
});
return { return {
trend, trend,
value: percentage, value: percentage,

View File

@@ -1397,12 +1397,10 @@ const StatCards = ({
const cachedData = getCacheData(detailTimeRange, metric); const cachedData = getCacheData(detailTimeRange, metric);
if (cachedData) { if (cachedData) {
console.log(`Using cached data for ${metric}`);
setDetailData((prev) => ({ ...prev, [metric]: cachedData })); setDetailData((prev) => ({ ...prev, [metric]: cachedData }));
return cachedData; return cachedData;
} }
console.log(`Fetching detail data for ${metric}`);
setDetailDataLoading((prev) => ({ ...prev, [metric]: true })); setDetailDataLoading((prev) => ({ ...prev, [metric]: true }));
try { try {
@@ -1481,7 +1479,6 @@ const StatCards = ({
eventType: "PLACED_ORDER", eventType: "PLACED_ORDER",
}); });
const data = response.stats; const data = response.stats;
console.log("Fetched order range data:", data);
setCacheData(detailTimeRange, metric, data); setCacheData(detailTimeRange, metric, data);
setDetailData((prev) => ({ ...prev, [metric]: data })); setDetailData((prev) => ({ ...prev, [metric]: data }));
setError(null); setError(null);
@@ -1570,16 +1567,6 @@ const StatCards = ({
: stats.revenue; : stats.revenue;
const prevRevenue = stats.prevPeriodRevenue; // Previous period's total revenue const prevRevenue = stats.prevPeriodRevenue; // Previous period's total revenue
console.log('[RevenueTrend Debug]', {
periodProgress: stats.periodProgress,
currentRevenue,
smartProjection: projection?.projectedRevenue,
simpleProjection: stats.projectedRevenue,
actualRevenue: stats.revenue,
prevRevenue,
isProjected: stats.periodProgress < 100
});
if (!currentRevenue || !prevRevenue) return null; if (!currentRevenue || !prevRevenue) return null;
// Calculate absolute difference percentage // Calculate absolute difference percentage
@@ -1587,12 +1574,6 @@ const StatCards = ({
const diff = Math.abs(currentRevenue - prevRevenue); const diff = Math.abs(currentRevenue - prevRevenue);
const percentage = (diff / prevRevenue) * 100; const percentage = (diff / prevRevenue) * 100;
console.log('[RevenueTrend Result]', {
trend,
percentage,
calculation: `(|${currentRevenue} - ${prevRevenue}| / ${prevRevenue}) * 100 = ${percentage}%`
});
return { return {
trend, trend,
value: percentage, value: percentage,

View File

@@ -86,7 +86,6 @@ export const UserBehaviorDashboard = () => {
const processPageData = (data) => { const processPageData = (data) => {
if (!data?.rows) { if (!data?.rows) {
console.log("No rows in page data");
return []; return [];
} }
@@ -101,7 +100,6 @@ export const UserBehaviorDashboard = () => {
const processDeviceData = (data) => { const processDeviceData = (data) => {
if (!data?.rows) { if (!data?.rows) {
console.log("No rows in device data");
return []; return [];
} }
@@ -123,7 +121,6 @@ export const UserBehaviorDashboard = () => {
const processSourceData = (data) => { const processSourceData = (data) => {
if (!data?.rows) { if (!data?.rows) {
console.log("No rows in source data");
return []; return [];
} }
@@ -150,7 +147,6 @@ export const UserBehaviorDashboard = () => {
} }
const result = await response.json(); const result = await response.json();
console.log("Raw user behavior response:", result);
if (!result?.success) { if (!result?.success) {
throw new Error("Invalid response structure"); throw new Error("Invalid response structure");
@@ -164,12 +160,6 @@ export const UserBehaviorDashboard = () => {
const deviceResponse = rawData?.deviceResponse || rawData?.reports?.[1]; const deviceResponse = rawData?.deviceResponse || rawData?.reports?.[1];
const sourceResponse = rawData?.sourceResponse || rawData?.reports?.[2]; const sourceResponse = rawData?.sourceResponse || rawData?.reports?.[2];
console.log("Extracted responses:", {
pageResponse,
deviceResponse,
sourceResponse,
});
const processed = { const processed = {
success: true, success: true,
data: { data: {
@@ -181,7 +171,6 @@ export const UserBehaviorDashboard = () => {
}, },
}; };
console.log("Final processed data:", processed);
setData(processed); setData(processed);
} catch (error) { } catch (error) {
console.error("Failed to fetch behavior data:", error); console.error("Failed to fetch behavior data:", error);

View File

@@ -40,14 +40,12 @@ export function ForecastMetrics() {
startDate: dateRange.from?.toISOString() || "", startDate: dateRange.from?.toISOString() || "",
endDate: dateRange.to?.toISOString() || "", endDate: dateRange.to?.toISOString() || "",
}); });
console.log('Fetching forecast metrics with params:', params.toString());
const response = await fetch(`${config.apiUrl}/dashboard/forecast/metrics?${params}`) const response = await fetch(`${config.apiUrl}/dashboard/forecast/metrics?${params}`)
if (!response.ok) { if (!response.ok) {
const text = await response.text(); const text = await response.text();
throw new Error(`Failed to fetch forecast metrics: ${text}`); throw new Error(`Failed to fetch forecast metrics: ${text}`);
} }
const data = await response.json(); const data = await response.json();
console.log('Forecast metrics response:', data);
return data; return data;
}, },
}) })

View File

@@ -103,7 +103,6 @@ export function PurchaseMetrics() {
const { data, error, isLoading } = useQuery<PurchaseMetricsData>({ const { data, error, isLoading } = useQuery<PurchaseMetricsData>({
queryKey: ["purchase-metrics"], queryKey: ["purchase-metrics"],
queryFn: async () => { queryFn: async () => {
console.log('Fetching from:', `${config.apiUrl}/dashboard/purchase/metrics`);
const response = await fetch(`${config.apiUrl}/dashboard/purchase/metrics`) const response = await fetch(`${config.apiUrl}/dashboard/purchase/metrics`)
if (!response.ok) { if (!response.ok) {
const text = await response.text(); const text = await response.text();
@@ -111,7 +110,6 @@ export function PurchaseMetrics() {
throw new Error(`Failed to fetch purchase metrics: ${response.status} ${response.statusText}`); throw new Error(`Failed to fetch purchase metrics: ${response.status} ${response.statusText}`);
} }
const data = await response.json(); const data = await response.json();
console.log('API Response:', data);
return data; return data;
}, },
}) })

View File

@@ -25,7 +25,6 @@ export function ReplenishmentMetrics() {
const { data, error, isLoading } = useQuery<ReplenishmentMetricsData>({ const { data, error, isLoading } = useQuery<ReplenishmentMetricsData>({
queryKey: ["replenishment-metrics"], queryKey: ["replenishment-metrics"],
queryFn: async () => { queryFn: async () => {
console.log('Fetching from:', `${config.apiUrl}/dashboard/replenishment/metrics`);
const response = await fetch(`${config.apiUrl}/dashboard/replenishment/metrics`) const response = await fetch(`${config.apiUrl}/dashboard/replenishment/metrics`)
if (!response.ok) { if (!response.ok) {
const text = await response.text(); const text = await response.text();
@@ -33,7 +32,6 @@ export function ReplenishmentMetrics() {
throw new Error(`Failed to fetch replenishment metrics: ${response.status} ${response.statusText} - ${text}`) throw new Error(`Failed to fetch replenishment metrics: ${response.status} ${response.statusText} - ${text}`)
} }
const data = await response.json(); const data = await response.json();
console.log('API Response:', data);
return data; return data;
}, },
}) })

View File

@@ -103,7 +103,6 @@ export function StockMetrics() {
const { data, error, isLoading } = useQuery<StockMetricsData>({ const { data, error, isLoading } = useQuery<StockMetricsData>({
queryKey: ["stock-metrics"], queryKey: ["stock-metrics"],
queryFn: async () => { queryFn: async () => {
console.log('Fetching from:', `${config.apiUrl}/dashboard/stock/metrics`);
const response = await fetch(`${config.apiUrl}/dashboard/stock/metrics`); const response = await fetch(`${config.apiUrl}/dashboard/stock/metrics`);
if (!response.ok) { if (!response.ok) {
const text = await response.text(); const text = await response.text();
@@ -111,7 +110,6 @@ export function StockMetrics() {
throw new Error(`Failed to fetch stock metrics: ${response.status} ${response.statusText}`); throw new Error(`Failed to fetch stock metrics: ${response.status} ${response.statusText}`);
} }
const data = await response.json(); const data = await response.json();
console.log('API Response:', data);
return data; return data;
}, },
}); });

View File

@@ -1029,7 +1029,6 @@ export const MatchColumnsStep = React.memo(<T extends string>({
); );
if (matchingOption) { if (matchingOption) {
console.log(`Auto-matched "${entryValue}" to "${matchingOption.label}" (${matchingOption.value})`);
return { return {
...option, ...option,
value: matchingOption.value value: matchingOption.value
@@ -1094,7 +1093,6 @@ export const MatchColumnsStep = React.memo(<T extends string>({
); );
if (matchingOption) { if (matchingOption) {
console.log(`Auto-matched "${entryValue}" to "${matchingOption.label}" (${matchingOption.value})`);
return { return {
...option, ...option,
value: matchingOption.value value: matchingOption.value
@@ -1159,18 +1157,6 @@ export const MatchColumnsStep = React.memo(<T extends string>({
// Convert the fields to the expected type // Convert the fields to the expected type
const fieldsArray = Array.isArray(fields) ? fields : [fields]; const fieldsArray = Array.isArray(fields) ? fields : [fields];
// Log the fields for debugging
console.log("All fields:", fieldsArray);
// Log validation rules for each field
fieldsArray.forEach(field => {
if (field.validations && Array.isArray(field.validations)) {
console.log(`Field ${field.key} validations:`, field.validations.map((v: any) => v.rule));
} else {
console.log(`Field ${field.key} has no validations`);
}
});
// Check for required fields based on validations // Check for required fields based on validations
const required = fieldsArray.filter(field => { const required = fieldsArray.filter(field => {
// Check if the field has validations // Check if the field has validations
@@ -1183,12 +1169,10 @@ export const MatchColumnsStep = React.memo(<T extends string>({
(v: any) => v.rule === 'required' || v.required === true (v: any) => v.rule === 'required' || v.required === true
); );
console.log(`Field ${field.key} required:`, isRequired, field.validations);
return isRequired; return isRequired;
}); });
console.log("Required fields:", required);
return required; return required;
}, [fields]); }, [fields]);

View File

@@ -62,14 +62,8 @@ export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps
const [selectedRowIndex] = selectedRows; const [selectedRowIndex] = selectedRows;
const selectedHeaderRow = localData[selectedRowIndex]; const selectedHeaderRow = localData[selectedRowIndex];
// Debug: Log the selected header row
console.log("Selected header row:", selectedHeaderRow);
const normalizedHeaderRow = normalizeRowForComparison(selectedHeaderRow); const normalizedHeaderRow = normalizeRowForComparison(selectedHeaderRow);
// Debug: Log the normalized header row
console.log("Normalized header row:", normalizedHeaderRow);
const selectedHeaderStr = JSON.stringify(Object.entries(normalizedHeaderRow).sort()); const selectedHeaderStr = JSON.stringify(Object.entries(normalizedHeaderRow).sort());
// Filter out empty rows, rows with single values (if we have multi-value rows), // Filter out empty rows, rows with single values (if we have multi-value rows),
@@ -97,11 +91,6 @@ export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps
// Check if it's a duplicate (case-insensitive) // Check if it's a duplicate (case-insensitive)
const normalizedRow = normalizeRowForComparison(row); const normalizedRow = normalizeRowForComparison(row);
// Debug: If this row might be a duplicate of the header, log it
if (index < 5 || index === selectedRowIndex + 1 || index === selectedRowIndex - 1) {
console.log(`Row ${index} normalized:`, normalizedRow);
}
const rowStr = JSON.stringify(Object.entries(normalizedRow).sort()); const rowStr = JSON.stringify(Object.entries(normalizedRow).sort());
if (seen.has(rowStr)) { if (seen.has(rowStr)) {
@@ -117,9 +106,6 @@ export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps
return true; return true;
}); });
// Debug: Log removed rows
console.log("Removed rows:", removedRows);
// Only update if we actually removed any rows // Only update if we actually removed any rows
if (filteredRows.length < localData.length) { if (filteredRows.length < localData.length) {
// Adjust the selected row index if needed // Adjust the selected row index if needed
@@ -127,9 +113,6 @@ export const SelectHeaderStep = ({ data, onContinue, onBack }: SelectHeaderProps
JSON.stringify(Object.entries(normalizeRowForComparison(row)).sort()) === selectedHeaderStr JSON.stringify(Object.entries(normalizeRowForComparison(row)).sort()) === selectedHeaderStr
); );
// Debug: Log the new selected index
console.log("New selected index:", newSelectedIndex);
setLocalData(filteredRows); setLocalData(filteredRows);
setSelectedRows(new Set([newSelectedIndex])); setSelectedRows(new Set([newSelectedIndex]));

View File

@@ -184,11 +184,9 @@ const ValidationContainer = <T extends string>({
const fetchFieldOptions = useCallback(async () => { const fetchFieldOptions = useCallback(async () => {
try { try {
const response = await axios.get('/api/import/field-options'); const response = await axios.get('/api/import/field-options');
console.log('Field options from API:', response.data);
// Check if suppliers are included in the response // Check if suppliers are included in the response
if (response.data && response.data.suppliers) { if (response.data && response.data.suppliers) {
console.log('Suppliers available:', response.data.suppliers.length);
} else { } else {
console.warn('No suppliers found in field options response'); console.warn('No suppliers found in field options response');
} }
@@ -282,24 +280,6 @@ const ValidationContainer = <T extends string>({
try { try {
const options = await fetchFieldOptions(); const options = await fetchFieldOptions();
if (options && options.suppliers) { if (options && options.suppliers) {
console.log(`Loaded ${options.suppliers.length} suppliers for template form`);
// Log if we can find a match for our supplier
if (templateData.supplier !== undefined) {
// Need to compare numeric values since supplier options have numeric values
const supplierMatch = options.suppliers.find((s: { value: string | number }) =>
s.value === templateData.supplier ||
Number(s.value) === Number(templateData.supplier)
);
console.log('Found supplier match:', supplierMatch ? 'Yes' : 'No',
'For supplier value:', templateData.supplier,
'Type:', typeof templateData.supplier);
if (supplierMatch) {
console.log('Matched supplier:', supplierMatch.label);
}
}
setIsTemplateFormOpen(true); setIsTemplateFormOpen(true);
} else { } else {
@@ -344,7 +324,6 @@ const ValidationContainer = <T extends string>({
.filter(([_, selected]) => selected === true) .filter(([_, selected]) => selected === true)
.map(([key, _]) => key); .map(([key, _]) => key);
console.log('Selected row keys for deletion:', selectedKeys);
if (selectedKeys.length === 0) { if (selectedKeys.length === 0) {
toast.error("No rows selected"); toast.error("No rows selected");
@@ -361,7 +340,6 @@ const ValidationContainer = <T extends string>({
return index; return index;
}).filter(index => index !== -1); // Filter out any not found }).filter(index => index !== -1); // Filter out any not found
console.log('Mapped row indices for deletion:', selectedIndices);
if (selectedIndices.length === 0) { if (selectedIndices.length === 0) {
toast.error('Could not find selected rows'); toast.error('Could not find selected rows');
@@ -567,7 +545,6 @@ const ValidationContainer = <T extends string>({
const upcValue = (data[rowIndex] as any)?.upc || (data[rowIndex] as any)?.barcode; const upcValue = (data[rowIndex] as any)?.upc || (data[rowIndex] as any)?.barcode;
if (upcValue) { if (upcValue) {
console.log(`Validating UPC: rowIndex=${rowIndex}, supplier=${value}, upc=${upcValue}`);
// Mark the item_number cell as being validated // Mark the item_number cell as being validated
const cellKey = `${rowIndex}-item_number`; const cellKey = `${rowIndex}-item_number`;
@@ -581,7 +558,6 @@ const ValidationContainer = <T extends string>({
upcValidation.validateUpc(rowIndex, value.toString(), upcValue.toString()) upcValidation.validateUpc(rowIndex, value.toString(), upcValue.toString())
.then(result => { .then(result => {
if (result.success) { if (result.success) {
console.log(`UPC validation successful for row ${rowIndex}`);
upcValidation.applyItemNumbersToData(); upcValidation.applyItemNumbersToData();
// Mark for revalidation after item numbers are updated // Mark for revalidation after item numbers are updated
@@ -606,14 +582,12 @@ const ValidationContainer = <T extends string>({
// Handle line change - clear subline and fetch sublines // Handle line change - clear subline and fetch sublines
if (key === 'line' && value) { if (key === 'line' && value) {
console.log(`Line changed to ${value} for row ${rowIndex}, updating sublines`);
// Clear any existing subline value // Clear any existing subline value
setData(prevData => { setData(prevData => {
const newData = [...prevData]; const newData = [...prevData];
const idx = newData.findIndex(item => item.__index === rowId); const idx = newData.findIndex(item => item.__index === rowId);
if (idx >= 0) { if (idx >= 0) {
console.log(`Clearing subline values for row with ID ${rowId}`);
newData[idx] = { newData[idx] = {
...newData[idx], ...newData[idx],
subline: undefined subline: undefined
@@ -628,9 +602,6 @@ const ValidationContainer = <T extends string>({
if (rowId && value !== undefined) { if (rowId && value !== undefined) {
const lineId = value.toString(); const lineId = value.toString();
// Force immediate fetch for better UX
console.log(`Immediately fetching sublines for line ${lineId} for row ${rowId}`);
// Set loading state first // Set loading state first
setValidatingCells(prev => { setValidatingCells(prev => {
const newSet = new Set(prev); const newSet = new Set(prev);
@@ -639,8 +610,7 @@ const ValidationContainer = <T extends string>({
}); });
fetchSublines(rowId, lineId) fetchSublines(rowId, lineId)
.then(sublines => { .then(() => {
console.log(`Successfully loaded ${sublines.length} sublines for line ${lineId}`);
}) })
.catch(err => { .catch(err => {
console.error(`Error fetching sublines for line ${lineId}:`, err); console.error(`Error fetching sublines for line ${lineId}:`, err);
@@ -664,7 +634,6 @@ const ValidationContainer = <T extends string>({
const supplier = (data[rowIndex] as any)?.supplier; const supplier = (data[rowIndex] as any)?.supplier;
if (supplier) { if (supplier) {
console.log(`Validating UPC from UPC change: rowIndex=${rowIndex}, supplier=${supplier}, upc=${value}`);
// Mark the item_number cell as being validated // Mark the item_number cell as being validated
const cellKey = `${rowIndex}-item_number`; const cellKey = `${rowIndex}-item_number`;
@@ -678,7 +647,6 @@ const ValidationContainer = <T extends string>({
upcValidation.validateUpc(rowIndex, supplier.toString(), value.toString()) upcValidation.validateUpc(rowIndex, supplier.toString(), value.toString())
.then(result => { .then(result => {
if (result.success) { if (result.success) {
console.log(`UPC validation successful for row ${rowIndex}`);
upcValidation.applyItemNumbersToData(); upcValidation.applyItemNumbersToData();
// Mark for revalidation after item numbers are updated // Mark for revalidation after item numbers are updated
@@ -818,7 +786,6 @@ const ValidationContainer = <T extends string>({
// Run validations in parallel but limit the batch size // Run validations in parallel but limit the batch size
if (validationsToRun.length > 0) { if (validationsToRun.length > 0) {
console.log(`Running ${validationsToRun.length} UPC validations for copyDown`);
// Mark all cells as validating // Mark all cells as validating
validationsToRun.forEach(({ rowIndex }) => { validationsToRun.forEach(({ rowIndex }) => {
@@ -877,7 +844,6 @@ const ValidationContainer = <T extends string>({
// Add a small delay between batches to prevent UI freezing // Add a small delay between batches to prevent UI freezing
setTimeout(() => processBatch(endIdx), 100); setTimeout(() => processBatch(endIdx), 100);
} else { } else {
console.log(`Completed all ${validationsToRun.length} UPC validations`);
// Final application of all item numbers if not done by individual batches // Final application of all item numbers if not done by individual batches
upcValidation.applyItemNumbersToData(updatedRowIds => { upcValidation.applyItemNumbersToData(updatedRowIds => {
// Mark these rows for revalidation after a delay // Mark these rows for revalidation after a delay
@@ -1112,8 +1078,6 @@ const ValidationContainer = <T extends string>({
size="sm" size="sm"
className="h-8 shadow-xs" className="h-8 shadow-xs"
onClick={() => { onClick={() => {
console.log('Delete/Discard button clicked');
console.log('Row selection state:', rowSelection);
deleteSelectedRows(); deleteSelectedRows();
}} }}
> >

View File

@@ -23,7 +23,6 @@ export default defineConfig(({ mode }) => {
await fs.ensureDir(path.dirname(targetPath)); await fs.ensureDir(path.dirname(targetPath));
await fs.remove(targetPath); await fs.remove(targetPath);
await fs.copy(sourcePath, targetPath); await fs.copy(sourcePath, targetPath);
console.log('Build files copied successfully to server directory!');
} catch (error) { } catch (error) {
console.error('Error copying build files:', error); console.error('Error copying build files:', error);
process.exit(1); process.exit(1);
@@ -105,7 +104,7 @@ export default defineConfig(({ mode }) => {
rewrite: (path) => path.replace(/^\/api/, "/api"), rewrite: (path) => path.replace(/^\/api/, "/api"),
configure: (proxy, _options) => { configure: (proxy, _options) => {
proxy.on("error", (err, req, res) => { proxy.on("error", (err, req, res) => {
console.log("API proxy error:", err) console.error("API proxy error:", err)
res.writeHead(500, { res.writeHead(500, {
"Content-Type": "application/json", "Content-Type": "application/json",
}) })
@@ -113,20 +112,6 @@ export default defineConfig(({ mode }) => {
JSON.stringify({ error: "Proxy Error", message: err.message }) JSON.stringify({ error: "Proxy Error", message: err.message })
) )
}) })
proxy.on("proxyReq", (proxyReq, req, _res) => {
console.log("Outgoing request to API:", {
method: req.method,
url: req.url,
headers: proxyReq.getHeaders(),
})
})
proxy.on("proxyRes", (proxyRes, req, _res) => {
console.log("API Proxy response:", {
statusCode: proxyRes.statusCode,
url: req.url,
headers: proxyRes.headers,
})
})
}, },
}, },
"/dashboard-auth": { "/dashboard-auth": {
@@ -153,7 +138,7 @@ export default defineConfig(({ mode }) => {
rewrite: (path) => path.replace(/^\/auth-inv/, "/auth-inv"), rewrite: (path) => path.replace(/^\/auth-inv/, "/auth-inv"),
configure: (proxy, _options) => { configure: (proxy, _options) => {
proxy.on("error", (err, req, res) => { proxy.on("error", (err, req, res) => {
console.log("Auth proxy error:", err) console.error("Auth proxy error:", err)
res.writeHead(500, { res.writeHead(500, {
"Content-Type": "application/json", "Content-Type": "application/json",
}) })
@@ -161,20 +146,6 @@ export default defineConfig(({ mode }) => {
JSON.stringify({ error: "Proxy Error", message: err.message }) JSON.stringify({ error: "Proxy Error", message: err.message })
) )
}) })
proxy.on("proxyReq", (proxyReq, req, _res) => {
console.log("Outgoing request to Auth:", {
method: req.method,
url: req.url,
headers: proxyReq.getHeaders(),
})
})
proxy.on("proxyRes", (proxyRes, req, _res) => {
console.log("Auth Proxy response:", {
statusCode: proxyRes.statusCode,
url: req.url,
headers: proxyRes.headers,
})
})
}, },
}, },
"/chat-api": { "/chat-api": {
@@ -188,7 +159,7 @@ export default defineConfig(({ mode }) => {
rewrite: (path) => path, rewrite: (path) => path,
configure: (proxy, _options) => { configure: (proxy, _options) => {
proxy.on("error", (err, req, res) => { proxy.on("error", (err, req, res) => {
console.log("Chat API proxy error:", err) console.error("Chat API proxy error:", err)
res.writeHead(500, { res.writeHead(500, {
"Content-Type": "application/json", "Content-Type": "application/json",
}) })
@@ -196,20 +167,6 @@ export default defineConfig(({ mode }) => {
JSON.stringify({ error: "Proxy Error", message: err.message }) JSON.stringify({ error: "Proxy Error", message: err.message })
) )
}) })
proxy.on("proxyReq", (proxyReq, req, _res) => {
console.log("Outgoing request to Chat API:", {
method: req.method,
url: req.url,
headers: proxyReq.getHeaders(),
})
})
proxy.on("proxyRes", (proxyRes, req, _res) => {
console.log("Chat API Proxy response:", {
statusCode: proxyRes.statusCode,
url: req.url,
headers: proxyRes.headers,
})
})
}, },
}, },
"/uploads": { "/uploads": {