diff --git a/packages/server/src/common/dtos/PaginatedResults.dto.ts b/packages/server/src/common/dtos/PaginatedResults.dto.ts new file mode 100644 index 000000000..ca7406f2d --- /dev/null +++ b/packages/server/src/common/dtos/PaginatedResults.dto.ts @@ -0,0 +1,33 @@ +import { ApiProperty } from '@nestjs/swagger'; + +class Pagination { + @ApiProperty({ + description: 'Total number of items across all pages', + example: 100, + }) + total: number; + + @ApiProperty({ + description: 'Current page number (1-based)', + example: 1, + minimum: 1, + }) + page: number; + + @ApiProperty({ + description: 'Number of items per page', + example: 10, + minimum: 1, + }) + pageSize: number; +} + +export class PaginatedResponseDto { + @ApiProperty({ + description: 'Pagination metadata', + type: Pagination, + }) + pagination: Pagination; + + data: TData[]; +} diff --git a/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts b/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts index a8bfb8078..5686d1ea2 100644 --- a/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts +++ b/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts @@ -7,13 +7,25 @@ import { Post, Query, } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery, ApiBody } from '@nestjs/swagger'; +import { + ApiTags, + ApiOperation, + ApiResponse, + ApiParam, + ApiQuery, + ApiBody, + getSchemaPath, + ApiExtraModels, +} from '@nestjs/swagger'; import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service'; import { CreateBankTransactionDto } from '../dtos/CreateBankTransaction.dto'; import { GetBankTransactionsQueryDto } from '../dtos/GetBankTranasctionsQuery.dto'; +import { BankTransactionResponseDto } from '../dtos/BankTransactionResponse.dto'; +import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto'; @Controller('banking/transactions') @ApiTags('Banking Transactions') +@ApiExtraModels(BankTransactionResponseDto, PaginatedResponseDto) export class BankingTransactionsController { constructor( private readonly bankingTransactionsApplication: BankingTransactionsApplication, @@ -24,6 +36,21 @@ export class BankingTransactionsController { @ApiResponse({ status: 200, description: 'Returns a list of bank account transactions', + schema: { + allOf: [ + { + $ref: getSchemaPath(PaginatedResponseDto), + }, + { + properties: { + data: { + type: 'array', + items: { $ref: getSchemaPath(BankTransactionResponseDto) }, + }, + }, + }, + ], + }, }) @ApiQuery({ name: 'page', @@ -89,6 +116,9 @@ export class BankingTransactionsController { @ApiResponse({ status: 200, description: 'Returns the bank transaction details', + schema: { + $ref: getSchemaPath(BankTransactionResponseDto), + }, }) @ApiResponse({ status: 404, diff --git a/packages/server/src/modules/BankingTransactions/dtos/BankTransactionResponse.dto.ts b/packages/server/src/modules/BankingTransactions/dtos/BankTransactionResponse.dto.ts new file mode 100644 index 000000000..30b0f6cb4 --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/dtos/BankTransactionResponse.dto.ts @@ -0,0 +1,129 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class BankTransactionResponseDto { + @ApiProperty({ + description: 'The withdrawal amount', + example: 1000.5, + type: Number, + }) + withdrawal: number; + + @ApiProperty({ + description: 'The deposit amount', + example: 2000.75, + type: Number, + }) + deposit: number; + + @ApiProperty({ + description: 'The running balance after the transaction', + example: 3000.25, + type: Number, + }) + runningBalance: number; + + @ApiProperty({ + description: 'Formatted withdrawal amount with currency symbol', + example: '$1,000.50', + type: String, + }) + formattedWithdrawal: string; + + @ApiProperty({ + description: 'Formatted deposit amount with currency symbol', + example: '$2,000.75', + type: String, + }) + formattedDeposit: string; + + @ApiProperty({ + description: 'Formatted running balance with currency symbol', + example: '$3,000.25', + type: String, + }) + formattedRunningBalance: string; + + @ApiProperty({ + description: 'Unique transaction number', + example: 'TRX-2024-001', + type: String, + }) + transactionNumber: string; + + @ApiProperty({ + description: 'Reference number for the transaction', + example: 'REF-2024-001', + type: String, + }) + referenceNumber: string; + + @ApiProperty({ + description: 'ID of the reference entity', + example: 12345, + type: Number, + }) + referenceId: number; + + @ApiProperty({ + description: 'Type of the reference entity', + example: 'INVOICE', + type: String, + }) + referenceType: string; + + @ApiProperty({ + description: 'Formatted transaction type', + example: 'Bank Transfer', + type: String, + }) + formattedTransactionType: string; + + @ApiProperty({ + description: 'Current balance', + example: 5000.0, + type: Number, + }) + balance: number; + + @ApiProperty({ + description: 'Formatted balance with currency symbol', + example: '$5,000.00', + type: String, + }) + formattedBalance: string; + + @ApiProperty({ + description: 'Transaction date', + example: '2024-03-20T10:30:00Z', + type: Date, + }) + date: Date; + + @ApiProperty({ + description: 'Formatted transaction date', + example: 'March 20, 2024', + type: String, + }) + formattedDate: string; + + @ApiProperty({ + description: 'Transaction status', + example: 'COMPLETED', + type: String, + }) + status: string; + + @ApiProperty({ + description: 'Formatted transaction status', + example: 'Completed', + type: String, + }) + formattedStatus: string; + + @ApiProperty({ + description: 'ID of the uncategorized transaction', + example: 67890, + type: Number, + }) + uncategorizedTransactionId: number; +} diff --git a/packages/server/src/modules/Expenses/Expenses.controller.ts b/packages/server/src/modules/Expenses/Expenses.controller.ts index bc605fa71..2c021f682 100644 --- a/packages/server/src/modules/Expenses/Expenses.controller.ts +++ b/packages/server/src/modules/Expenses/Expenses.controller.ts @@ -10,11 +10,20 @@ import { } from '@nestjs/common'; import { ExpensesApplication } from './ExpensesApplication.service'; import { IExpensesFilter } from './Expenses.types'; -import { ApiOperation, ApiTags } from '@nestjs/swagger'; +import { + ApiExtraModels, + ApiOperation, + ApiResponse, + ApiTags, + getSchemaPath, +} from '@nestjs/swagger'; import { CreateExpenseDto, EditExpenseDto } from './dtos/Expense.dto'; +import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto'; +import { ExpenseResponseDto } from './dtos/ExpenseResponse.dto'; @Controller('expenses') @ApiTags('Expenses') +@ApiExtraModels(PaginatedResponseDto, ExpenseResponseDto) export class ExpensesController { constructor(private readonly expensesApplication: ExpensesApplication) {} @@ -65,8 +74,25 @@ export class ExpensesController { /** * Get the expense transaction details. */ - @Get('') - @ApiOperation({ summary: 'Get the expense transaction details.' }) + @Get() + @ApiOperation({ summary: 'Get the expense transactions.' }) + @ApiResponse({ + status: 200, + description: 'The item list has been successfully retrieved.', + schema: { + allOf: [ + { $ref: getSchemaPath(PaginatedResponseDto) }, + { + properties: { + data: { + type: 'array', + items: { $ref: getSchemaPath(ExpenseResponseDto) }, + }, + }, + }, + ], + }, + }) public getExpenses(@Query() filterDTO: IExpensesFilter) { return this.expensesApplication.getExpenses(filterDTO); } @@ -77,6 +103,13 @@ export class ExpensesController { */ @Get(':id') @ApiOperation({ summary: 'Get the expense transaction details.' }) + @ApiResponse({ + status: 200, + description: 'The expense transaction have been successfully retrieved.', + schema: { + $ref: getSchemaPath(ExpenseResponseDto), + }, + }) public getExpense(@Param('id') expenseId: number) { return this.expensesApplication.getExpense(expenseId); } diff --git a/packages/server/src/modules/Expenses/dtos/ExpenseResponse.dto.ts b/packages/server/src/modules/Expenses/dtos/ExpenseResponse.dto.ts new file mode 100644 index 000000000..592231dbb --- /dev/null +++ b/packages/server/src/modules/Expenses/dtos/ExpenseResponse.dto.ts @@ -0,0 +1,208 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { + IsArray, + IsBoolean, + IsDate, + IsNumber, + IsOptional, + IsString, + ValidateNested, +} from 'class-validator'; + +export class ExpenseCategoryResponseDto { + @ApiProperty({ + example: 1, + description: 'The unique identifier of the expense category', + }) + id: number; + + @ApiProperty({ + example: 100, + description: 'The amount of the expense category', + }) + amount: number; + + @ApiProperty({ + example: 50, + description: 'The allocated cost amount of the expense category', + }) + allocatedCostAmount: number; + + @ApiProperty({ + example: 1, + description: 'The expense account ID associated with this category', + }) + expenseAccountId: number; + + @ApiProperty({ + example: 1, + description: 'The project ID associated with this category', + required: false, + }) + projectId?: number; + + @ApiProperty({ + example: 'Office supplies for Q1', + description: 'The description of the expense category', + }) + description: string; + + @ApiProperty({ + example: 50, + description: 'The unallocated cost amount of the expense category', + }) + unallocatedCostAmount: number; +} + +export class ExpenseResponseDto { + @ApiProperty({ + example: 1, + description: 'The unique identifier of the expense', + }) + id: number; + + @ApiProperty({ + example: 1000, + description: 'The total amount of the expense', + }) + totalAmount: number; + + @ApiProperty({ + example: 'USD', + description: 'The currency code of the expense', + }) + currencyCode: string; + + @ApiProperty({ + example: 1.2, + description: 'The exchange rate used for the expense', + }) + exchangeRate: number; + + @ApiProperty({ + example: 'Office supplies and equipment', + description: 'The description of the expense', + required: false, + }) + description?: string; + + @ApiProperty({ + example: 1, + description: 'The ID of the payment account used for this expense', + }) + paymentAccountId: number; + + @ApiProperty({ + example: 'EXP-2024-001', + description: 'The reference number of the expense', + }) + referenceNo: string; + + @ApiProperty({ + example: '2024-03-20T10:00:00Z', + description: 'The date when the expense was published', + required: false, + }) + publishedAt?: Date; + + @ApiProperty({ + example: 1, + description: 'The ID of the user who created the expense', + }) + userId: number; + + @ApiProperty({ + example: '2024-03-20T10:00:00Z', + description: 'The payment date of the expense', + }) + paymentDate: Date; + + @ApiProperty({ + example: 1, + description: 'The ID of the payee', + }) + payeeId: number; + + @ApiProperty({ + example: 800, + description: 'The landed cost amount of the expense', + }) + landedCostAmount: number; + + @ApiProperty({ + example: 200, + description: 'The allocated cost amount of the expense', + }) + allocatedCostAmount: number; + + @ApiProperty({ + example: 0, + description: 'The invoiced amount of the expense', + }) + invoicedAmount: number; + + @ApiProperty({ + example: 1, + description: 'The ID of the branch associated with the expense', + }) + branchId: number; + + @ApiProperty({ + example: '2024-03-20T10:00:00Z', + description: 'The creation date of the expense', + }) + createdAt: Date; + + @ApiProperty({ + example: true, + description: 'Whether the expense is published', + }) + isPublished: boolean; + + @ApiProperty({ + example: 200, + description: 'The unallocated cost amount of the expense', + }) + unallocatedCostAmount: number; + + @ApiProperty({ + example: 1200, + description: + 'The local amount of the expense (total amount * exchange rate)', + }) + localAmount: number; + + @ApiProperty({ + example: 960, + description: 'The local landed cost amount of the expense', + }) + localLandedCostAmount: number; + + @ApiProperty({ + example: 240, + description: 'The local allocated cost amount of the expense', + }) + localAllocatedCostAmount: number; + + @ApiProperty({ + example: 240, + description: 'The local unallocated cost amount of the expense', + }) + localUnallocatedCostAmount: number; + + @ApiProperty({ + example: 1000, + description: 'The billable amount of the expense', + }) + billableAmount: number; + + @ApiProperty({ + type: [ExpenseCategoryResponseDto], + description: 'The categories associated with this expense', + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => ExpenseCategoryResponseDto) + categories: ExpenseCategoryResponseDto[]; +} diff --git a/packages/server/src/modules/Items/Item.controller.ts b/packages/server/src/modules/Items/Item.controller.ts index 82b2a1cb4..1a46fd444 100644 --- a/packages/server/src/modules/Items/Item.controller.ts +++ b/packages/server/src/modules/Items/Item.controller.ts @@ -26,11 +26,13 @@ import { import { CreateItemDto, EditItemDto } from './dtos/Item.dto'; import { GetItemsQueryDto } from './dtos/GetItemsQuery.dto'; import { ItemResponseDto } from './dtos/itemResponse.dto'; +import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto'; @Controller('/items') @ApiTags('Items') @UseGuards(SubscriptionGuard) @ApiExtraModels(ItemResponseDto) +@ApiExtraModels(PaginatedResponseDto) export class ItemsController extends TenantController { constructor(private readonly itemsApplication: ItemsApplicationService) { super(); @@ -41,6 +43,19 @@ export class ItemsController extends TenantController { @ApiResponse({ status: 200, description: 'The item list has been successfully retrieved.', + schema: { + allOf: [ + { $ref: getSchemaPath(PaginatedResponseDto) }, + { + properties: { + data: { + type: 'array', + items: { $ref: getSchemaPath(ItemResponseDto) }, + }, + }, + }, + ], + }, }) @ApiQuery({ name: 'customViewId', diff --git a/packages/server/src/modules/WarehousesTransfers/WarehouseTransfers.controller.ts b/packages/server/src/modules/WarehousesTransfers/WarehouseTransfers.controller.ts index 815785c27..3b4310090 100644 --- a/packages/server/src/modules/WarehousesTransfers/WarehouseTransfers.controller.ts +++ b/packages/server/src/modules/WarehousesTransfers/WarehouseTransfers.controller.ts @@ -9,16 +9,25 @@ import { Query, Inject, } from '@nestjs/common'; -import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { + ApiExtraModels, + ApiOperation, + ApiResponse, + ApiTags, + getSchemaPath, +} from '@nestjs/swagger'; import { WarehouseTransferApplication } from './WarehouseTransferApplication'; import { CreateWarehouseTransferDto, EditWarehouseTransferDto, } from './dtos/WarehouseTransfer.dto'; import { GetWarehouseTransfersQueryDto } from '../Warehouses/dtos/GetWarehouseTransfersQuery.dto'; +import { WarehouseTransferResponseDto } from './dtos/WarehouseTransferResponse.dto'; +import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto'; @Controller('warehouse-transfers') @ApiTags('Warehouse Transfers') +@ApiExtraModels(WarehouseTransferResponseDto, PaginatedResponseDto) export class WarehouseTransfersController { /** * @param {WarehouseTransferApplication} warehouseTransferApplication - Warehouse transfer application. @@ -129,6 +138,19 @@ export class WarehouseTransfersController { status: 200, description: 'The warehouse transfer transactions have been retrieved successfully.', + schema: { + allOf: [ + { $ref: getSchemaPath(PaginatedResponseDto) }, + { + properties: { + data: { + type: 'array', + items: { $ref: getSchemaPath(WarehouseTransferResponseDto) }, + }, + }, + }, + ], + }, }) async getWarehousesTransfers(@Query() query: GetWarehouseTransfersQueryDto) { const { warehousesTransfers, pagination, filter } = @@ -150,6 +172,9 @@ export class WarehouseTransfersController { status: 200, description: 'The warehouse transfer transaction details have been retrieved successfully.', + schema: { + $ref: getSchemaPath(WarehouseTransferResponseDto), + }, }) async getWarehouseTransfer(@Param('id') id: number) { const warehouseTransfer = diff --git a/packages/server/src/modules/WarehousesTransfers/dtos/WarehouseTransferResponse.dto.ts b/packages/server/src/modules/WarehousesTransfers/dtos/WarehouseTransferResponse.dto.ts new file mode 100644 index 000000000..7056aa194 --- /dev/null +++ b/packages/server/src/modules/WarehousesTransfers/dtos/WarehouseTransferResponse.dto.ts @@ -0,0 +1,151 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; + +export class WarehouseTransferEntryResponseDto { + @ApiProperty({ + description: 'The ID of the warehouse transfer entry', + example: 1, + }) + id: number; + + @ApiProperty({ + description: 'The ID of the item being transferred', + example: 1, + }) + itemId: number; + + @ApiProperty({ + description: 'The quantity of items being transferred', + example: 100, + }) + quantity: number; + + @ApiProperty({ + description: 'The cost per unit of the item', + example: 10.5, + }) + cost: number; + + @ApiProperty({ + description: 'The total cost of the transfer entry', + example: 1050.0, + }) + total: number; + + @ApiProperty({ + description: 'The formatted quantity of items being transferred', + example: '100.00', + }) + formattedQuantity: string; + + @ApiProperty({ + description: 'The formatted cost per unit of the item', + example: '$10.50', + }) + formattedCost: string; + + @ApiProperty({ + description: 'The formatted total cost of the transfer entry', + example: '$1,050.00', + }) + formattedTotal: string; + + @ApiProperty({ + description: 'The item details', + type: 'object', + }) + item: any; +} + +export class WarehouseTransferResponseDto { + @ApiProperty({ + description: 'The ID of the warehouse transfer', + example: 1, + }) + id: number; + + @ApiProperty({ + description: 'The date of the warehouse transfer', + example: '2024-03-20', + }) + date: Date; + + @ApiProperty({ + description: 'The formatted date of the warehouse transfer', + example: 'Mar 20, 2024', + }) + formattedDate: string; + + @ApiProperty({ + description: 'The transaction number of the warehouse transfer', + example: 'WT-2024-001', + }) + transactionNumber: string; + + @ApiProperty({ + description: 'The ID of the source warehouse', + example: 1, + }) + fromWarehouseId: number; + + @ApiProperty({ + description: 'The ID of the destination warehouse', + example: 2, + }) + toWarehouseId: number; + + @ApiProperty({ + description: 'The date when the transfer was initiated', + example: '2024-03-20T10:00:00Z', + }) + transferInitiatedAt: Date; + + @ApiProperty({ + description: 'The date when the transfer was delivered', + example: '2024-03-21T15:00:00Z', + }) + transferDeliveredAt: Date; + + @ApiProperty({ + description: 'Whether the transfer has been initiated', + example: true, + }) + isInitiated: boolean; + + @ApiProperty({ + description: 'Whether the transfer has been completed', + example: true, + }) + isTransferred: boolean; + + @ApiProperty({ + description: 'The source warehouse details', + type: 'object', + }) + fromWarehouse: any; + + @ApiProperty({ + description: 'The destination warehouse details', + type: 'object', + }) + toWarehouse: any; + + @ApiProperty({ + description: 'The entries of the warehouse transfer', + type: [WarehouseTransferEntryResponseDto], + }) + @Type(() => WarehouseTransferEntryResponseDto) + entries: WarehouseTransferEntryResponseDto[]; + + @ApiProperty({ + description: 'The creation date of the warehouse transfer', + example: '2024-03-20T09:00:00Z', + }) + createdAt: Date; + + @ApiProperty({ + description: 'The last update date of the warehouse transfer', + example: '2024-03-21T15:00:00Z', + }) + updatedAt: Date; +}