From 46012a1b1ce636897b3aef160e7e47a6608cb510 Mon Sep 17 00:00:00 2001 From: Chris <63758245+c-premus@users.noreply.github.com> Date: Wed, 29 Apr 2026 11:51:49 +0000 Subject: [PATCH] Fix pagination params silently ignored on collection GET endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hoist `page` and `pageSize` declarations from the per-module DTOs into the shared DynamicFilterQueryDto base class. Without these declarations, the global ValidationPipe (whitelist: true) strips the params from the request before the service layer sees them, so list services fall back to their default page=1, pageSize=12 regardless of what the client sent. Affects 10 collection GET endpoints whose query DTOs are empty subclasses of DynamicFilterQueryDto: expenses, bills, credit-notes, manual-journals, payments-received, sale-invoices, sale-estimates, sale-receipts, vendor-credits, item-categories. The 3 already-working DTOs (Customers, Vendors, Items) keep their local page/pageSize declarations as redundant overrides — no behavior change. Closes #1088 --- .../DynamicListing/dtos/DynamicFilterQuery.dto.ts | 14 +++++++++++++- packages/server/test/expenses.e2e-spec.ts | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/server/src/modules/DynamicListing/dtos/DynamicFilterQuery.dto.ts b/packages/server/src/modules/DynamicListing/dtos/DynamicFilterQuery.dto.ts index 41a1afa36..732989d51 100644 --- a/packages/server/src/modules/DynamicListing/dtos/DynamicFilterQuery.dto.ts +++ b/packages/server/src/modules/DynamicListing/dtos/DynamicFilterQuery.dto.ts @@ -1,9 +1,21 @@ import { ToNumber } from '@/common/decorators/Validators'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsArray, IsOptional, IsString } from 'class-validator'; +import { IsArray, IsInt, IsOptional, IsString } from 'class-validator'; import { IFilterRole, ISortOrder } from '../DynamicFilter/DynamicFilter.types'; export class DynamicFilterQueryDto { + @ApiPropertyOptional({ description: 'Page number (1-based)', type: Number }) + @IsOptional() + @IsInt() + @ToNumber() + page?: number; + + @ApiPropertyOptional({ description: 'Page size', type: Number }) + @IsOptional() + @IsInt() + @ToNumber() + pageSize?: number; + @ApiPropertyOptional({ description: 'Custom view ID', type: Number }) @IsOptional() @ToNumber() diff --git a/packages/server/test/expenses.e2e-spec.ts b/packages/server/test/expenses.e2e-spec.ts index 9d9850cba..1d86645a9 100644 --- a/packages/server/test/expenses.e2e-spec.ts +++ b/packages/server/test/expenses.e2e-spec.ts @@ -77,4 +77,16 @@ describe('Expenses (e2e)', () => { .set('Authorization', AuthorizationHeader) .expect(200); }); + + it('/expenses (GET) honors page and pageSize query params', async () => { + const response = await request(app.getHttpServer()) + .get('/expenses?page=2&pageSize=5') + .set('organization-id', orgainzationId) + .set('Authorization', AuthorizationHeader) + .expect(200); + + expect(response.body.pagination).toBeDefined(); + expect(response.body.pagination.page).toBe(2); + expect(response.body.pagination.page_size).toBe(5); + }); });