feat(server): endpoints swagger docs

This commit is contained in:
Ahmed Bouhuolia
2025-06-30 16:30:55 +02:00
parent 83e698acf3
commit 9f6e9e85a5
23 changed files with 1248 additions and 23 deletions

View File

@@ -85,9 +85,7 @@ export class AccountTransformer extends Transformer {
* @returns {boolean}
*/
protected isFeedsPaused = (account: Account): boolean => {
// return account.plaidItem?.isPaused || false;
return false;
return account.plaidItem?.isPaused || false;
};
/**

View File

@@ -11,7 +11,7 @@ import {
import { AccountsApplication } from './AccountsApplication.service';
import { CreateAccountDTO } from './CreateAccount.dto';
import { EditAccountDTO } from './EditAccount.dto';
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
import { IAccountsFilter } from './Accounts.types';
import {
ApiExtraModels,
ApiOperation,
@@ -22,11 +22,14 @@ import {
} from '@nestjs/swagger';
import { AccountResponseDto } from './dtos/AccountResponse.dto';
import { AccountTypeResponseDto } from './dtos/AccountTypeResponse.dto';
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
import { GetAccountTransactionsQueryDto } from './dtos/GetAccountTransactionsQuery.dto';
@Controller('accounts')
@ApiTags('Accounts')
@ApiExtraModels(AccountResponseDto)
@ApiExtraModels(AccountTypeResponseDto)
@ApiExtraModels(GetAccountTransactionResponseDto)
export class AccountsController {
constructor(private readonly accountsApplication: AccountsApplication) {}
@@ -132,8 +135,16 @@ export class AccountsController {
@ApiResponse({
status: 200,
description: 'The account transactions have been successfully retrieved.',
schema: {
type: 'array',
items: {
$ref: getSchemaPath(GetAccountTransactionResponseDto),
},
},
})
async getAccountTransactions(@Query() filter: IAccountsTransactionsFilter) {
async getAccountTransactions(
@Query() filter: GetAccountTransactionsQueryDto,
) {
return this.accountsApplication.getAccountsTransactions(filter);
}

View File

@@ -10,13 +10,10 @@ import { GetAccount } from './GetAccount.service';
import { ActivateAccount } from './ActivateAccount.service';
import { GetAccountTypesService } from './GetAccountTypes.service';
import { GetAccountTransactionsService } from './GetAccountTransactions.service';
import {
IAccountsFilter,
IAccountsTransactionsFilter,
IGetAccountTransactionPOJO,
} from './Accounts.types';
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
import { GetAccountsService } from './GetAccounts.service';
import { IFilterMeta } from '@/interfaces/Model';
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
@Injectable()
export class AccountsApplication {
@@ -127,7 +124,7 @@ export class AccountsApplication {
*/
public getAccountsTransactions = (
filter: IAccountsTransactionsFilter,
): Promise<IGetAccountTransactionPOJO[]> => {
): Promise<Array<GetAccountTransactionResponseDto>> => {
return this.getAccountTransactionsService.getAccountsTransactions(filter);
};
}

View File

@@ -1,6 +1,5 @@
import { Knex } from 'knex';
import { Inject, Injectable } from '@nestjs/common';
// import { IAccountEventDeletedPayload } from '@/interfaces';
import { CommandAccountValidators } from './CommandAccountValidators.service';
import { Account } from './models/Account.model';
import { EventEmitter2 } from '@nestjs/event-emitter';
@@ -8,6 +7,7 @@ import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
import { events } from '@/common/events/events';
import { IAccountEventDeletedPayload } from './Accounts.types';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
import { ERRORS } from './constants';
@Injectable()
export class DeleteAccount {
@@ -70,8 +70,12 @@ export class DeleteAccount {
await this.unassociateChildrenAccountsFromParent(accountId, trx);
// Deletes account by the given id.
await this.accountModel().query(trx).deleteById(accountId);
await this.accountModel()
.query(trx)
.findById(accountId)
.deleteIfNoRelations({
type: ERRORS.ACCOUNT_HAS_ASSOCIATED_TRANSACTIONS,
});
// Triggers `onAccountDeleted` event.
await this.eventEmitter.emitAsync(events.accounts.onDeleted, {
accountId,

View File

@@ -8,6 +8,7 @@ import { Account } from './models/Account.model';
import { Inject, Injectable } from '@nestjs/common';
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
@Injectable()
export class GetAccountTransactionsService {
@@ -29,7 +30,7 @@ export class GetAccountTransactionsService {
*/
public getAccountsTransactions = async (
filter: IAccountsTransactionsFilter,
): Promise<IGetAccountTransactionPOJO[]> => {
): Promise<Array<GetAccountTransactionResponseDto>> => {
// Retrieve the given account or throw not found error.
if (filter.accountId) {
await this.account().query().findById(filter.accountId).throwIfNotFound();

View File

@@ -0,0 +1,114 @@
import { ApiProperty } from '@nestjs/swagger';
export class GetAccountTransactionResponseDto {
/**
* The transaction date (ISO string or Date).
*/
@ApiProperty({
description: 'The transaction date (ISO string or Date)',
example: '2024-01-01',
})
date: string | Date;
/**
* The formatted transaction date (string).
*/
@ApiProperty({
description: 'The formatted transaction date',
example: '01 Jan 2024',
})
formattedDate: string;
/**
* The transaction type (referenceType from model).
*/
@ApiProperty({
description: 'The transaction type (referenceType from model)',
example: 'INVOICE',
})
transactionType: string;
/**
* The transaction id (referenceId from model).
*/
@ApiProperty({
description: 'The transaction id (referenceId from model)',
example: 123,
})
transactionId: number;
/**
* The formatted transaction type (translated string).
*/
@ApiProperty({
description: 'The formatted transaction type (translated string)',
example: 'Invoice',
})
transactionTypeFormatted: string;
/**
* The credit amount (number).
*/
@ApiProperty({ description: 'The credit amount', example: 100 })
credit: number;
/**
* The debit amount (number).
*/
@ApiProperty({ description: 'The debit amount', example: 50 })
debit: number;
/**
* The formatted credit amount (string, e.g. currency formatted).
*/
@ApiProperty({
description: 'The formatted credit amount (e.g. currency formatted)',
example: '100.00 USD',
})
formattedCredit: string;
/**
* The formatted debit amount (string, e.g. currency formatted).
*/
@ApiProperty({
description: 'The formatted debit amount (e.g. currency formatted)',
example: '50.00 USD',
})
formattedDebit: string;
/**
* The foreign currency credit (number, credit * exchangeRate).
*/
@ApiProperty({
description: 'The foreign currency credit (credit * exchangeRate)',
example: 120,
})
fcCredit: number;
/**
* The foreign currency debit (number, debit * exchangeRate).
*/
@ApiProperty({
description: 'The foreign currency debit (debit * exchangeRate)',
example: 60,
})
fcDebit: number;
/**
* The formatted foreign currency credit (string).
*/
@ApiProperty({
description: 'The formatted foreign currency credit',
example: '120.00 EUR',
})
formattedFcCredit: string;
/**
* The formatted foreign currency debit (string).
*/
@ApiProperty({
description: 'The formatted foreign currency debit',
example: '60.00 EUR',
})
formattedFcDebit: string;
}

View File

@@ -0,0 +1,23 @@
import { IsInt, IsOptional } from 'class-validator';
import { ApiPropertyOptional } from '@nestjs/swagger';
import { ToNumber } from '@/common/decorators/Validators';
export class GetAccountTransactionsQueryDto {
@ApiPropertyOptional({
type: Number,
description: 'ID of the account to fetch transactions for',
})
@IsOptional()
@IsInt()
@ToNumber()
accountId?: number;
@ApiPropertyOptional({
type: Number,
description: 'Maximum number of transactions to return',
})
@IsOptional()
@IsInt()
@ToNumber()
limit?: number;
}