diff --git a/packages/server/src/modules/App/App.module.ts b/packages/server/src/modules/App/App.module.ts index 2342e762f..8fffeab7f 100644 --- a/packages/server/src/modules/App/App.module.ts +++ b/packages/server/src/modules/App/App.module.ts @@ -183,9 +183,9 @@ import { BankingPlaidModule } from '../BankingPlaid/BankingPlaid.module'; LedgerModule, BankAccountsModule, BankRulesModule, - BankingTransactionsModule, BankingTransactionsExcludeModule, BankingTransactionsRegonizeModule, + BankingTransactionsModule, BankingMatchingModule, BankingPlaidModule, TransactionsLockingModule, diff --git a/packages/server/src/modules/BankingTranasctionsRegonize/BankingRecognizedTransactions.controller.ts b/packages/server/src/modules/BankingTranasctionsRegonize/BankingRecognizedTransactions.controller.ts new file mode 100644 index 000000000..17a2ab8eb --- /dev/null +++ b/packages/server/src/modules/BankingTranasctionsRegonize/BankingRecognizedTransactions.controller.ts @@ -0,0 +1,26 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { BankingTransactionsApplication } from '../BankingTransactions/BankingTransactionsApplication.service'; +import { ApiTags } from '@nestjs/swagger'; +import { RecognizedTransactionsApplication } from './RecognizedTransactions.application'; + +@Controller('banking/recognized') +@ApiTags('banking-recognized') +export class BankingRecognizedTransactionsController { + constructor( + private readonly recognizedTransactionsApplication: RecognizedTransactionsApplication, + ) {} + + @Get(':recognizedTransactionId') + async getRecognizedTransaction( + @Param('recognizedTransactionId') recognizedTransactionId: number, + ) { + return this.recognizedTransactionsApplication.getRecognizedTransaction( + Number(recognizedTransactionId), + ); + } + + @Get() + async getRecognizedTransactions(@Query() query: any) { + return this.recognizedTransactionsApplication.getRecognizedTransactions(query); + } +} diff --git a/packages/server/src/modules/BankingTranasctionsRegonize/BankingTransactionsRegonize.module.ts b/packages/server/src/modules/BankingTranasctionsRegonize/BankingTransactionsRegonize.module.ts index 5ffd15015..9e7fcc10a 100644 --- a/packages/server/src/modules/BankingTranasctionsRegonize/BankingTransactionsRegonize.module.ts +++ b/packages/server/src/modules/BankingTranasctionsRegonize/BankingTransactionsRegonize.module.ts @@ -7,6 +7,10 @@ import { RecognizeTranasctionsService } from './commands/RecognizeTranasctions.s import { TriggerRecognizedTransactionsSubscriber } from './events/TriggerRecognizedTransactions'; import { BankingTransactionsModule } from '../BankingTransactions/BankingTransactions.module'; import { BankRulesModule } from '../BankRules/BankRules.module'; +import { BankingRecognizedTransactionsController } from './BankingRecognizedTransactions.controller'; +import { RecognizedTransactionsApplication } from './RecognizedTransactions.application'; +import { GetRecognizedTransactionsService } from './GetRecongizedTransactions'; +import { GetRecognizedTransactionService } from './queries/GetRecognizedTransaction.service'; const models = [RegisterTenancyModel(RecognizedBankTransaction)]; @@ -17,10 +21,13 @@ const models = [RegisterTenancyModel(RecognizedBankTransaction)]; ...models, ], providers: [ + RecognizedTransactionsApplication, + GetRecognizedTransactionsService, GetAutofillCategorizeTransactionService, RevertRecognizedTransactionsService, RecognizeTranasctionsService, TriggerRecognizedTransactionsSubscriber, + GetRecognizedTransactionService, ], exports: [ ...models, @@ -28,5 +35,6 @@ const models = [RegisterTenancyModel(RecognizedBankTransaction)]; RevertRecognizedTransactionsService, RecognizeTranasctionsService, ], + controllers: [BankingRecognizedTransactionsController], }) export class BankingTransactionsRegonizeModule {} diff --git a/packages/server/src/modules/BankingTransactions/queries/GetRecongizedTransactions.ts b/packages/server/src/modules/BankingTranasctionsRegonize/GetRecongizedTransactions.ts similarity index 76% rename from packages/server/src/modules/BankingTransactions/queries/GetRecongizedTransactions.ts rename to packages/server/src/modules/BankingTranasctionsRegonize/GetRecongizedTransactions.ts index 94e1c5d9a..559f44730 100644 --- a/packages/server/src/modules/BankingTransactions/queries/GetRecongizedTransactions.ts +++ b/packages/server/src/modules/BankingTranasctionsRegonize/GetRecongizedTransactions.ts @@ -1,8 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; -import { GetRecognizedTransactionTransformer } from './GetRecognizedTransactionTransformer'; -import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction'; +import { GetRecognizedTransactionTransformer } from './queries/GetRecognizedTransactionTransformer'; +import { UncategorizedBankTransaction } from '../BankingTransactions/models/UncategorizedBankTransaction'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; -import { IGetRecognizedTransactionsQuery } from '../types/BankingTransactions.types'; +import { IGetRecognizedTransactionsQuery } from '../BankingTransactions/types/BankingTransactions.types'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @Injectable() export class GetRecognizedTransactionsService { @@ -10,7 +11,7 @@ export class GetRecognizedTransactionsService { private readonly transformer: TransformerInjectable, @Inject(UncategorizedBankTransaction.name) - private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction, + private readonly uncategorizedBankTransactionModel: TenantModelProxy, ) {} /** @@ -25,7 +26,7 @@ export class GetRecognizedTransactionsService { ...filter, }; const { results, pagination } = - await this.uncategorizedBankTransactionModel.query() + await this.uncategorizedBankTransactionModel().query() .onBuild((q) => { q.withGraphFetched('recognizedTransaction.assignAccount'); q.withGraphFetched('recognizedTransaction.bankRule'); diff --git a/packages/server/src/modules/BankingTranasctionsRegonize/RecognizedTransactions.application.ts b/packages/server/src/modules/BankingTranasctionsRegonize/RecognizedTransactions.application.ts new file mode 100644 index 000000000..df9013ca4 --- /dev/null +++ b/packages/server/src/modules/BankingTranasctionsRegonize/RecognizedTransactions.application.ts @@ -0,0 +1,70 @@ +import { Knex } from 'knex'; +import { Injectable } from '@nestjs/common'; +import { GetRecognizedTransactionsService } from './GetRecongizedTransactions'; +import { GetRecognizedTransactionService } from './queries/GetRecognizedTransaction.service'; +import { RevertRecognizedTransactionsService } from './commands/RevertRecognizedTransactions.service'; +import { GetAutofillCategorizeTransactionService } from './queries/GetAutofillCategorizeTransaction.service'; +import { IGetRecognizedTransactionsQuery } from '../BankingTransactions/types/BankingTransactions.types'; +import { RevertRecognizedTransactionsCriteria } from './_types'; + +@Injectable() +export class RecognizedTransactionsApplication { + constructor( + private readonly getRecognizedTransactionsService: GetRecognizedTransactionsService, + private readonly getRecognizedTransactionService: GetRecognizedTransactionService, + private readonly revertRecognizedTransactionsService: RevertRecognizedTransactionsService, + private readonly getAutofillCategorizeTransactionService: GetAutofillCategorizeTransactionService, + ) {} + + /** + * Retrieves the recognized transactions based on the provided filter. + * @param {IGetRecognizedTransactionsQuery} filter - Filter criteria. + * @returns {Promise<{ data: any[], pagination: any }>} + */ + public getRecognizedTransactions(filter: IGetRecognizedTransactionsQuery) { + return this.getRecognizedTransactionsService.getRecognizedTranactions( + filter, + ); + } + + /** + * Retrieves a specific recognized transaction by ID. + * @param {number} recognizedTransactionId - The ID of the recognized transaction. + * @returns {Promise} + */ + public getRecognizedTransaction(recognizedTransactionId: number) { + return this.getRecognizedTransactionService.getRecognizedTransaction( + recognizedTransactionId, + ); + } + + /** + * Reverts a recognized transaction. + * @param {number} ruleId - The ID of the recognized transaction to revert. + * @param {RevertRecognizedTransactionsCriteria} transactionsCriteria - The criteria for the recognized transaction to revert. + * @param {Knex.Transaction} trx - The transaction to use for the revert operation. + * @returns {Promise} + */ + public revertRecognizedTransactions( + ruleId?: number | Array, + transactionsCriteria?: RevertRecognizedTransactionsCriteria, + trx?: Knex.Transaction, + ) { + return this.revertRecognizedTransactionsService.revertRecognizedTransactions( + ruleId, + transactionsCriteria, + trx, + ); + } + + /** + * Gets autofill categorize suggestions for a transaction. + * @param {number} uncategorizedTransactionId - The ID of the uncategorized transaction. + * @returns {Promise} + */ + public getAutofillCategorizeTransaction(uncategorizedTransactionId: number) { + return this.getAutofillCategorizeTransactionService.getAutofillCategorizeTransaction( + uncategorizedTransactionId, + ); + } +} diff --git a/packages/server/src/modules/BankingTransactions/queries/GetRecognizedTransaction.service.ts b/packages/server/src/modules/BankingTranasctionsRegonize/queries/GetRecognizedTransaction.service.ts similarity index 92% rename from packages/server/src/modules/BankingTransactions/queries/GetRecognizedTransaction.service.ts rename to packages/server/src/modules/BankingTranasctionsRegonize/queries/GetRecognizedTransaction.service.ts index 8000b60e4..c4aac1d06 100644 --- a/packages/server/src/modules/BankingTransactions/queries/GetRecognizedTransaction.service.ts +++ b/packages/server/src/modules/BankingTranasctionsRegonize/queries/GetRecognizedTransaction.service.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { GetRecognizedTransactionTransformer } from './GetRecognizedTransactionTransformer'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; -import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction'; +import { UncategorizedBankTransaction } from '../../BankingTransactions/models/UncategorizedBankTransaction'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; @Injectable() diff --git a/packages/server/src/modules/BankingTransactions/queries/GetRecognizedTransactionTransformer.ts b/packages/server/src/modules/BankingTranasctionsRegonize/queries/GetRecognizedTransactionTransformer.ts similarity index 100% rename from packages/server/src/modules/BankingTransactions/queries/GetRecognizedTransactionTransformer.ts rename to packages/server/src/modules/BankingTranasctionsRegonize/queries/GetRecognizedTransactionTransformer.ts diff --git a/packages/server/src/modules/BankingTransactions/BankingTransactions.controller.ts b/packages/server/src/modules/BankingTransactions/BankingTransactions.controller.ts deleted file mode 100644 index e4bd26e0d..000000000 --- a/packages/server/src/modules/BankingTransactions/BankingTransactions.controller.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Param, - Post, - Query, -} from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; -import { BankingTransactionsApplication } from './BankingTransactionsApplication.service'; -import { CreateBankTransactionDto } from './dtos/CreateBankTransaction.dto'; -import { GetBankTransactionsQueryDto } from './dtos/GetBankTranasctionsQuery.dto'; - -@Controller('banking/transactions') -@ApiTags('banking-transactions') -export class BankingTransactionsController { - constructor( - private readonly bankingTransactionsApplication: BankingTransactionsApplication, - ) {} - - @Get() - async getBankAccountTransactions( - @Query() query: GetBankTransactionsQueryDto, - ) { - return this.bankingTransactionsApplication.getBankAccountTransactions( - query, - ); - } - - @Post() - async createTransaction(@Body() transactionDTO: CreateBankTransactionDto) { - return this.bankingTransactionsApplication.createTransaction( - transactionDTO, - ); - } - - @Delete(':id') - async deleteTransaction(@Param('id') transactionId: string) { - return this.bankingTransactionsApplication.deleteTransaction( - Number(transactionId), - ); - } - - @Get(':id') - async getTransaction(@Param('id') transactionId: string) { - return this.bankingTransactionsApplication.getTransaction( - Number(transactionId), - ); - } -} diff --git a/packages/server/src/modules/BankingTransactions/BankingTransactions.module.ts b/packages/server/src/modules/BankingTransactions/BankingTransactions.module.ts index 38d046fc9..d1176a594 100644 --- a/packages/server/src/modules/BankingTransactions/BankingTransactions.module.ts +++ b/packages/server/src/modules/BankingTransactions/BankingTransactions.module.ts @@ -19,13 +19,18 @@ import { CommandBankTransactionValidator } from './commands/CommandCasflowValida import { BranchTransactionDTOTransformer } from '../Branches/integrations/BranchTransactionDTOTransform'; import { BranchesModule } from '../Branches/Branches.module'; import { RemovePendingUncategorizedTransaction } from './commands/RemovePendingUncategorizedTransaction.service'; -import { BankingTransactionsController } from './BankingTransactions.controller'; +import { BankingTransactionsController } from './controllers/BankingTransactions.controller'; import { GetBankAccountsService } from './queries/GetBankAccounts.service'; import { DynamicListModule } from '../DynamicListing/DynamicList.module'; import { BankAccount } from './models/BankAccount'; import { LedgerModule } from '../Ledger/Ledger.module'; import { GetBankAccountTransactionsService } from './queries/GetBankAccountTransactions/GetBankAccountTransactions.service'; import { GetBankAccountTransactionsRepository } from './queries/GetBankAccountTransactions/GetBankAccountTransactionsRepo.service'; +import { GetUncategorizedTransactions } from './queries/GetUncategorizedTransactions'; +import { GetUncategorizedBankTransactionService } from './queries/GetUncategorizedBankTransaction.service'; +import { BankingUncategorizedTransactionsController } from './controllers/BankingUncategorizedTransactions.controller'; +import { BankingPendingTransactionsController } from './controllers/BankingPendingTransactions.controller'; +import { GetPendingBankAccountTransactions } from './queries/GetPendingBankAccountTransaction.service'; const models = [ RegisterTenancyModel(UncategorizedBankTransaction), @@ -42,7 +47,11 @@ const models = [ DynamicListModule, ...models, ], - controllers: [BankingTransactionsController], + controllers: [ + BankingTransactionsController, + BankingUncategorizedTransactionsController, + BankingPendingTransactionsController, + ], providers: [ BankTransactionAutoIncrement, BankTransactionGLEntriesService, @@ -61,6 +70,9 @@ const models = [ RemovePendingUncategorizedTransaction, GetBankAccountTransactionsRepository, GetBankAccountTransactionsService, + GetUncategorizedTransactions, + GetUncategorizedBankTransactionService, + GetPendingBankAccountTransactions ], exports: [...models, RemovePendingUncategorizedTransaction], }) diff --git a/packages/server/src/modules/BankingTransactions/BankingTransactionsApplication.service.ts b/packages/server/src/modules/BankingTransactions/BankingTransactionsApplication.service.ts index fbaeaca3f..ccb1cd528 100644 --- a/packages/server/src/modules/BankingTransactions/BankingTransactionsApplication.service.ts +++ b/packages/server/src/modules/BankingTransactions/BankingTransactionsApplication.service.ts @@ -9,6 +9,11 @@ import { import { GetBankAccountsService } from './queries/GetBankAccounts.service'; import { CreateBankTransactionDto } from './dtos/CreateBankTransaction.dto'; import { GetBankAccountTransactionsService } from './queries/GetBankAccountTransactions/GetBankAccountTransactions.service'; +import { GetUncategorizedTransactions } from './queries/GetUncategorizedTransactions'; +import { GetUncategorizedBankTransactionService } from './queries/GetUncategorizedBankTransaction.service'; +import { GetUncategorizedTransactionsQueryDto } from './dtos/GetUncategorizedTransactionsQuery.dto'; +import { GetPendingBankAccountTransactions } from './queries/GetPendingBankAccountTransaction.service'; +import { GetPendingTransactionsQueryDto } from './dtos/GetPendingTransactionsQuery.dto'; @Injectable() export class BankingTransactionsApplication { @@ -18,6 +23,9 @@ export class BankingTransactionsApplication { private readonly getCashflowTransactionService: GetBankTransactionService, private readonly getBankAccountsService: GetBankAccountsService, private readonly getBankAccountTransactionsService: GetBankAccountTransactionsService, + private readonly getBankAccountUncategorizedTransitionsService: GetUncategorizedTransactions, + private readonly getBankAccountUncategorizedTransactionService: GetUncategorizedBankTransactionService, + private readonly getPendingBankAccountTransactionsService: GetPendingBankAccountTransactions ) {} /** @@ -68,4 +76,37 @@ export class BankingTransactionsApplication { public getBankAccounts(filterDTO: IBankAccountsFilter) { return this.getBankAccountsService.getBankAccounts(filterDTO); } + + /** + * Retrieves the uncategorized cashflow transactions. + * @param {number} accountId - Account id. + * @param {IGetUncategorizedTransactionsQuery} query - Query. + */ + public getBankAccountUncategorizedTransactions( + accountId: number, + query: GetUncategorizedTransactionsQueryDto, + ) { + return this.getBankAccountUncategorizedTransitionsService.getTransactions( + accountId, + query, + ); + } + + /** + * Retrieves specific uncategorized cashflow transaction. + * @param {number} uncategorizedTransactionId - Uncategorized transaction id. + */ + public getUncategorizedTransaction(uncategorizedTransactionId: number) { + return this.getBankAccountUncategorizedTransactionService.getTransaction( + uncategorizedTransactionId, + ); + } + + /** + * Retrieves the pending bank account transactions. + * @param {GetPendingTransactionsQueryDto} filter - Pending transactions query. + */ + public getPendingBankAccountTransactions(filter?: GetPendingTransactionsQueryDto) { + return this.getPendingBankAccountTransactionsService.getPendingTransactions(filter); + } } diff --git a/packages/server/src/modules/BankingTransactions/controllers/BankingPendingTransactions.controller.ts b/packages/server/src/modules/BankingTransactions/controllers/BankingPendingTransactions.controller.ts new file mode 100644 index 000000000..ba051f2cb --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/controllers/BankingPendingTransactions.controller.ts @@ -0,0 +1,42 @@ +import { Controller, Get, Query } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger'; +import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service'; +import { GetPendingTransactionsQueryDto } from '../dtos/GetPendingTransactionsQuery.dto'; + +@Controller('banking/pending') +@ApiTags('banking-pending') +export class BankingPendingTransactionsController { + constructor( + private readonly bankingTransactionsApplication: BankingTransactionsApplication, + ) {} + + @Get() + @ApiOperation({ summary: 'Get pending bank account transactions' }) + @ApiResponse({ + status: 200, + description: 'Returns a list of pending bank account transactions', + }) + @ApiQuery({ + name: 'page', + required: false, + type: Number, + description: 'Page number for pagination', + }) + @ApiQuery({ + name: 'pageSize', + required: false, + type: Number, + description: 'Number of items per page', + }) + @ApiQuery({ + name: 'accountId', + required: false, + type: Number, + description: 'Filter by bank account ID', + }) + async getPendingTransactions(@Query() query: GetPendingTransactionsQueryDto) { + return this.bankingTransactionsApplication.getPendingBankAccountTransactions( + query, + ); + } +} diff --git a/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts b/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts new file mode 100644 index 000000000..f41703021 --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/controllers/BankingTransactions.controller.ts @@ -0,0 +1,108 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + Post, + Query, +} from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery, ApiBody } from '@nestjs/swagger'; +import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service'; +import { CreateBankTransactionDto } from '../dtos/CreateBankTransaction.dto'; +import { GetBankTransactionsQueryDto } from '../dtos/GetBankTranasctionsQuery.dto'; + +@Controller('banking/transactions') +@ApiTags('banking-transactions') +export class BankingTransactionsController { + constructor( + private readonly bankingTransactionsApplication: BankingTransactionsApplication, + ) {} + + @Get() + @ApiOperation({ summary: 'Get bank account transactions' }) + @ApiResponse({ + status: 200, + description: 'Returns a list of bank account transactions', + }) + @ApiQuery({ + name: 'page', + required: false, + type: Number, + description: 'Page number for pagination', + }) + @ApiQuery({ + name: 'pageSize', + required: false, + type: Number, + description: 'Number of items per page', + }) + async getBankAccountTransactions( + @Query() query: GetBankTransactionsQueryDto, + ) { + return this.bankingTransactionsApplication.getBankAccountTransactions( + query, + ); + } + + @Post() + @ApiOperation({ summary: 'Create a new bank transaction' }) + @ApiResponse({ + status: 201, + description: 'The bank transaction has been successfully created', + }) + @ApiResponse({ + status: 400, + description: 'Invalid input data', + }) + @ApiBody({ type: CreateBankTransactionDto }) + async createTransaction(@Body() transactionDTO: CreateBankTransactionDto) { + return this.bankingTransactionsApplication.createTransaction( + transactionDTO, + ); + } + + @Delete(':id') + @ApiOperation({ summary: 'Delete a bank transaction' }) + @ApiResponse({ + status: 200, + description: 'The bank transaction has been successfully deleted', + }) + @ApiResponse({ + status: 404, + description: 'Bank transaction not found', + }) + @ApiParam({ + name: 'id', + required: true, + type: String, + description: 'Bank transaction ID', + }) + async deleteTransaction(@Param('id') transactionId: string) { + return this.bankingTransactionsApplication.deleteTransaction( + Number(transactionId), + ); + } + + @Get(':id') + @ApiOperation({ summary: 'Get a specific bank transaction by ID' }) + @ApiResponse({ + status: 200, + description: 'Returns the bank transaction details', + }) + @ApiResponse({ + status: 404, + description: 'Bank transaction not found', + }) + @ApiParam({ + name: 'id', + required: true, + type: String, + description: 'Bank transaction ID', + }) + async getTransaction(@Param('id') transactionId: string) { + return this.bankingTransactionsApplication.getTransaction( + Number(transactionId), + ); + } +} diff --git a/packages/server/src/modules/BankingTransactions/controllers/BankingUncategorizedTransactions.controller.ts b/packages/server/src/modules/BankingTransactions/controllers/BankingUncategorizedTransactions.controller.ts new file mode 100644 index 000000000..287cbbbd4 --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/controllers/BankingUncategorizedTransactions.controller.ts @@ -0,0 +1,70 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger'; +import { GetUncategorizedTransactionsQueryDto } from '../dtos/GetUncategorizedTransactionsQuery.dto'; +import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service'; + +@Controller('banking/uncategorized') +@ApiTags('banking-uncategorized') +export class BankingUncategorizedTransactionsController { + constructor( + private readonly bankingTransactionsApplication: BankingTransactionsApplication, + ) {} + + @Get('accounts/:accountId') + @ApiOperation({ summary: 'Get uncategorized transactions for a specific bank account' }) + @ApiResponse({ + status: 200, + description: 'Returns a list of uncategorized transactions for the specified bank account', + }) + @ApiParam({ + name: 'accountId', + required: true, + type: Number, + description: 'Bank account ID', + }) + @ApiQuery({ + name: 'page', + required: false, + type: Number, + description: 'Page number for pagination', + }) + @ApiQuery({ + name: 'pageSize', + required: false, + type: Number, + description: 'Number of items per page', + }) + async getBankAccountUncategorizedTransactions( + @Param('accountId') accountId: number, + @Query() query: GetUncategorizedTransactionsQueryDto, + ) { + return this.bankingTransactionsApplication.getBankAccountUncategorizedTransactions( + accountId, + query, + ); + } + + @Get(':uncategorizedTransactionId') + @ApiOperation({ summary: 'Get a specific uncategorized transaction by ID' }) + @ApiResponse({ + status: 200, + description: 'Returns the uncategorized transaction details', + }) + @ApiResponse({ + status: 404, + description: 'Uncategorized transaction not found', + }) + @ApiParam({ + name: 'uncategorizedTransactionId', + required: true, + type: Number, + description: 'Uncategorized transaction ID', + }) + async getUncategorizedTransaction( + @Param('uncategorizedTransactionId') uncategorizedTransactionId: number, + ) { + return this.bankingTransactionsApplication.getUncategorizedTransaction( + Number(uncategorizedTransactionId), + ); + } +} diff --git a/packages/server/src/modules/BankingTransactions/dtos/GetBankTranasctionsQuery.dto.ts b/packages/server/src/modules/BankingTransactions/dtos/GetBankTranasctionsQuery.dto.ts index 11d8a13e1..8d8356103 100644 --- a/packages/server/src/modules/BankingTransactions/dtos/GetBankTranasctionsQuery.dto.ts +++ b/packages/server/src/modules/BankingTransactions/dtos/GetBankTranasctionsQuery.dto.ts @@ -6,23 +6,47 @@ import { } from 'class-validator'; import { NumberFormatQueryDto } from './NumberFormatQuery.dto'; import { Type } from 'class-transformer'; +import { ApiProperty } from '@nestjs/swagger'; export class GetBankTransactionsQueryDto { @IsOptional() @Type(() => Number) @IsNumber() + @ApiProperty({ + description: 'Page number for pagination', + required: false, + type: Number, + example: 1 + }) page: number; @IsOptional() @Type(() => Number) @IsNumber() + @ApiProperty({ + description: 'Number of items per page', + required: false, + type: Number, + example: 10 + }) pageSize: number; @IsNotEmpty() @Type(() => Number) @IsNumber() + @ApiProperty({ + description: 'Bank account ID', + required: true, + type: Number, + example: 1 + }) accountId: number; @IsOptional() + @ApiProperty({ + description: 'Number format options', + required: false, + type: NumberFormatQueryDto + }) numberFormat: NumberFormatQueryDto; } diff --git a/packages/server/src/modules/BankingTransactions/dtos/GetPendingTransactionsQuery.dto.ts b/packages/server/src/modules/BankingTransactions/dtos/GetPendingTransactionsQuery.dto.ts new file mode 100644 index 000000000..61e141ea6 --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/dtos/GetPendingTransactionsQuery.dto.ts @@ -0,0 +1,31 @@ +import { IsOptional } from "class-validator"; +import { ApiProperty } from "@nestjs/swagger"; + +export class GetPendingTransactionsQueryDto { + @IsOptional() + @ApiProperty({ + description: 'Page number for pagination', + required: false, + type: Number, + example: 1 + }) + page?: number; + + @IsOptional() + @ApiProperty({ + description: 'Number of items per page', + required: false, + type: Number, + example: 10 + }) + pageSize?: number; + + @IsOptional() + @ApiProperty({ + description: 'Filter by bank account ID', + required: false, + type: Number, + example: 1 + }) + accountId?: number; +} diff --git a/packages/server/src/modules/BankingTransactions/dtos/GetUncategorizedTransactionsQuery.dto.ts b/packages/server/src/modules/BankingTransactions/dtos/GetUncategorizedTransactionsQuery.dto.ts new file mode 100644 index 000000000..a06e4ac39 --- /dev/null +++ b/packages/server/src/modules/BankingTransactions/dtos/GetUncategorizedTransactionsQuery.dto.ts @@ -0,0 +1,58 @@ +import { IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class GetUncategorizedTransactionsQueryDto { + @IsOptional() + @ApiProperty({ + description: 'Page number for pagination', + required: false, + type: Number, + example: 1 + }) + page?: number; + + @IsOptional() + @ApiProperty({ + description: 'Number of items per page', + required: false, + type: Number, + example: 10 + }) + pageSize?: number; + + @IsOptional() + @ApiProperty({ + description: 'Minimum date for filtering transactions', + required: false, + type: Date, + example: '2023-01-01' + }) + minDate?: Date; + + @IsOptional() + @ApiProperty({ + description: 'Maximum date for filtering transactions', + required: false, + type: Date, + example: '2023-12-31' + }) + maxDate?: Date; + + @IsOptional() + @ApiProperty({ + description: 'Minimum amount for filtering transactions', + required: false, + type: Number, + example: 100 + }) + minAmount?: number; + + @IsOptional() + @ApiProperty({ + description: 'Maximum amount for filtering transactions', + required: false, + type: Number, + example: 1000 + }) + maxAmount?: number; +} diff --git a/packages/server/src/modules/BankingTransactions/queries/GetPendingBankAccountTransaction.service.ts b/packages/server/src/modules/BankingTransactions/queries/GetPendingBankAccountTransaction.service.ts index 5da6b2cc4..1f1363e36 100644 --- a/packages/server/src/modules/BankingTransactions/queries/GetPendingBankAccountTransaction.service.ts +++ b/packages/server/src/modules/BankingTransactions/queries/GetPendingBankAccountTransaction.service.ts @@ -2,6 +2,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { GetPendingBankAccountTransactionTransformer } from './GetPendingBankAccountTransactionTransformer'; import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; +import { GetPendingTransactionsQueryDto } from '../dtos/GetPendingTransactionsQuery.dto'; @Injectable() export class GetPendingBankAccountTransactions { @@ -9,40 +11,37 @@ export class GetPendingBankAccountTransactions { private readonly transformerService: TransformerInjectable, @Inject(UncategorizedBankTransaction.name) - private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction + private readonly uncategorizedBankTransactionModel: TenantModelProxy< + typeof UncategorizedBankTransaction + >, ) {} /** * Retrieves the given bank accounts pending transaction. - * @param {GetPendingTransactionsQuery} filter - Pending transactions query. + * @param {GetPendingTransactionsQueryDto} filter - Pending transactions query. */ - async getPendingTransactions(filter?: GetPendingTransactionsQuery) { + async getPendingTransactions(filter?: GetPendingTransactionsQueryDto) { const _filter = { - page: 1, + page: 1, pageSize: 20, ...filter, }; const { results, pagination } = - await this.uncategorizedBankTransactionModel.query() + await this.uncategorizedBankTransactionModel() + .query() .onBuild((q) => { q.modify('pending'); - if (_filter?.accountId) { - q.where('accountId', _filter.accountId); - } - }) - .pagination(_filter.page - 1, _filter.pageSize); + if (_filter?.accountId) { + q.where('accountId', _filter.accountId); + } + }) + .pagination(_filter.page - 1, _filter.pageSize); const data = await this.transformerService.transform( results, - new GetPendingBankAccountTransactionTransformer() + new GetPendingBankAccountTransactionTransformer(), ); return { data, pagination }; } } - -interface GetPendingTransactionsQuery { - page?: number; - pageSize?: number; - accountId?: number; -} diff --git a/packages/server/src/modules/BankingTransactions/queries/GetUncategorizedTransactions.ts b/packages/server/src/modules/BankingTransactions/queries/GetUncategorizedTransactions.ts index 67c8334c7..6bb5d0778 100644 --- a/packages/server/src/modules/BankingTransactions/queries/GetUncategorizedTransactions.ts +++ b/packages/server/src/modules/BankingTransactions/queries/GetUncategorizedTransactions.ts @@ -1,26 +1,45 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { initialize } from 'objection'; +import { Knex } from 'knex'; import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service'; import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction'; -import { Inject, Injectable } from '@nestjs/common'; import { UncategorizedTransactionTransformer } from '../../BankingCategorize/commands/UncategorizedTransaction.transformer'; -import { IGetUncategorizedTransactionsQuery } from '../types/BankingTransactions.types'; +import { GetUncategorizedTransactionsQueryDto } from '../dtos/GetUncategorizedTransactionsQuery.dto'; +import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; +import { TENANCY_DB_CONNECTION } from '@/modules/Tenancy/TenancyDB/TenancyDB.constants'; +import { Account } from '@/modules/Accounts/models/Account.model'; +import { RecognizedBankTransaction } from '@/modules/BankingTranasctionsRegonize/models/RecognizedBankTransaction'; +import { MatchedBankTransaction } from '@/modules/BankingMatching/models/MatchedBankTransaction'; @Injectable() export class GetUncategorizedTransactions { constructor( private readonly transformer: TransformerInjectable, + @Inject(TENANCY_DB_CONNECTION) + private readonly tenantDb: () => Knex, + @Inject(UncategorizedBankTransaction.name) - private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction, + private readonly uncategorizedBankTransactionModel: TenantModelProxy, + + @Inject(Account.name) + private readonly accountModel: TenantModelProxy, + + @Inject(RecognizedBankTransaction.name) + private readonly recognizedTransactionModel: TenantModelProxy, + + @Inject(MatchedBankTransaction.name) + private readonly matchedTransactionModel: TenantModelProxy, ) {} /** * Retrieves the uncategorized cashflow transactions. - * @param {number} tenantId - Tenant id. * @param {number} accountId - Account Id. + * @param {IGetUncategorizedTransactionsQuery} query - Query. */ public async getTransactions( accountId: number, - query: IGetUncategorizedTransactionsQuery + query: GetUncategorizedTransactionsQueryDto ) { // Parsed query with default values. const _query = { @@ -29,8 +48,15 @@ export class GetUncategorizedTransactions { ...query, }; + await initialize(this.tenantDb(), [ + this.accountModel(), + this.uncategorizedBankTransactionModel(), + this.recognizedTransactionModel(), + this.matchedTransactionModel(), + ]); + const { results, pagination } = - await this.uncategorizedBankTransactionModel.query() + await this.uncategorizedBankTransactionModel().query() .onBuild((q) => { q.where('accountId', accountId); q.where('categorized', false); diff --git a/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.controller.ts b/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.controller.ts index a53cc6aab..0ad68bc44 100644 --- a/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.controller.ts +++ b/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.controller.ts @@ -11,13 +11,27 @@ import { ExcludeBankTransactionsApplication } from './ExcludeBankTransactionsApp import { ExcludedBankTransactionsQuery } from './types/BankTransactionsExclude.types'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; -@Controller('banking/transactions') +@Controller('banking/exclude') @ApiTags('banking-transactions') export class BankingTransactionsExcludeController { constructor( private readonly excludeBankTransactionsApplication: ExcludeBankTransactionsApplication, ) {} + @Post('bulk') + @ApiOperation({ summary: 'Exclude the given bank transactions.' }) + public excludeBankTransactions(@Body('ids') ids: number[]) { + return this.excludeBankTransactionsApplication.excludeBankTransactions(ids); + } + + @Delete('bulk') + @ApiOperation({ summary: 'Unexclude the given bank transactions.' }) + public unexcludeBankTransactions(@Body('ids') ids: number[]) { + return this.excludeBankTransactionsApplication.unexcludeBankTransactions( + ids, + ); + } + @Get() @ApiOperation({ summary: 'Retrieves the excluded bank transactions.' }) public getExcludedBankTransactions( @@ -28,7 +42,7 @@ export class BankingTransactionsExcludeController { ); } - @Post(':id/exclude') + @Post(':id') @ApiOperation({ summary: 'Exclude the given bank transaction.' }) public excludeBankTransaction(@Param('id') id: string) { return this.excludeBankTransactionsApplication.excludeBankTransaction( @@ -36,25 +50,11 @@ export class BankingTransactionsExcludeController { ); } - @Delete(':id/exclude') + @Delete(':id') @ApiOperation({ summary: 'Unexclude the given bank transaction.' }) public unexcludeBankTransaction(@Param('id') id: string) { return this.excludeBankTransactionsApplication.unexcludeBankTransaction( Number(id), ); } - - @Post('bulk/exclude') - @ApiOperation({ summary: 'Exclude the given bank transactions.' }) - public excludeBankTransactions(@Body('ids') ids: number[]) { - return this.excludeBankTransactionsApplication.excludeBankTransactions(ids); - } - - @Delete('bulk/exclude') - @ApiOperation({ summary: 'Unexclude the given bank transactions.' }) - public unexcludeBankTransactions(@Body('ids') ids: number[]) { - return this.excludeBankTransactionsApplication.unexcludeBankTransactions( - ids, - ); - } } diff --git a/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.module.ts b/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.module.ts index 05177cf8c..a0a332ec6 100644 --- a/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.module.ts +++ b/packages/server/src/modules/BankingTransactionsExclude/BankingTransactionsExclude.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { ExcludeBankTransactionsApplication } from './ExcludeBankTransactionsApplication'; import { ExcludeBankTransactionService } from './commands/ExcludeBankTransaction.service'; import { UnexcludeBankTransactionService } from './commands/UnexcludeBankTransaction.service'; @@ -10,7 +10,9 @@ import { BankingTransactionsExcludeController } from './BankingTransactionsExclu import { BankingTransactionsModule } from '../BankingTransactions/BankingTransactions.module'; @Module({ - imports: [BankingTransactionsModule], + imports: [ + forwardRef(() => BankingTransactionsModule), + ], providers: [ ExcludeBankTransactionsApplication, ExcludeBankTransactionService, diff --git a/packages/webapp/src/hooks/query/bank-rules.ts b/packages/webapp/src/hooks/query/bank-rules.ts index e5049f3ea..d2633f64d 100644 --- a/packages/webapp/src/hooks/query/bank-rules.ts +++ b/packages/webapp/src/hooks/query/bank-rules.ts @@ -668,7 +668,7 @@ export function useExcludedBankTransactionsInfinity( const response = await apiRequest.http({ ...axios, method: 'get', - url: `/api/banking/excluded`, + url: `/api/banking/exclude`, params: { page: pageParam, ...query }, }); return response.data; @@ -700,7 +700,7 @@ export function usePendingBankTransactionsInfinity( const response = await apiRequest.http({ ...axios, method: 'get', - url: `/api/banking/accounts/pending_transactions`, + url: `/api/banking/pending`, params: { page: pageParam, ...query }, }); return response.data; diff --git a/packages/webapp/src/hooks/query/cashflowAccounts.tsx b/packages/webapp/src/hooks/query/cashflowAccounts.tsx index 58c02eda1..c7991cfb4 100644 --- a/packages/webapp/src/hooks/query/cashflowAccounts.tsx +++ b/packages/webapp/src/hooks/query/cashflowAccounts.tsx @@ -157,7 +157,7 @@ export function useAccountUncategorizedTransactionsInfinity( const response = await apiRequest.http({ ...axios, method: 'get', - url: `/api/banking/transactions/${accountId}/uncategorized`, + url: `/api/banking/uncategorized/accounts/${accountId}`, params: { page: pageParam, ...query }, }); return response.data; @@ -231,7 +231,7 @@ export function useUncategorizedTransaction( [t.CASHFLOW_UNCAATEGORIZED_TRANSACTION, uncategorizedTranasctionId], { method: 'get', - url: `banking/transactions/uncategorized/${uncategorizedTranasctionId}`, + url: `banking/uncategorized/${uncategorizedTranasctionId}`, }, { select: (res) => res.data?.data,