diff --git a/src/transactions/dto/transaction.dto.ts b/src/transactions/dto/transaction.dto.ts index a8b965b..816d420 100644 --- a/src/transactions/dto/transaction.dto.ts +++ b/src/transactions/dto/transaction.dto.ts @@ -189,13 +189,13 @@ export enum TransactionAnalyticsGranularity { } export class TransactionAnalyticsQueryDto { - @ApiPropertyOptional({ description: 'Only include transactions created on or after this date' }) + @ApiPropertyOptional({ description: 'Only include transactions created on or after this date. Maximum date window is 365 days when both startDate and endDate are provided.' }) @IsOptional() @Type(() => Date) @IsDate() startDate?: Date; - @ApiPropertyOptional({ description: 'Only include transactions created on or before this date' }) + @ApiPropertyOptional({ description: 'Only include transactions created on or before this date. Maximum date window is 365 days when both startDate and endDate are provided.' }) @IsOptional() @Type(() => Date) @IsDate() diff --git a/src/transactions/transactions.service.spec.ts b/src/transactions/transactions.service.spec.ts index 9f11856..f6ea136 100644 --- a/src/transactions/transactions.service.spec.ts +++ b/src/transactions/transactions.service.spec.ts @@ -1,3 +1,4 @@ +import { BadRequestException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { Decimal } from '@prisma/client/runtime/library'; import { TransactionsService } from './transactions.service'; @@ -254,5 +255,15 @@ describe('TransactionsService', () => { expect(result.revenue).toBe(0); expect(result.volumeTrends).toEqual([]); }); + + it('should reject date ranges larger than 365 days', async () => { + const startDate = new Date('2025-01-01T00:00:00.000Z'); + const endDate = new Date('2026-01-02T00:00:00.000Z'); + + await expect( + service.getAnalytics({ startDate, endDate, granularity: TransactionAnalyticsGranularity.MONTH }), + ).rejects.toThrow(BadRequestException); + expect(prisma.transaction.findMany).not.toHaveBeenCalled(); + }); }); }); diff --git a/src/transactions/transactions.service.ts b/src/transactions/transactions.service.ts index 57e5163..d1fb9a8 100644 --- a/src/transactions/transactions.service.ts +++ b/src/transactions/transactions.service.ts @@ -316,6 +316,18 @@ export class TransactionsService { async getAnalytics(query: TransactionAnalyticsQueryDto = {}): Promise { const where: Record = {}; + if (query.startDate && query.endDate) { + const maxRangeMs = 365 * 24 * 60 * 60 * 1000; + const durationMs = query.endDate.getTime() - query.startDate.getTime(); + + if (durationMs < 0) { + throw new BadRequestException('endDate must be on or after startDate'); + } + if (durationMs > maxRangeMs) { + throw new BadRequestException('Date range cannot exceed 365 days'); + } + } + if (query.type) { where.type = query.type; }