mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat(server): endpoints swagger docs
This commit is contained in:
3
packages/server/src/i18n/en/branches.json
Normal file
3
packages/server/src/i18n/en/branches.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"head_branch": "Head Branch"
|
||||||
|
}
|
||||||
@@ -85,9 +85,7 @@ export class AccountTransformer extends Transformer {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
protected isFeedsPaused = (account: Account): boolean => {
|
protected isFeedsPaused = (account: Account): boolean => {
|
||||||
// return account.plaidItem?.isPaused || false;
|
return account.plaidItem?.isPaused || false;
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { AccountsApplication } from './AccountsApplication.service';
|
import { AccountsApplication } from './AccountsApplication.service';
|
||||||
import { CreateAccountDTO } from './CreateAccount.dto';
|
import { CreateAccountDTO } from './CreateAccount.dto';
|
||||||
import { EditAccountDTO } from './EditAccount.dto';
|
import { EditAccountDTO } from './EditAccount.dto';
|
||||||
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
|
import { IAccountsFilter } from './Accounts.types';
|
||||||
import {
|
import {
|
||||||
ApiExtraModels,
|
ApiExtraModels,
|
||||||
ApiOperation,
|
ApiOperation,
|
||||||
@@ -22,11 +22,14 @@ import {
|
|||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { AccountResponseDto } from './dtos/AccountResponse.dto';
|
import { AccountResponseDto } from './dtos/AccountResponse.dto';
|
||||||
import { AccountTypeResponseDto } from './dtos/AccountTypeResponse.dto';
|
import { AccountTypeResponseDto } from './dtos/AccountTypeResponse.dto';
|
||||||
|
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
|
||||||
|
import { GetAccountTransactionsQueryDto } from './dtos/GetAccountTransactionsQuery.dto';
|
||||||
|
|
||||||
@Controller('accounts')
|
@Controller('accounts')
|
||||||
@ApiTags('Accounts')
|
@ApiTags('Accounts')
|
||||||
@ApiExtraModels(AccountResponseDto)
|
@ApiExtraModels(AccountResponseDto)
|
||||||
@ApiExtraModels(AccountTypeResponseDto)
|
@ApiExtraModels(AccountTypeResponseDto)
|
||||||
|
@ApiExtraModels(GetAccountTransactionResponseDto)
|
||||||
export class AccountsController {
|
export class AccountsController {
|
||||||
constructor(private readonly accountsApplication: AccountsApplication) {}
|
constructor(private readonly accountsApplication: AccountsApplication) {}
|
||||||
|
|
||||||
@@ -132,8 +135,16 @@ export class AccountsController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'The account transactions have been successfully retrieved.',
|
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);
|
return this.accountsApplication.getAccountsTransactions(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,10 @@ import { GetAccount } from './GetAccount.service';
|
|||||||
import { ActivateAccount } from './ActivateAccount.service';
|
import { ActivateAccount } from './ActivateAccount.service';
|
||||||
import { GetAccountTypesService } from './GetAccountTypes.service';
|
import { GetAccountTypesService } from './GetAccountTypes.service';
|
||||||
import { GetAccountTransactionsService } from './GetAccountTransactions.service';
|
import { GetAccountTransactionsService } from './GetAccountTransactions.service';
|
||||||
import {
|
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
|
||||||
IAccountsFilter,
|
|
||||||
IAccountsTransactionsFilter,
|
|
||||||
IGetAccountTransactionPOJO,
|
|
||||||
} from './Accounts.types';
|
|
||||||
import { GetAccountsService } from './GetAccounts.service';
|
import { GetAccountsService } from './GetAccounts.service';
|
||||||
import { IFilterMeta } from '@/interfaces/Model';
|
import { IFilterMeta } from '@/interfaces/Model';
|
||||||
|
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AccountsApplication {
|
export class AccountsApplication {
|
||||||
@@ -127,7 +124,7 @@ export class AccountsApplication {
|
|||||||
*/
|
*/
|
||||||
public getAccountsTransactions = (
|
public getAccountsTransactions = (
|
||||||
filter: IAccountsTransactionsFilter,
|
filter: IAccountsTransactionsFilter,
|
||||||
): Promise<IGetAccountTransactionPOJO[]> => {
|
): Promise<Array<GetAccountTransactionResponseDto>> => {
|
||||||
return this.getAccountTransactionsService.getAccountsTransactions(filter);
|
return this.getAccountTransactionsService.getAccountsTransactions(filter);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
// import { IAccountEventDeletedPayload } from '@/interfaces';
|
|
||||||
import { CommandAccountValidators } from './CommandAccountValidators.service';
|
import { CommandAccountValidators } from './CommandAccountValidators.service';
|
||||||
import { Account } from './models/Account.model';
|
import { Account } from './models/Account.model';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
@@ -8,6 +7,7 @@ import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
|||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { IAccountEventDeletedPayload } from './Accounts.types';
|
import { IAccountEventDeletedPayload } from './Accounts.types';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
import { ERRORS } from './constants';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeleteAccount {
|
export class DeleteAccount {
|
||||||
@@ -70,8 +70,12 @@ export class DeleteAccount {
|
|||||||
await this.unassociateChildrenAccountsFromParent(accountId, trx);
|
await this.unassociateChildrenAccountsFromParent(accountId, trx);
|
||||||
|
|
||||||
// Deletes account by the given id.
|
// 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.
|
// Triggers `onAccountDeleted` event.
|
||||||
await this.eventEmitter.emitAsync(events.accounts.onDeleted, {
|
await this.eventEmitter.emitAsync(events.accounts.onDeleted, {
|
||||||
accountId,
|
accountId,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Account } from './models/Account.model';
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
import { GetAccountTransactionResponseDto } from './dtos/GetAccountTransactionResponse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GetAccountTransactionsService {
|
export class GetAccountTransactionsService {
|
||||||
@@ -29,7 +30,7 @@ export class GetAccountTransactionsService {
|
|||||||
*/
|
*/
|
||||||
public getAccountsTransactions = async (
|
public getAccountsTransactions = async (
|
||||||
filter: IAccountsTransactionsFilter,
|
filter: IAccountsTransactionsFilter,
|
||||||
): Promise<IGetAccountTransactionPOJO[]> => {
|
): Promise<Array<GetAccountTransactionResponseDto>> => {
|
||||||
// Retrieve the given account or throw not found error.
|
// Retrieve the given account or throw not found error.
|
||||||
if (filter.accountId) {
|
if (filter.accountId) {
|
||||||
await this.account().query().findById(filter.accountId).throwIfNotFound();
|
await this.account().query().findById(filter.accountId).throwIfNotFound();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -5,11 +5,15 @@ import {
|
|||||||
ApiParam,
|
ApiParam,
|
||||||
ApiQuery,
|
ApiQuery,
|
||||||
ApiResponse,
|
ApiResponse,
|
||||||
|
ApiExtraModels,
|
||||||
|
getSchemaPath,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { RecognizedTransactionsApplication } from './RecognizedTransactions.application';
|
import { RecognizedTransactionsApplication } from './RecognizedTransactions.application';
|
||||||
|
import { GetRecognizedTransactionResponseDto } from './dtos/GetRecognizedTransactionResponse.dto';
|
||||||
|
|
||||||
@Controller('banking/recognized')
|
@Controller('banking/recognized')
|
||||||
@ApiTags('Banking Recognized Transactions')
|
@ApiTags('Banking Recognized Transactions')
|
||||||
|
@ApiExtraModels(GetRecognizedTransactionResponseDto)
|
||||||
export class BankingRecognizedTransactionsController {
|
export class BankingRecognizedTransactionsController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly recognizedTransactionsApplication: RecognizedTransactionsApplication,
|
private readonly recognizedTransactionsApplication: RecognizedTransactionsApplication,
|
||||||
@@ -25,6 +29,9 @@ export class BankingRecognizedTransactionsController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'Returns the recognized transaction details',
|
description: 'Returns the recognized transaction details',
|
||||||
|
schema: {
|
||||||
|
$ref: getSchemaPath(GetRecognizedTransactionResponseDto),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 404,
|
status: 404,
|
||||||
@@ -48,6 +55,12 @@ export class BankingRecognizedTransactionsController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'Returns a list of recognized transactions',
|
description: 'Returns a list of recognized transactions',
|
||||||
|
schema: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: getSchemaPath(GetRecognizedTransactionResponseDto),
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
async getRecognizedTransactions(@Query() query: any) {
|
async getRecognizedTransactions(@Query() query: any) {
|
||||||
return this.recognizedTransactionsApplication.getRecognizedTransactions(
|
return this.recognizedTransactionsApplication.getRecognizedTransactions(
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class GetRecognizedTransactionResponseDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The unique identifier of the uncategorized transaction',
|
||||||
|
example: 123,
|
||||||
|
})
|
||||||
|
uncategorizedTransactionId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The reference number of the transaction',
|
||||||
|
example: 'TRX-2024-001',
|
||||||
|
})
|
||||||
|
referenceNo: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The description of the transaction',
|
||||||
|
example: 'Payment for invoice #123',
|
||||||
|
})
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The payee of the transaction',
|
||||||
|
example: 'John Doe',
|
||||||
|
})
|
||||||
|
payee: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The amount of the transaction',
|
||||||
|
example: 1500.75,
|
||||||
|
})
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The formatted amount of the transaction',
|
||||||
|
example: '$1,500.75',
|
||||||
|
})
|
||||||
|
formattedAmount: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The date of the transaction',
|
||||||
|
example: '2024-04-01',
|
||||||
|
})
|
||||||
|
date: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The formatted date of the transaction',
|
||||||
|
example: 'Apr 1, 2024',
|
||||||
|
})
|
||||||
|
formattedDate: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The assigned account ID', example: 10 })
|
||||||
|
assignedAccountId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The assigned account name',
|
||||||
|
example: 'Bank Account',
|
||||||
|
})
|
||||||
|
assignedAccountName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The assigned account code', example: '1001' })
|
||||||
|
assignedAccountCode: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The assigned payee', example: 'Jane Smith' })
|
||||||
|
assignedPayee: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The assigned memo', example: 'Office supplies' })
|
||||||
|
assignedMemo: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The assigned category',
|
||||||
|
example: 'Office Expenses',
|
||||||
|
})
|
||||||
|
assignedCategory: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The formatted assigned category',
|
||||||
|
example: 'Other Income',
|
||||||
|
})
|
||||||
|
assignedCategoryFormatted: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The withdrawal amount', example: 500 })
|
||||||
|
withdrawal: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The deposit amount', example: 1000 })
|
||||||
|
deposit: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether this is a deposit transaction',
|
||||||
|
example: true,
|
||||||
|
})
|
||||||
|
isDepositTransaction: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether this is a withdrawal transaction',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isWithdrawalTransaction: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The formatted deposit amount',
|
||||||
|
example: '$1,000.00',
|
||||||
|
})
|
||||||
|
formattedDepositAmount: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The formatted withdrawal amount',
|
||||||
|
example: '$500.00',
|
||||||
|
})
|
||||||
|
formattedWithdrawalAmount: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The bank rule ID', example: 'BR-001' })
|
||||||
|
bankRuleId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'The bank rule name', example: 'Salary Rule' })
|
||||||
|
bankRuleName: string;
|
||||||
|
}
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
import { Controller, Get, Query } from '@nestjs/common';
|
import { Controller, Get, Query } from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiTags,
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
ApiQuery,
|
||||||
|
getSchemaPath,
|
||||||
|
ApiExtraModels,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service';
|
import { BankingTransactionsApplication } from '../BankingTransactionsApplication.service';
|
||||||
import { GetPendingTransactionsQueryDto } from '../dtos/GetPendingTransactionsQuery.dto';
|
import { GetPendingTransactionsQueryDto } from '../dtos/GetPendingTransactionsQuery.dto';
|
||||||
|
import { GetPendingTransactionResponseDto } from '../dtos/GetPendingTransactionResponse.dto';
|
||||||
|
|
||||||
@Controller('banking/pending')
|
@Controller('banking/pending')
|
||||||
@ApiTags('Banking Pending Transactions')
|
@ApiTags('Banking Pending Transactions')
|
||||||
|
@ApiExtraModels(GetPendingTransactionResponseDto)
|
||||||
export class BankingPendingTransactionsController {
|
export class BankingPendingTransactionsController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly bankingTransactionsApplication: BankingTransactionsApplication,
|
private readonly bankingTransactionsApplication: BankingTransactionsApplication,
|
||||||
@@ -15,6 +24,9 @@ export class BankingPendingTransactionsController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'Returns a list of pending bank account transactions',
|
description: 'Returns a list of pending bank account transactions',
|
||||||
|
schema: {
|
||||||
|
$ref: getSchemaPath(GetPendingTransactionResponseDto),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
@ApiQuery({
|
@ApiQuery({
|
||||||
name: 'page',
|
name: 'page',
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsString, IsNumber, IsBoolean, IsDateString } from 'class-validator';
|
||||||
|
|
||||||
|
export class GetPendingTransactionResponseDto {
|
||||||
|
@ApiProperty({ description: 'Transaction amount' })
|
||||||
|
@IsNumber()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction date' })
|
||||||
|
@IsDateString()
|
||||||
|
date: Date | string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Bank account ID' })
|
||||||
|
@IsNumber()
|
||||||
|
accountId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction reference number', required: false })
|
||||||
|
@IsString()
|
||||||
|
referenceNo: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Payee', required: false })
|
||||||
|
@IsString()
|
||||||
|
payee: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction description', required: false })
|
||||||
|
@IsString()
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Plaid transaction ID', required: false })
|
||||||
|
@IsString()
|
||||||
|
plaidTransactionId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Recognized transaction ID', required: false })
|
||||||
|
@IsNumber()
|
||||||
|
recognizedTransactionId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Is transaction pending?' })
|
||||||
|
@IsBoolean()
|
||||||
|
pending: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction currency code' })
|
||||||
|
@IsString()
|
||||||
|
currencyCode: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Withdrawal amount' })
|
||||||
|
@IsNumber()
|
||||||
|
withdrawal: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Deposit amount' })
|
||||||
|
@IsNumber()
|
||||||
|
deposit: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Is deposit transaction?' })
|
||||||
|
@IsBoolean()
|
||||||
|
isDepositTransaction: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Is withdrawal transaction?' })
|
||||||
|
@IsBoolean()
|
||||||
|
isWithdrawalTransaction: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted amount' })
|
||||||
|
@IsString()
|
||||||
|
formattedAmount: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted date' })
|
||||||
|
@IsString()
|
||||||
|
formattedDate: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted deposit amount' })
|
||||||
|
@IsString()
|
||||||
|
formattedDepositAmount: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted withdrawal amount' })
|
||||||
|
@IsString()
|
||||||
|
formattedWithdrawalAmount: string;
|
||||||
|
}
|
||||||
@@ -10,10 +10,18 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ExcludeBankTransactionsApplication } from './ExcludeBankTransactionsApplication';
|
import { ExcludeBankTransactionsApplication } from './ExcludeBankTransactionsApplication';
|
||||||
import { ExcludedBankTransactionsQuery } from './types/BankTransactionsExclude.types';
|
import { ExcludedBankTransactionsQuery } from './types/BankTransactionsExclude.types';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiExtraModels,
|
||||||
|
ApiOperation,
|
||||||
|
ApiResponse,
|
||||||
|
ApiTags,
|
||||||
|
getSchemaPath,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
|
import { GetExcludedBankTransactionResponseDto } from './dtos/GetExcludedBankTransactionResponse.dto';
|
||||||
|
|
||||||
@Controller('banking/exclude')
|
@Controller('banking/exclude')
|
||||||
@ApiTags('Banking Transactions')
|
@ApiTags('Banking Transactions')
|
||||||
|
@ApiExtraModels(GetExcludedBankTransactionResponseDto)
|
||||||
export class BankingTransactionsExcludeController {
|
export class BankingTransactionsExcludeController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly excludeBankTransactionsApplication: ExcludeBankTransactionsApplication,
|
private readonly excludeBankTransactionsApplication: ExcludeBankTransactionsApplication,
|
||||||
@@ -35,6 +43,17 @@ export class BankingTransactionsExcludeController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Retrieves the excluded bank transactions.' })
|
@ApiOperation({ summary: 'Retrieves the excluded bank transactions.' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description:
|
||||||
|
'The excluded bank transactions has been retrieved successfully.',
|
||||||
|
schema: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: getSchemaPath(GetExcludedBankTransactionResponseDto),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
public getExcludedBankTransactions(
|
public getExcludedBankTransactions(
|
||||||
@Query() query: ExcludedBankTransactionsQuery,
|
@Query() query: ExcludedBankTransactionsQuery,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -0,0 +1,205 @@
|
|||||||
|
import { ApiProperty, ApiExtraModels } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
IsNumber,
|
||||||
|
IsString,
|
||||||
|
IsBoolean,
|
||||||
|
IsDateString,
|
||||||
|
IsOptional,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
@ApiExtraModels()
|
||||||
|
export class GetExcludedBankTransactionResponseDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description:
|
||||||
|
'Transaction amount (positive for deposit, negative for withdrawal)',
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction date (ISO string or Date)' })
|
||||||
|
@IsDateString()
|
||||||
|
date: string | Date;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'ID of the associated bank account' })
|
||||||
|
@IsNumber()
|
||||||
|
accountId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Reference number for the transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
referenceNo?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Payee name', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
payee?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Transaction description', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Plaid transaction ID', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
plaidTransactionId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether the transaction is pending',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
pending?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID of the recognized transaction, if any',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
recognizedTransactionId?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Categorization reference type',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
categorizeRefType?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Categorization reference ID', required: false })
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
categorizeRefId?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Formatted amount (localized string)',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
formattedAmount?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted transaction date', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
formattedDate?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted deposit amount', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
formattedDepositAmount?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Formatted withdrawal amount', required: false })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
formattedWithdrawalAmount?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Withdrawal amount', required: false })
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
withdrawal?: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Deposit amount', required: false })
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
deposit?: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'True if deposit transaction', required: false })
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isDepositTransaction?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'True if withdrawal transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isWithdrawalTransaction?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'True if transaction is recognized',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isRecognized?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'True if transaction is excluded',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isExcluded?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'True if transaction is pending',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
isPending?: boolean;
|
||||||
|
|
||||||
|
// Recognized transaction fields (from transformer)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned account ID from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
assignedAccountId?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned account name from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedAccountName?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned account code from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedAccountCode?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned payee from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedPayee?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned memo from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedMemo?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned category from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedCategory?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Assigned formatted category from recognized transaction',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
assignedCategoryFormatted?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { UncategorizedTransactionTransformer } from '@/modules/BankingCategorize/commands/UncategorizedTransaction.transformer';
|
||||||
|
|
||||||
|
export class ExcludedBankTransactionTransformer extends UncategorizedTransactionTransformer {}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||||
import { ExcludedBankTransactionsQuery } from '../types/BankTransactionsExclude.types';
|
import { ExcludedBankTransactionsQuery } from '../types/BankTransactionsExclude.types';
|
||||||
import { UncategorizedTransactionTransformer } from '@/modules/BankingCategorize/commands/UncategorizedTransaction.transformer';
|
|
||||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { ExcludedBankTransactionTransformer } from './ExcludedBankTransaction.transformer';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GetExcludedBankTransactionsService {
|
export class GetExcludedBankTransactionsService {
|
||||||
@@ -60,7 +60,7 @@ export class GetExcludedBankTransactionsService {
|
|||||||
|
|
||||||
const data = await this.transformer.transform(
|
const data = await this.transformer.transform(
|
||||||
results,
|
results,
|
||||||
new UncategorizedTransactionTransformer(),
|
new ExcludedBankTransactionTransformer(),
|
||||||
);
|
);
|
||||||
return { data, pagination };
|
return { data, pagination };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,14 @@ import { Response } from 'express';
|
|||||||
import { Controller, Get, Headers, Query, Res } from '@nestjs/common';
|
import { Controller, Get, Headers, Query, Res } from '@nestjs/common';
|
||||||
import { APAgingSummaryApplication } from './APAgingSummaryApplication';
|
import { APAgingSummaryApplication } from './APAgingSummaryApplication';
|
||||||
import { AcceptType } from '@/constants/accept-type';
|
import { AcceptType } from '@/constants/accept-type';
|
||||||
import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiProduces,
|
||||||
|
ApiResponse,
|
||||||
|
ApiTags,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
import { APAgingSummaryResponseExample } from './APAgingSummary.swagger';
|
||||||
|
|
||||||
@Controller('reports/payable-aging-summary')
|
@Controller('reports/payable-aging-summary')
|
||||||
@ApiTags('Reports')
|
@ApiTags('Reports')
|
||||||
@@ -12,6 +18,11 @@ export class APAgingSummaryController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Get payable aging summary' })
|
@ApiOperation({ summary: 'Get payable aging summary' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'A/P aging summary response',
|
||||||
|
example: APAgingSummaryResponseExample,
|
||||||
|
})
|
||||||
@ApiProduces(
|
@ApiProduces(
|
||||||
AcceptType.ApplicationJson,
|
AcceptType.ApplicationJson,
|
||||||
AcceptType.ApplicationJsonTable,
|
AcceptType.ApplicationJsonTable,
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
export const APAgingSummaryResponseExample = {
|
||||||
|
data: {
|
||||||
|
vendors: [
|
||||||
|
{
|
||||||
|
vendor_name: 'asdasd, asdasd',
|
||||||
|
current: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
vendor_name: 'Ahmed Bouhuolia',
|
||||||
|
current: {
|
||||||
|
amount: 32000,
|
||||||
|
formatted_amount: '32,000.00',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 32000,
|
||||||
|
formatted_amount: '$32,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
current: {
|
||||||
|
amount: 32000,
|
||||||
|
formatted_amount: '$32,000.00',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 32000,
|
||||||
|
formatted_amount: '$32,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
query: {
|
||||||
|
as_date: '2025-06-30',
|
||||||
|
aging_days_before: 30,
|
||||||
|
aging_periods: 3,
|
||||||
|
number_format: {
|
||||||
|
precision: 2,
|
||||||
|
divide_on1000: false,
|
||||||
|
show_zero: false,
|
||||||
|
format_money: 'total',
|
||||||
|
negative_format: 'mines',
|
||||||
|
},
|
||||||
|
vendors_ids: [],
|
||||||
|
branches_ids: [],
|
||||||
|
none_zero: false,
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
organization_name: 'BIGCAPITAL, INC',
|
||||||
|
base_currency: 'USD',
|
||||||
|
date_format: 'DD MMM yyyy',
|
||||||
|
is_cost_compute_running: false,
|
||||||
|
sheet_name: 'A/P Aging Summary',
|
||||||
|
formatted_as_date: '2025/06/30',
|
||||||
|
formatted_date_range: 'As 2025/06/30',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -3,8 +3,14 @@ import { Query, Res } from '@nestjs/common';
|
|||||||
import { ARAgingSummaryApplication } from './ARAgingSummaryApplication';
|
import { ARAgingSummaryApplication } from './ARAgingSummaryApplication';
|
||||||
import { AcceptType } from '@/constants/accept-type';
|
import { AcceptType } from '@/constants/accept-type';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { ApiOperation, ApiProduces, ApiTags } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiOperation,
|
||||||
|
ApiProduces,
|
||||||
|
ApiResponse,
|
||||||
|
ApiTags,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
import { ARAgingSummaryResponseExample } from './ARAgingSummary.swagger';
|
||||||
|
|
||||||
@Controller('reports/receivable-aging-summary')
|
@Controller('reports/receivable-aging-summary')
|
||||||
@ApiTags('Reports')
|
@ApiTags('Reports')
|
||||||
@@ -13,6 +19,11 @@ export class ARAgingSummaryController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Get receivable aging summary' })
|
@ApiOperation({ summary: 'Get receivable aging summary' })
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'Receivable aging summary response',
|
||||||
|
example: ARAgingSummaryResponseExample,
|
||||||
|
})
|
||||||
@ApiProduces(
|
@ApiProduces(
|
||||||
AcceptType.ApplicationJson,
|
AcceptType.ApplicationJson,
|
||||||
AcceptType.ApplicationJsonTable,
|
AcceptType.ApplicationJsonTable,
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
export const ARAgingSummaryResponseExample = {
|
||||||
|
query: {
|
||||||
|
as_date: '2025-06-30',
|
||||||
|
aging_days_before: 30,
|
||||||
|
aging_periods: 3,
|
||||||
|
number_format: {
|
||||||
|
divide_on1000: false,
|
||||||
|
negative_format: 'mines',
|
||||||
|
show_zero: false,
|
||||||
|
format_money: 'total',
|
||||||
|
precision: 2,
|
||||||
|
},
|
||||||
|
customers_ids: [],
|
||||||
|
branches_ids: [],
|
||||||
|
none_zero: false,
|
||||||
|
},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: {
|
||||||
|
customers: [
|
||||||
|
{
|
||||||
|
customer_name: 'business',
|
||||||
|
current: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 5000,
|
||||||
|
formatted_amount: '5,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 5000,
|
||||||
|
formatted_amount: '$5,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
customer_name: 'business',
|
||||||
|
current: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
customer_name: 'asdsadasd, asd',
|
||||||
|
current: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
customer_name: 'Ahmed Bouhuolia',
|
||||||
|
current: {
|
||||||
|
amount: 300000,
|
||||||
|
formatted_amount: '300,000.00',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 300000,
|
||||||
|
formatted_amount: '$300,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
current: {
|
||||||
|
amount: 300000,
|
||||||
|
formatted_amount: '$300,000.00',
|
||||||
|
},
|
||||||
|
aging: [
|
||||||
|
{
|
||||||
|
from_period: '2025-06-30',
|
||||||
|
to_period: '2025-05-31',
|
||||||
|
before_days: 0,
|
||||||
|
to_days: 30,
|
||||||
|
total: {
|
||||||
|
amount: 5000,
|
||||||
|
formatted_amount: '$5,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-31',
|
||||||
|
to_period: '2025-05-01',
|
||||||
|
before_days: 31,
|
||||||
|
to_days: 60,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from_period: '2025-05-01',
|
||||||
|
to_period: null,
|
||||||
|
before_days: 61,
|
||||||
|
to_days: null,
|
||||||
|
total: {
|
||||||
|
amount: 0,
|
||||||
|
formatted_amount: '$0.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
amount: 305000,
|
||||||
|
formatted_amount: '$305,000.00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
organization_name: 'BIGCAPITAL, INC',
|
||||||
|
base_currency: 'USD',
|
||||||
|
date_format: 'DD MMM yyyy',
|
||||||
|
is_cost_compute_running: false,
|
||||||
|
sheet_name: 'A/R Aging Summary',
|
||||||
|
formatted_as_date: '2025/06/30',
|
||||||
|
formatted_date_range: 'As 2025/06/30',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -4,6 +4,9 @@ import {
|
|||||||
ApiResponse,
|
ApiResponse,
|
||||||
ApiBody,
|
ApiBody,
|
||||||
ApiOkResponse,
|
ApiOkResponse,
|
||||||
|
ApiExtraModels,
|
||||||
|
getSchemaPath,
|
||||||
|
ApiParam,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
@@ -29,11 +32,13 @@ import {
|
|||||||
OrganizationBuildResponseExample,
|
OrganizationBuildResponseExample,
|
||||||
OrganizationBuiltResponseExample,
|
OrganizationBuiltResponseExample,
|
||||||
} from './Organization.swagger';
|
} from './Organization.swagger';
|
||||||
|
import { GetCurrentOrganizationResponseDto } from './dtos/GetCurrentOrganizationResponse.dto';
|
||||||
|
|
||||||
@ApiTags('Organization')
|
@ApiTags('Organization')
|
||||||
@Controller('organization')
|
@Controller('organization')
|
||||||
@IgnoreTenantInitializedRoute()
|
@IgnoreTenantInitializedRoute()
|
||||||
@IgnoreTenantSeededRoute()
|
@IgnoreTenantSeededRoute()
|
||||||
|
@ApiExtraModels(GetCurrentOrganizationResponseDto)
|
||||||
export class OrganizationController {
|
export class OrganizationController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly buildOrganizationService: BuildOrganizationService,
|
private readonly buildOrganizationService: BuildOrganizationService,
|
||||||
@@ -68,6 +73,12 @@ export class OrganizationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Get('build/:buildJobId')
|
@Get('build/:buildJobId')
|
||||||
|
@ApiParam({
|
||||||
|
name: 'buildJobId',
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
description: 'The build job id',
|
||||||
|
})
|
||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
@ApiOperation({ summary: 'Gets the organization build job details' })
|
@ApiOperation({ summary: 'Gets the organization build job details' })
|
||||||
async buildJob(@Param('buildJobId') buildJobId: string) {
|
async buildJob(@Param('buildJobId') buildJobId: string) {
|
||||||
@@ -80,12 +91,15 @@ export class OrganizationController {
|
|||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'Returns the current organization',
|
description: 'Returns the current organization',
|
||||||
|
schema: {
|
||||||
|
$ref: getSchemaPath(GetCurrentOrganizationResponseDto),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
async currentOrganization() {
|
async currentOrganization() {
|
||||||
const organization =
|
const organization =
|
||||||
await this.getCurrentOrgService.getCurrentOrganization();
|
await this.getCurrentOrgService.getCurrentOrganization();
|
||||||
|
|
||||||
return { organization };
|
return organization;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('base-currency-mutate')
|
@Get('base-currency-mutate')
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class OrganizationMetadataResponseDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Internal numeric ID of the metadata',
|
||||||
|
example: 1,
|
||||||
|
})
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Tenant ID associated with the organization',
|
||||||
|
example: 101,
|
||||||
|
})
|
||||||
|
tenantId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Name of the organization',
|
||||||
|
example: 'Acme Inc.',
|
||||||
|
})
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Industry of the organization',
|
||||||
|
example: 'Technology',
|
||||||
|
})
|
||||||
|
industry: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Location of the organization', example: 'US' })
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Base currency in ISO 4217 format',
|
||||||
|
example: 'USD',
|
||||||
|
})
|
||||||
|
baseCurrency: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Language/locale of the organization',
|
||||||
|
example: 'en-US',
|
||||||
|
})
|
||||||
|
language: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Timezone of the organization',
|
||||||
|
example: 'America/New_York',
|
||||||
|
})
|
||||||
|
timezone: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Date format used by the organization',
|
||||||
|
example: 'MM/DD/YYYY',
|
||||||
|
})
|
||||||
|
dateFormat: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Fiscal year of the organization',
|
||||||
|
example: 'January',
|
||||||
|
})
|
||||||
|
fiscalYear: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Tax identification number',
|
||||||
|
example: '12-3456789',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
taxNumber: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Primary brand color in hex format',
|
||||||
|
example: '#4285F4',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
primaryColor: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Logo file key reference',
|
||||||
|
example: 'organizations/acme-logo-123456.png',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
logoKey: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Organization address details',
|
||||||
|
example: '123 Main St, New York, NY',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GetCurrentOrganizationResponseDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Internal numeric ID of the organization',
|
||||||
|
example: 1,
|
||||||
|
})
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Unique string identifier for the organization',
|
||||||
|
example: 'org_123456',
|
||||||
|
})
|
||||||
|
organizationId: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Date when the organization was initialized',
|
||||||
|
example: '2024-01-01T00:00:00.000Z',
|
||||||
|
})
|
||||||
|
initializedAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Date when the organization was seeded',
|
||||||
|
example: '2024-01-01T01:00:00.000Z',
|
||||||
|
})
|
||||||
|
seededAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Date when the organization was built',
|
||||||
|
example: '2024-01-01T02:00:00.000Z',
|
||||||
|
})
|
||||||
|
builtAt: Date;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Database batch identifier, if any',
|
||||||
|
example: 'batch_001',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
databaseBatch: null | string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Organization metadata',
|
||||||
|
type: () => [OrganizationMetadataResponseDto],
|
||||||
|
})
|
||||||
|
metadata: OrganizationMetadataResponseDto;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether the organization is ready',
|
||||||
|
example: true,
|
||||||
|
})
|
||||||
|
isReady: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether a build process is currently running',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isBuildRunning: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether an upgrade process is currently running',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isUpgradeRunning: boolean;
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ export function useCurrentOrganization(props) {
|
|||||||
[t.ORGANIZATION_CURRENT],
|
[t.ORGANIZATION_CURRENT],
|
||||||
{ method: 'get', url: OrganizationRoute.Current },
|
{ method: 'get', url: OrganizationRoute.Current },
|
||||||
{
|
{
|
||||||
select: (res) => res.data.organization,
|
select: (res) => res.data,
|
||||||
defaultData: {},
|
defaultData: {},
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
const organization = omit(data, ['subscriptions']);
|
const organization = omit(data, ['subscriptions']);
|
||||||
|
|||||||
Reference in New Issue
Block a user