Add hourly detail charts for single-day ranges
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 46s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 46s
This commit is contained in:
@@ -414,6 +414,8 @@ const getDateOnly = (value) => {
|
||||
return match ? match[1] : null;
|
||||
};
|
||||
|
||||
const isSingleDayRange = (start, end) => Boolean(start && end && start === end);
|
||||
|
||||
const WEEKDAY_LABELS = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'];
|
||||
|
||||
const getWeekdayIndex = (value) => {
|
||||
@@ -751,6 +753,7 @@ const getProductDetailsAnalytics = async (productId, range = {}) => {
|
||||
|
||||
const normalizedStart = normalizeDateParam(range.start);
|
||||
const normalizedEnd = normalizeDateParam(range.end);
|
||||
const useHourlyChart = isSingleDayRange(normalizedStart, normalizedEnd);
|
||||
const periodParams = [normalizedProductId];
|
||||
const periodFilters = [
|
||||
'produto_id = $1',
|
||||
@@ -798,7 +801,16 @@ const getProductDetailsAnalytics = async (productId, range = {}) => {
|
||||
LEFT JOIN order_info ON order_info.id = selected_product.id
|
||||
WHERE stock_info.id IS NOT NULL OR order_info.id IS NOT NULL;
|
||||
`, [normalizedProductId]),
|
||||
pool.query(`
|
||||
pool.query(useHourlyChart ? `
|
||||
SELECT
|
||||
EXTRACT(HOUR FROM created_at AT TIME ZONE 'America/Sao_Paulo')::int as hour,
|
||||
COALESCE(SUM(quantidade), 0) as quantity_sold,
|
||||
COALESCE(SUM(quantidade * valor_unitario), 0) as revenue
|
||||
FROM orders
|
||||
WHERE ${periodFilters.join(' AND ')}
|
||||
GROUP BY hour
|
||||
ORDER BY hour ASC;
|
||||
` : `
|
||||
SELECT
|
||||
data_pedido_date,
|
||||
MAX(data_pedido) as date_label,
|
||||
@@ -814,10 +826,18 @@ const getProductDetailsAnalytics = async (productId, range = {}) => {
|
||||
const summary = summaryResult.rows[0];
|
||||
if (!summary) return null;
|
||||
|
||||
const chartData = periodResult.rows.map(row => ({
|
||||
date: row.date_label || getDateOnly(row.data_pedido_date) || '',
|
||||
value: toNumber(row.quantity_sold)
|
||||
}));
|
||||
const chartData = useHourlyChart
|
||||
? Array.from({ length: 24 }, (_, hour) => {
|
||||
const row = periodResult.rows.find(item => toNumber(item.hour) === hour);
|
||||
return {
|
||||
date: `${String(hour).padStart(2, '0')}h`,
|
||||
value: row ? toNumber(row.quantity_sold) : 0
|
||||
};
|
||||
})
|
||||
: periodResult.rows.map(row => ({
|
||||
date: row.date_label || getDateOnly(row.data_pedido_date) || '',
|
||||
value: toNumber(row.quantity_sold)
|
||||
}));
|
||||
const totalSold = periodResult.rows.reduce((sum, row) => sum + toNumber(row.quantity_sold), 0);
|
||||
const totalRevenue = periodResult.rows.reduce((sum, row) => sum + toNumber(row.revenue), 0);
|
||||
|
||||
@@ -934,6 +954,7 @@ const getClientDetailsAnalytics = async (clientToken, range = {}) => {
|
||||
|
||||
const normalizedStart = normalizeDateParam(range.start);
|
||||
const normalizedEnd = normalizeDateParam(range.end);
|
||||
const useHourlyChart = isSingleDayRange(normalizedStart, normalizedEnd);
|
||||
const periodParams = [resolvedCustomerKey];
|
||||
const periodFilters = [
|
||||
`${CUSTOMER_KEY_SQL} = $1`,
|
||||
@@ -1006,6 +1027,10 @@ const getClientDetailsAnalytics = async (clientToken, range = {}) => {
|
||||
|
||||
const groupedOrdersByKey = new Map();
|
||||
const spentByDate = new Map();
|
||||
const spentByHour = Array.from({ length: 24 }, (_, hour) => ({
|
||||
date: `${String(hour).padStart(2, '0')}h`,
|
||||
value: 0
|
||||
}));
|
||||
const weekdayCounts = WEEKDAY_LABELS.map(label => ({ label, value: 0 }));
|
||||
const hourCounts = Array.from({ length: 24 }, (_, hour) => ({
|
||||
label: `${String(hour).padStart(2, '0')}h`,
|
||||
@@ -1047,6 +1072,13 @@ const getClientDetailsAnalytics = async (clientToken, range = {}) => {
|
||||
spentByDate.set(dateLabel, currentDateSpend);
|
||||
}
|
||||
|
||||
if (useHourlyChart) {
|
||||
const orderHour = getHourFromTimestamp(row.created_at) ?? getHourFromTimestamp(row.data_pedido);
|
||||
if (orderHour !== null) {
|
||||
spentByHour[orderHour].value += itemRevenue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupedOrdersByKey.has(groupKey)) {
|
||||
groupedOrdersByKey.set(groupKey, {
|
||||
date: dateLabel,
|
||||
@@ -1082,9 +1114,11 @@ const getClientDetailsAnalytics = async (clientToken, range = {}) => {
|
||||
const groupedOrders = [...groupedOrdersByKey.values()]
|
||||
.sort((a, b) => String(b.sortDate).localeCompare(String(a.sortDate)))
|
||||
.map(({ sortDate, ...group }) => group);
|
||||
const chartData = [...spentByDate.values()]
|
||||
.sort((a, b) => String(a.sortDate).localeCompare(String(b.sortDate)))
|
||||
.map(({ sortDate, ...entry }) => entry);
|
||||
const chartData = useHourlyChart
|
||||
? spentByHour
|
||||
: [...spentByDate.values()]
|
||||
.sort((a, b) => String(a.sortDate).localeCompare(String(b.sortDate)))
|
||||
.map(({ sortDate, ...entry }) => entry);
|
||||
const periodOrderCount = groupedOrders.length;
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user