This commit is contained in:
2025-12-23 23:08:05 +03:30
parent e298ccec32
commit 575e6276eb
@@ -308,59 +308,53 @@ export class PaymentsService {
async getChartData(dto: PaymentChartDto, restaurantId: string): Promise<Array<{ date: string; cash: number; online: number }>> { async getChartData(dto: PaymentChartDto, restaurantId: string): Promise<Array<{ date: string; cash: number; online: number }>> {
const { startDate, endDate, type = ChartPeriodEnum.Daily } = dto; 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);
const start = startDate ? new Date(startDate) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // Default: last 30 days
const end = endDate ? new Date(endDate) : new Date(); const end = endDate ? new Date(endDate) : new Date();
let dateGrouping: string; const startOfDay = new Date(start);
let dateSelect: string; startOfDay.setHours(0, 0, 0, 0);
switch (type) { const endOfDay = new Date(end);
case ChartPeriodEnum.Weekly: endOfDay.setHours(23, 59, 59, 999);
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 conditions: string[] = [`p.status = 'paid'`, 'p.paid_at IS NOT NULL']; // 1. Map your Enum to valid Postgres date_trunc units
const params: any[] = []; // '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 >= ?`); const params: any[] = [startOfDay, endOfDay];
params.push(start); let restaurantFilter = '';
conditions.push(`p.paid_at::timestamp <= ?`);
params.push(end);
if (restaurantId) { if (restaurantId) {
conditions.push(`o.restaurant_id = ?`);
params.push(restaurantId); 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 = ` const query = `
SELECT SELECT
${dateSelect} as date, TO_CHAR(DATE_TRUNC('${pgPeriod}', CAST(p.paid_at AS timestamp)), 'YYYY-MM-DD') 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 = '${PaymentMethodEnum.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 COALESCE(SUM(CASE WHEN p.method = '${PaymentMethodEnum.Online}' THEN p.amount ELSE 0 END), 0)::numeric as online
FROM payments p FROM payments p
INNER JOIN orders o ON p.order_id = o.id INNER JOIN orders o ON p.order_id = o.id
WHERE ${whereClause} WHERE p.status = '${PaymentStatusEnum.Paid}'
GROUP BY ${dateGrouping} AND p.paid_at IS NOT NULL
ORDER BY ${dateGrouping} ASC 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); 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 }>(); const dataMap = new Map<string, { cash: number; online: number }>();
result.forEach((row: any) => { result.forEach((row: any) => {
dataMap.set(row.date, { 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(startOfDay, endOfDay, type);
const allDates = this.generateDateRange(start, end, type);
// Return array with all dates, filling missing ones with zeros
return allDates.map(date => ({ return allDates.map(date => ({
date, date,
cash: dataMap.get(date)?.cash ?? 0, cash: dataMap.get(date)?.cash ?? 0,