chart
This commit is contained in:
@@ -308,59 +308,53 @@ export class PaymentsService {
|
||||
async getChartData(dto: PaymentChartDto, restaurantId: string): Promise<Array<{ date: string; cash: number; online: number }>> {
|
||||
const { startDate, endDate, type = ChartPeriodEnum.Daily } = dto;
|
||||
|
||||
// Set default date range if not provided
|
||||
const start = startDate ? new Date(startDate) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // Default: last 30 days
|
||||
const start = startDate ? new Date(startDate) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
||||
const end = endDate ? new Date(endDate) : new Date();
|
||||
|
||||
let dateGrouping: string;
|
||||
let dateSelect: string;
|
||||
const startOfDay = new Date(start);
|
||||
startOfDay.setHours(0, 0, 0, 0);
|
||||
|
||||
switch (type) {
|
||||
case ChartPeriodEnum.Weekly:
|
||||
dateGrouping = "DATE_TRUNC('week', p.paid_at::timestamp)";
|
||||
dateSelect = "TO_CHAR(DATE_TRUNC('week', p.paid_at::timestamp), 'YYYY-MM-DD')";
|
||||
break;
|
||||
case ChartPeriodEnum.Monthly:
|
||||
dateGrouping = "DATE_TRUNC('month', p.paid_at::timestamp)";
|
||||
dateSelect = "TO_CHAR(DATE_TRUNC('month', p.paid_at::timestamp), 'YYYY-MM-DD')";
|
||||
break;
|
||||
case ChartPeriodEnum.Daily:
|
||||
default:
|
||||
dateGrouping = "DATE_TRUNC('day', p.paid_at::timestamp)";
|
||||
dateSelect = "TO_CHAR(DATE_TRUNC('day', p.paid_at::timestamp), 'YYYY-MM-DD')";
|
||||
}
|
||||
const endOfDay = new Date(end);
|
||||
endOfDay.setHours(23, 59, 59, 999);
|
||||
|
||||
const conditions: string[] = [`p.status = 'paid'`, 'p.paid_at IS NOT NULL'];
|
||||
const params: any[] = [];
|
||||
// 1. Map your Enum to valid Postgres date_trunc units
|
||||
// 'Daily' is not valid in PG, it must be 'day'
|
||||
const pgPeriod = {
|
||||
[ChartPeriodEnum.Daily]: 'day',
|
||||
[ChartPeriodEnum.Weekly]: 'week',
|
||||
[ChartPeriodEnum.Monthly]: 'month',
|
||||
}[type] || 'day';
|
||||
|
||||
conditions.push(`p.paid_at::timestamp >= ?`);
|
||||
params.push(start);
|
||||
|
||||
conditions.push(`p.paid_at::timestamp <= ?`);
|
||||
params.push(end);
|
||||
const params: any[] = [startOfDay, endOfDay];
|
||||
let restaurantFilter = '';
|
||||
|
||||
if (restaurantId) {
|
||||
conditions.push(`o.restaurant_id = ?`);
|
||||
params.push(restaurantId);
|
||||
restaurantFilter = `AND o.restaurant_id = ?`;
|
||||
}
|
||||
|
||||
const whereClause = conditions.join(' AND ');
|
||||
|
||||
// MikroORM uses ? placeholders for parameter binding
|
||||
// Ensure paid_at is not NULL and handle timestamp casting properly
|
||||
const query = `
|
||||
SELECT
|
||||
${dateSelect} as date,
|
||||
COALESCE(SUM(CASE WHEN p.method = 'Cash' THEN p.amount ELSE 0 END), 0)::numeric as cash,
|
||||
COALESCE(SUM(CASE WHEN p.method = 'Online' THEN p.amount ELSE 0 END), 0)::numeric as online
|
||||
TO_CHAR(DATE_TRUNC('${pgPeriod}', CAST(p.paid_at AS timestamp)), 'YYYY-MM-DD') as "date",
|
||||
COALESCE(SUM(CASE WHEN p.method = '${PaymentMethodEnum.Cash}' THEN p.amount ELSE 0 END), 0)::numeric as cash,
|
||||
COALESCE(SUM(CASE WHEN p.method = '${PaymentMethodEnum.Online}' THEN p.amount ELSE 0 END), 0)::numeric as online
|
||||
FROM payments p
|
||||
INNER JOIN orders o ON p.order_id = o.id
|
||||
WHERE ${whereClause}
|
||||
GROUP BY ${dateGrouping}
|
||||
ORDER BY ${dateGrouping} ASC
|
||||
WHERE p.status = '${PaymentStatusEnum.Paid}'
|
||||
AND p.paid_at IS NOT NULL
|
||||
AND p.paid_at >= ?
|
||||
AND p.paid_at <= ?
|
||||
${restaurantFilter}
|
||||
GROUP BY DATE_TRUNC('${pgPeriod}', CAST(p.paid_at AS timestamp))
|
||||
ORDER BY DATE_TRUNC('${pgPeriod}', CAST(p.paid_at AS timestamp)) ASC
|
||||
`;
|
||||
|
||||
this.logger.debug(`Chart query params: startOfDay=${startOfDay.toISOString()}, endOfDay=${endOfDay.toISOString()}, restaurantId=${restaurantId}`);
|
||||
const result = await this.em.execute(query, params);
|
||||
this.logger.debug(`Chart query returned ${result.length} rows`);
|
||||
|
||||
// Create a map of existing data
|
||||
const dataMap = new Map<string, { cash: number; online: number }>();
|
||||
result.forEach((row: any) => {
|
||||
dataMap.set(row.date, {
|
||||
@@ -369,10 +363,8 @@ export class PaymentsService {
|
||||
});
|
||||
});
|
||||
|
||||
// Generate all dates in the range based on period type
|
||||
const allDates = this.generateDateRange(start, end, type);
|
||||
const allDates = this.generateDateRange(startOfDay, endOfDay, type);
|
||||
|
||||
// Return array with all dates, filling missing ones with zeros
|
||||
return allDates.map(date => ({
|
||||
date,
|
||||
cash: dataMap.get(date)?.cash ?? 0,
|
||||
|
||||
Reference in New Issue
Block a user