feat: document more endpoints

This commit is contained in:
Ahmed Bouhuolia
2025-06-16 23:40:12 +02:00
parent e057b4e2f0
commit f624cf7ae6
8 changed files with 629 additions and 5 deletions

View File

@@ -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<TData> {
@ApiProperty({
description: 'Pagination metadata',
type: Pagination,
})
pagination: Pagination;
data: TData[];
}

View File

@@ -7,13 +7,25 @@ import {
Post, Post,
Query, Query,
} from '@nestjs/common'; } 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 { BankingTransactionsApplication } from '../BankingTransactionsApplication.service';
import { CreateBankTransactionDto } from '../dtos/CreateBankTransaction.dto'; import { CreateBankTransactionDto } from '../dtos/CreateBankTransaction.dto';
import { GetBankTransactionsQueryDto } from '../dtos/GetBankTranasctionsQuery.dto'; import { GetBankTransactionsQueryDto } from '../dtos/GetBankTranasctionsQuery.dto';
import { BankTransactionResponseDto } from '../dtos/BankTransactionResponse.dto';
import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto';
@Controller('banking/transactions') @Controller('banking/transactions')
@ApiTags('Banking Transactions') @ApiTags('Banking Transactions')
@ApiExtraModels(BankTransactionResponseDto, PaginatedResponseDto)
export class BankingTransactionsController { export class BankingTransactionsController {
constructor( constructor(
private readonly bankingTransactionsApplication: BankingTransactionsApplication, private readonly bankingTransactionsApplication: BankingTransactionsApplication,
@@ -24,6 +36,21 @@ export class BankingTransactionsController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Returns a list of bank account transactions', description: 'Returns a list of bank account transactions',
schema: {
allOf: [
{
$ref: getSchemaPath(PaginatedResponseDto),
},
{
properties: {
data: {
type: 'array',
items: { $ref: getSchemaPath(BankTransactionResponseDto) },
},
},
},
],
},
}) })
@ApiQuery({ @ApiQuery({
name: 'page', name: 'page',
@@ -89,6 +116,9 @@ export class BankingTransactionsController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'Returns the bank transaction details', description: 'Returns the bank transaction details',
schema: {
$ref: getSchemaPath(BankTransactionResponseDto),
},
}) })
@ApiResponse({ @ApiResponse({
status: 404, status: 404,

View File

@@ -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;
}

View File

@@ -10,11 +10,20 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { ExpensesApplication } from './ExpensesApplication.service'; import { ExpensesApplication } from './ExpensesApplication.service';
import { IExpensesFilter } from './Expenses.types'; 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 { CreateExpenseDto, EditExpenseDto } from './dtos/Expense.dto';
import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto';
import { ExpenseResponseDto } from './dtos/ExpenseResponse.dto';
@Controller('expenses') @Controller('expenses')
@ApiTags('Expenses') @ApiTags('Expenses')
@ApiExtraModels(PaginatedResponseDto, ExpenseResponseDto)
export class ExpensesController { export class ExpensesController {
constructor(private readonly expensesApplication: ExpensesApplication) {} constructor(private readonly expensesApplication: ExpensesApplication) {}
@@ -65,8 +74,25 @@ export class ExpensesController {
/** /**
* Get the expense transaction details. * Get the expense transaction details.
*/ */
@Get('') @Get()
@ApiOperation({ summary: 'Get the expense transaction details.' }) @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) { public getExpenses(@Query() filterDTO: IExpensesFilter) {
return this.expensesApplication.getExpenses(filterDTO); return this.expensesApplication.getExpenses(filterDTO);
} }
@@ -77,6 +103,13 @@ export class ExpensesController {
*/ */
@Get(':id') @Get(':id')
@ApiOperation({ summary: 'Get the expense transaction details.' }) @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) { public getExpense(@Param('id') expenseId: number) {
return this.expensesApplication.getExpense(expenseId); return this.expensesApplication.getExpense(expenseId);
} }

View File

@@ -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[];
}

View File

@@ -26,11 +26,13 @@ import {
import { CreateItemDto, EditItemDto } from './dtos/Item.dto'; import { CreateItemDto, EditItemDto } from './dtos/Item.dto';
import { GetItemsQueryDto } from './dtos/GetItemsQuery.dto'; import { GetItemsQueryDto } from './dtos/GetItemsQuery.dto';
import { ItemResponseDto } from './dtos/itemResponse.dto'; import { ItemResponseDto } from './dtos/itemResponse.dto';
import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto';
@Controller('/items') @Controller('/items')
@ApiTags('Items') @ApiTags('Items')
@UseGuards(SubscriptionGuard) @UseGuards(SubscriptionGuard)
@ApiExtraModels(ItemResponseDto) @ApiExtraModels(ItemResponseDto)
@ApiExtraModels(PaginatedResponseDto)
export class ItemsController extends TenantController { export class ItemsController extends TenantController {
constructor(private readonly itemsApplication: ItemsApplicationService) { constructor(private readonly itemsApplication: ItemsApplicationService) {
super(); super();
@@ -41,6 +43,19 @@ export class ItemsController extends TenantController {
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
description: 'The item list has been successfully retrieved.', description: 'The item list has been successfully retrieved.',
schema: {
allOf: [
{ $ref: getSchemaPath(PaginatedResponseDto) },
{
properties: {
data: {
type: 'array',
items: { $ref: getSchemaPath(ItemResponseDto) },
},
},
},
],
},
}) })
@ApiQuery({ @ApiQuery({
name: 'customViewId', name: 'customViewId',

View File

@@ -9,16 +9,25 @@ import {
Query, Query,
Inject, Inject,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import {
ApiExtraModels,
ApiOperation,
ApiResponse,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { WarehouseTransferApplication } from './WarehouseTransferApplication'; import { WarehouseTransferApplication } from './WarehouseTransferApplication';
import { import {
CreateWarehouseTransferDto, CreateWarehouseTransferDto,
EditWarehouseTransferDto, EditWarehouseTransferDto,
} from './dtos/WarehouseTransfer.dto'; } from './dtos/WarehouseTransfer.dto';
import { GetWarehouseTransfersQueryDto } from '../Warehouses/dtos/GetWarehouseTransfersQuery.dto'; import { GetWarehouseTransfersQueryDto } from '../Warehouses/dtos/GetWarehouseTransfersQuery.dto';
import { WarehouseTransferResponseDto } from './dtos/WarehouseTransferResponse.dto';
import { PaginatedResponseDto } from '@/common/dtos/PaginatedResults.dto';
@Controller('warehouse-transfers') @Controller('warehouse-transfers')
@ApiTags('Warehouse Transfers') @ApiTags('Warehouse Transfers')
@ApiExtraModels(WarehouseTransferResponseDto, PaginatedResponseDto)
export class WarehouseTransfersController { export class WarehouseTransfersController {
/** /**
* @param {WarehouseTransferApplication} warehouseTransferApplication - Warehouse transfer application. * @param {WarehouseTransferApplication} warehouseTransferApplication - Warehouse transfer application.
@@ -129,6 +138,19 @@ export class WarehouseTransfersController {
status: 200, status: 200,
description: description:
'The warehouse transfer transactions have been retrieved successfully.', '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) { async getWarehousesTransfers(@Query() query: GetWarehouseTransfersQueryDto) {
const { warehousesTransfers, pagination, filter } = const { warehousesTransfers, pagination, filter } =
@@ -150,6 +172,9 @@ export class WarehouseTransfersController {
status: 200, status: 200,
description: description:
'The warehouse transfer transaction details have been retrieved successfully.', 'The warehouse transfer transaction details have been retrieved successfully.',
schema: {
$ref: getSchemaPath(WarehouseTransferResponseDto),
},
}) })
async getWarehouseTransfer(@Param('id') id: number) { async getWarehouseTransfer(@Param('id') id: number) {
const warehouseTransfer = const warehouseTransfer =

View File

@@ -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;
}