mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 04:10:32 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { BankRulesApplication } from './BankRulesApplication';
|
||||
import { BankRule } from './models/BankRule';
|
||||
import { CreateBankRuleDto } from './dtos/BankRule.dto';
|
||||
import { EditBankRuleDto } from './dtos/BankRule.dto';
|
||||
|
||||
@Controller('banking/rules')
|
||||
@ApiTags('bank-rules')
|
||||
export class BankRulesController {
|
||||
constructor(private readonly bankRulesApplication: BankRulesApplication) {}
|
||||
|
||||
@Post()
|
||||
@ApiOperation({ summary: 'Create a new bank rule.' })
|
||||
async createBankRule(
|
||||
@Body() createRuleDTO: CreateBankRuleDto,
|
||||
): Promise<BankRule> {
|
||||
return this.bankRulesApplication.createBankRule(createRuleDTO);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@ApiOperation({ summary: 'Edit the given bank rule.' })
|
||||
async editBankRule(
|
||||
@Param('id') ruleId: number,
|
||||
@Body() editRuleDTO: EditBankRuleDto,
|
||||
): Promise<void> {
|
||||
return this.bankRulesApplication.editBankRule(ruleId, editRuleDTO);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@ApiOperation({ summary: 'Delete the given bank rule.' })
|
||||
async deleteBankRule(@Param('id') ruleId: number): Promise<void> {
|
||||
return this.bankRulesApplication.deleteBankRule(ruleId);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Retrieves the bank rule details.' })
|
||||
async getBankRule(@Param('id') ruleId: number): Promise<any> {
|
||||
return this.bankRulesApplication.getBankRule(ruleId);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Retrieves the bank rules.' })
|
||||
async getBankRules(): Promise<any> {
|
||||
return this.bankRulesApplication.getBankRules();
|
||||
}
|
||||
}
|
||||
36
packages/server/src/modules/BankRules/BankRules.module.ts
Normal file
36
packages/server/src/modules/BankRules/BankRules.module.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { forwardRef, Module } from '@nestjs/common';
|
||||
import { CreateBankRuleService } from './commands/CreateBankRule.service';
|
||||
import { EditBankRuleService } from './commands/EditBankRule.service';
|
||||
import { DeleteBankRuleService } from './commands/DeleteBankRule.service';
|
||||
import { GetBankRulesService } from './queries/GetBankRules.service';
|
||||
import { GetBankRuleService } from './queries/GetBankRule.service';
|
||||
import { BankRulesApplication } from './BankRulesApplication';
|
||||
import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module';
|
||||
import { BankRuleCondition } from './models/BankRuleCondition';
|
||||
import { BankRule } from './models/BankRule';
|
||||
import { BankRulesController } from './BankRules.controller';
|
||||
import { UnlinkBankRuleOnDeleteBankRuleSubscriber } from './events/UnlinkBankRuleOnDeleteBankRule';
|
||||
import { DeleteBankRulesService } from './commands/DeleteBankRules.service';
|
||||
import { BankingTransactionsRegonizeModule } from '../BankingTranasctionsRegonize/BankingTransactionsRegonize.module';
|
||||
|
||||
const models = [
|
||||
RegisterTenancyModel(BankRule),
|
||||
RegisterTenancyModel(BankRuleCondition),
|
||||
];
|
||||
|
||||
@Module({
|
||||
controllers: [BankRulesController],
|
||||
imports: [forwardRef(() => BankingTransactionsRegonizeModule), ...models],
|
||||
providers: [
|
||||
CreateBankRuleService,
|
||||
EditBankRuleService,
|
||||
DeleteBankRuleService,
|
||||
DeleteBankRulesService,
|
||||
GetBankRuleService,
|
||||
GetBankRulesService,
|
||||
BankRulesApplication,
|
||||
UnlinkBankRuleOnDeleteBankRuleSubscriber,
|
||||
],
|
||||
exports: [...models, DeleteBankRuleService, DeleteBankRulesService],
|
||||
})
|
||||
export class BankRulesModule {}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { CreateBankRuleService } from './commands/CreateBankRule.service';
|
||||
import { DeleteBankRuleService } from './commands/DeleteBankRule.service';
|
||||
import { EditBankRuleService } from './commands/EditBankRule.service';
|
||||
import { GetBankRuleService } from './queries/GetBankRule.service';
|
||||
import { GetBankRulesService } from './queries/GetBankRules.service';
|
||||
import { BankRule } from './models/BankRule';
|
||||
import { CreateBankRuleDto, EditBankRuleDto } from './dtos/BankRule.dto';
|
||||
|
||||
@Injectable()
|
||||
export class BankRulesApplication {
|
||||
constructor(
|
||||
private readonly createBankRuleService: CreateBankRuleService,
|
||||
private readonly editBankRuleService: EditBankRuleService,
|
||||
private readonly deleteBankRuleService: DeleteBankRuleService,
|
||||
private readonly getBankRuleService: GetBankRuleService,
|
||||
private readonly getBankRulesService: GetBankRulesService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates new bank rule.
|
||||
* @param {ICreateBankRuleDTO} createRuleDTO - Bank rule data.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public createBankRule(
|
||||
createRuleDTO: CreateBankRuleDto,
|
||||
): Promise<BankRule> {
|
||||
return this.createBankRuleService.createBankRule(createRuleDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the given bank rule.
|
||||
* @param {number} ruleId - Bank rule identifier.
|
||||
* @param {EditBankRuleDto} editRuleDTO - Bank rule data.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public editBankRule(
|
||||
ruleId: number,
|
||||
editRuleDTO: EditBankRuleDto,
|
||||
): Promise<void> {
|
||||
return this.editBankRuleService.editBankRule(ruleId, editRuleDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given bank rule.
|
||||
* @param {number} ruleId - Bank rule identifier.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public deleteBankRule(ruleId: number): Promise<void> {
|
||||
return this.deleteBankRuleService.deleteBankRule(ruleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given bank rule.
|
||||
* @param {number} ruleId - Bank rule identifier.
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
public getBankRule(ruleId: number): Promise<any> {
|
||||
return this.getBankRuleService.getBankRule(ruleId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the bank rules of the given account.
|
||||
* @param {number} accountId - Bank account identifier.
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
public getBankRules(): Promise<any> {
|
||||
return this.getBankRulesService.getBankRules();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ModelObject } from 'objection';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IBankRuleEventCreatedPayload,
|
||||
IBankRuleEventCreatingPayload,
|
||||
} from '../types';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { CreateBankRuleDto } from '../dtos/BankRule.dto';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateBankRuleService {
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(BankRule.name)
|
||||
private readonly bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Transforms the DTO to model.
|
||||
* @param {ICreateBankRuleDTO} createDTO
|
||||
*/
|
||||
private transformDTO(createDTO: CreateBankRuleDto): ModelObject<BankRule> {
|
||||
return {
|
||||
...createDTO,
|
||||
} as ModelObject<BankRule>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new bank rule.
|
||||
* @param {ICreateBankRuleDTO} createRuleDTO
|
||||
* @returns {Promise<BankRule>}
|
||||
*/
|
||||
public async createBankRule(
|
||||
createRuleDTO: CreateBankRuleDto,
|
||||
): Promise<BankRule> {
|
||||
const transformDTO = this.transformDTO(createRuleDTO);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onBankRuleCreating` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onCreating, {
|
||||
createRuleDTO,
|
||||
trx,
|
||||
} as IBankRuleEventCreatingPayload);
|
||||
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
...transformDTO,
|
||||
});
|
||||
// Triggers `onBankRuleCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onCreated, {
|
||||
createRuleDTO,
|
||||
bankRule,
|
||||
trx,
|
||||
} as IBankRuleEventCreatedPayload);
|
||||
|
||||
return bankRule;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
IBankRuleEventDeletedPayload,
|
||||
IBankRuleEventDeletingPayload,
|
||||
} from '../types';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { BankRuleCondition } from '../models/BankRuleCondition';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBankRuleService {
|
||||
constructor(
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
|
||||
@Inject(BankRuleCondition.name)
|
||||
private bankRuleConditionModel: TenantModelProxy<typeof BankRuleCondition>,
|
||||
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given bank rule.
|
||||
* @param {number} ruleId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async deleteBankRule(
|
||||
ruleId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
const oldBankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.throwIfNotFound();
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onBankRuleDeleting` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onDeleting, {
|
||||
oldBankRule,
|
||||
ruleId,
|
||||
trx,
|
||||
} as IBankRuleEventDeletingPayload);
|
||||
|
||||
await this.bankRuleConditionModel()
|
||||
.query(trx)
|
||||
.where('ruleId', ruleId)
|
||||
.delete();
|
||||
|
||||
await this.bankRuleModel().query(trx).findById(ruleId).delete();
|
||||
|
||||
// Triggers `onBankRuleDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onDeleted, {
|
||||
ruleId,
|
||||
trx,
|
||||
} as IBankRuleEventDeletedPayload);
|
||||
}, trx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Knex } from 'knex';
|
||||
import { PromisePool } from '@supercharge/promise-pool';
|
||||
import { castArray, uniq } from 'lodash';
|
||||
import { DeleteBankRuleService } from './DeleteBankRule.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBankRulesService {
|
||||
constructor(private readonly deleteBankRuleService: DeleteBankRuleService) {}
|
||||
|
||||
/**
|
||||
* Delete bank rules.
|
||||
* @param {number | Array<number>} bankRuleId - The bank rule id or ids.
|
||||
* @param {Knex.Transaction} trx - The transaction.
|
||||
*/
|
||||
async deleteBankRules(
|
||||
bankRuleId: number | Array<number>,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const bankRulesIds = uniq(castArray(bankRuleId));
|
||||
|
||||
const results = await PromisePool.withConcurrency(1)
|
||||
.for(bankRulesIds)
|
||||
.process(async (bankRuleId: number) => {
|
||||
await this.deleteBankRuleService.deleteBankRule(bankRuleId, trx);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
IBankRuleEventEditedPayload,
|
||||
IBankRuleEventEditingPayload,
|
||||
IEditBankRuleDTO,
|
||||
} from '../types';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { EditBankRuleDto } from '../dtos/BankRule.dto';
|
||||
import { ModelObject } from 'objection';
|
||||
|
||||
@Injectable()
|
||||
export class EditBankRuleService {
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param createDTO
|
||||
* @returns
|
||||
*/
|
||||
private transformDTO(createDTO: EditBankRuleDto): ModelObject<BankRule> {
|
||||
return {
|
||||
...createDTO,
|
||||
} as ModelObject<BankRule>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the given bank rule.
|
||||
* @param {number} ruleId -
|
||||
* @param {IEditBankRuleDTO} editBankDTO
|
||||
*/
|
||||
public async editBankRule(ruleId: number, editRuleDTO: EditBankRuleDto) {
|
||||
const oldBankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.withGraphFetched('conditions')
|
||||
.throwIfNotFound();
|
||||
|
||||
const tranformDTO = this.transformDTO(editRuleDTO);
|
||||
|
||||
return this.uow.withTransaction(async (trx) => {
|
||||
// Triggers `onBankRuleEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onEditing, {
|
||||
oldBankRule,
|
||||
ruleId,
|
||||
editRuleDTO,
|
||||
trx,
|
||||
} as IBankRuleEventEditingPayload);
|
||||
|
||||
// Updates the given bank rule.
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
...tranformDTO,
|
||||
id: ruleId,
|
||||
});
|
||||
// Triggers `onBankRuleEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onEdited, {
|
||||
oldBankRule,
|
||||
bankRule,
|
||||
editRuleDTO,
|
||||
trx,
|
||||
} as IBankRuleEventEditedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
122
packages/server/src/modules/BankRules/dtos/BankRule.dto.ts
Normal file
122
packages/server/src/modules/BankRules/dtos/BankRule.dto.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsString,
|
||||
IsInt,
|
||||
Min,
|
||||
IsOptional,
|
||||
IsIn,
|
||||
IsArray,
|
||||
ValidateNested,
|
||||
ArrayMinSize,
|
||||
IsNotEmpty,
|
||||
} from 'class-validator';
|
||||
import { BankRuleComparator } from '../types';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
class BankRuleConditionDto {
|
||||
@IsNotEmpty()
|
||||
@IsIn(['description', 'amount'])
|
||||
field: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsIn([
|
||||
'equals',
|
||||
'equal',
|
||||
'contains',
|
||||
'not_contain',
|
||||
'bigger',
|
||||
'bigger_or_equal',
|
||||
'smaller',
|
||||
'smaller_or_equal',
|
||||
])
|
||||
comparator: BankRuleComparator = 'contains';
|
||||
|
||||
@IsNotEmpty()
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class CommandBankRuleDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@ApiProperty({
|
||||
description: 'The name of the bank rule',
|
||||
example: 'Monthly Salary',
|
||||
})
|
||||
name: string;
|
||||
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
@ApiProperty({
|
||||
description: 'The order of the bank rule',
|
||||
example: 1,
|
||||
})
|
||||
order: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
@ApiProperty({
|
||||
description: 'The account ID to apply the rule if',
|
||||
example: 1,
|
||||
})
|
||||
applyIfAccountId?: number;
|
||||
|
||||
@IsIn(['deposit', 'withdrawal'])
|
||||
@ApiProperty({
|
||||
description: 'The transaction type to apply the rule if',
|
||||
example: 'deposit',
|
||||
})
|
||||
applyIfTransactionType: 'deposit' | 'withdrawal';
|
||||
|
||||
@IsString()
|
||||
@IsIn(['and', 'or'])
|
||||
@ApiProperty({
|
||||
description: 'The conditions type to apply the rule if',
|
||||
example: 'and',
|
||||
})
|
||||
conditionsType: 'and' | 'or' = 'and';
|
||||
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => BankRuleConditionDto)
|
||||
@ApiProperty({
|
||||
description: 'The conditions to apply the rule if',
|
||||
example: [{ field: 'description', comparator: 'contains', value: 'Salary' }],
|
||||
})
|
||||
conditions: BankRuleConditionDto[];
|
||||
|
||||
@IsString()
|
||||
@ApiProperty({
|
||||
description: 'The category to assign the rule if',
|
||||
example: 'Income:Salary',
|
||||
})
|
||||
assignCategory: string;
|
||||
|
||||
@IsInt()
|
||||
@Min(0)
|
||||
@ApiProperty({
|
||||
description: 'The account ID to assign the rule if',
|
||||
example: 1,
|
||||
})
|
||||
assignAccountId: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({
|
||||
description: 'The payee to assign the rule if',
|
||||
example: 'Employer Inc.',
|
||||
})
|
||||
assignPayee?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@ApiProperty({
|
||||
description: 'The memo to assign the rule if',
|
||||
example: 'Monthly Salary',
|
||||
})
|
||||
assignMemo?: string;
|
||||
}
|
||||
|
||||
export class CreateBankRuleDto extends CommandBankRuleDto {}
|
||||
export class EditBankRuleDto extends CommandBankRuleDto {}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { IBankRuleEventDeletingPayload } from '../types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { RevertRecognizedTransactionsService } from '@/modules/BankingTranasctionsRegonize/commands/RevertRecognizedTransactions.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
@Injectable()
|
||||
export class UnlinkBankRuleOnDeleteBankRuleSubscriber {
|
||||
constructor(
|
||||
private readonly revertRecognizedTransactionsService: RevertRecognizedTransactionsService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Unlinks the bank rule out of recognized transactions.
|
||||
* @param {IBankRuleEventDeletingPayload} payload -
|
||||
*/
|
||||
@OnEvent(events.bankRules.onDeleting)
|
||||
public async unlinkBankRuleOutRecognizedTransactionsOnRuleDeleting({
|
||||
oldBankRule,
|
||||
}: IBankRuleEventDeletingPayload) {
|
||||
await this.revertRecognizedTransactionsService.revertRecognizedTransactions(
|
||||
oldBankRule.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
74
packages/server/src/modules/BankRules/models/BankRule.ts
Normal file
74
packages/server/src/modules/BankRules/models/BankRule.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { Model } from 'objection';
|
||||
import { BankRuleCondition } from './BankRuleCondition';
|
||||
import { BankRuleAssignCategory, BankRuleConditionType } from '../types';
|
||||
|
||||
export class BankRule extends BaseModel {
|
||||
public readonly id!: number;
|
||||
public readonly name!: string;
|
||||
public readonly order!: number;
|
||||
public readonly applyIfAccountId!: number;
|
||||
public readonly applyIfTransactionType!: string;
|
||||
public readonly assignCategory!: BankRuleAssignCategory;
|
||||
public readonly assignAccountId!: number;
|
||||
public readonly assignPayee!: string;
|
||||
public readonly assignMemo!: string;
|
||||
public readonly conditionsType!: BankRuleConditionType;
|
||||
|
||||
public readonly conditions!: BankRuleCondition[];
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'bank_rules';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
static get timestamps() {
|
||||
return ['created_at', 'updated_at'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
const { BankRuleCondition } = require('./BankRuleCondition');
|
||||
const { Account } = require('../../Accounts/models/Account.model');
|
||||
|
||||
return {
|
||||
/**
|
||||
* Sale invoice associated entries.
|
||||
*/
|
||||
conditions: {
|
||||
relation: Model.HasManyRelation,
|
||||
modelClass: BankRuleCondition,
|
||||
join: {
|
||||
from: 'bank_rules.id',
|
||||
to: 'bank_rule_conditions.ruleId',
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Bank rule may associated to the assign account.
|
||||
*/
|
||||
assignAccount: {
|
||||
relation: Model.BelongsToOneRelation,
|
||||
modelClass: Account,
|
||||
join: {
|
||||
from: 'bank_rules.assignAccountId',
|
||||
to: 'accounts.id',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { BankRuleComparator } from '../types';
|
||||
|
||||
export class BankRuleCondition extends BaseModel {
|
||||
public id!: number;
|
||||
public bankRuleId!: number;
|
||||
public field!: string;
|
||||
public comparator!: BankRuleComparator;
|
||||
public value!: string;
|
||||
|
||||
/**
|
||||
* Table name.
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'bank_rule_conditions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
get timestamps() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { GetBankRuleTransformer } from './GetBankRuleTransformer';
|
||||
import { TransformerInjectable } from '../../Transformer/TransformerInjectable.service';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { GetBankRulesTransformer } from './GetBankRulesTransformer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBankRuleService {
|
||||
constructor(
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
private transformer: TransformerInjectable,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the bank rule.
|
||||
* @param {number} ruleId - Rule id.
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async getBankRule(ruleId: number): Promise<any> {
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.withGraphFetched('conditions')
|
||||
.withGraphFetched('assignAccount');
|
||||
|
||||
return this.transformer.transform(bankRule, new GetBankRulesTransformer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Transformer } from "@/modules/Transformer/Transformer";
|
||||
|
||||
export class GetBankRuleTransformer extends Transformer {
|
||||
/**
|
||||
* Include these attributes to sale invoice object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { GetBankRulesTransformer } from './GetBankRulesTransformer';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBankRulesService {
|
||||
constructor(
|
||||
private transformer: TransformerInjectable,
|
||||
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the bank rules of the given account.
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
public async getBankRules(): Promise<any> {
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.withGraphFetched('conditions')
|
||||
.withGraphFetched('assignAccount');
|
||||
|
||||
return this.transformer.transform(bankRule, new GetBankRulesTransformer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Transformer } from '@/modules/Transformer/Transformer';
|
||||
import { getCashflowTransactionFormattedType } from '../../BankingTransactions/utils';
|
||||
|
||||
export class GetBankRulesTransformer extends Transformer {
|
||||
/**
|
||||
* Include these attributes to sale invoice object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return [
|
||||
'assignAccountName',
|
||||
'assignCategoryFormatted',
|
||||
'conditionsFormatted',
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the assign account name.
|
||||
* @param bankRule
|
||||
* @returns {string}
|
||||
*/
|
||||
protected assignAccountName(bankRule: any) {
|
||||
return bankRule.assignAccount.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigned category formatted.
|
||||
* @returns {string}
|
||||
*/
|
||||
protected assignCategoryFormatted(bankRule: any) {
|
||||
return getCashflowTransactionFormattedType(bankRule.assignCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bank rule formatted conditions.
|
||||
* @param bankRule
|
||||
* @returns {string}
|
||||
*/
|
||||
protected conditionsFormatted(bankRule: any) {
|
||||
return bankRule.conditions
|
||||
.map((condition) => {
|
||||
const field =
|
||||
condition.field.charAt(0).toUpperCase() + condition.field.slice(1);
|
||||
|
||||
return `${field} ${condition.comparator} ${condition.value}`;
|
||||
})
|
||||
.join(bankRule.conditionsType === 'and' ? ' and ' : ' or ');
|
||||
}
|
||||
}
|
||||
127
packages/server/src/modules/BankRules/types.ts
Normal file
127
packages/server/src/modules/BankRules/types.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { Knex } from 'knex';
|
||||
import { BankRule } from './models/BankRule';
|
||||
import { CreateBankRuleDto, EditBankRuleDto } from './dtos/BankRule.dto';
|
||||
|
||||
export enum BankRuleConditionField {
|
||||
Amount = 'amount',
|
||||
Description = 'description',
|
||||
Payee = 'payee',
|
||||
}
|
||||
|
||||
export enum BankRuleConditionComparator {
|
||||
Contains = 'contains',
|
||||
Equals = 'equals',
|
||||
Equal = 'equal',
|
||||
NotContain = 'not_contains',
|
||||
Bigger = 'bigger',
|
||||
BiggerOrEqual = 'bigger_or_equal',
|
||||
Smaller = 'smaller',
|
||||
SmallerOrEqual = 'smaller_or_equal',
|
||||
}
|
||||
|
||||
export interface IBankRuleCondition {
|
||||
id?: number;
|
||||
field: BankRuleConditionField;
|
||||
comparator: BankRuleConditionComparator;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export enum BankRuleConditionType {
|
||||
Or = 'or',
|
||||
And = 'and',
|
||||
}
|
||||
|
||||
export enum BankRuleApplyIfTransactionType {
|
||||
Deposit = 'deposit',
|
||||
Withdrawal = 'withdrawal',
|
||||
}
|
||||
|
||||
// export interface BankRule {
|
||||
// id?: number;
|
||||
// name: string;
|
||||
// order?: number;
|
||||
// applyIfAccountId: number;
|
||||
// applyIfTransactionType: BankRuleApplyIfTransactionType;
|
||||
|
||||
// conditionsType: BankRuleConditionType;
|
||||
// conditions: IBankRuleCondition[];
|
||||
|
||||
// assignCategory: BankRuleAssignCategory;
|
||||
// assignAccountId: number;
|
||||
// assignPayee?: string;
|
||||
// assignMemo?: string;
|
||||
// }
|
||||
|
||||
export enum BankRuleAssignCategory {
|
||||
InterestIncome = 'InterestIncome',
|
||||
OtherIncome = 'OtherIncome',
|
||||
Deposit = 'Deposit',
|
||||
Expense = 'Expense',
|
||||
OwnerDrawings = 'OwnerDrawings',
|
||||
}
|
||||
|
||||
export type BankRuleComparator =
|
||||
| 'contains'
|
||||
| 'equals'
|
||||
| 'not_contains'
|
||||
| 'equal'
|
||||
| 'bigger'
|
||||
| 'bigger_or_equal'
|
||||
| 'smaller'
|
||||
| 'smaller_or_equal';
|
||||
|
||||
export interface IBankRuleConditionDTO {
|
||||
id?: number;
|
||||
field: string;
|
||||
comparator: BankRuleComparator;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IBankRuleCommonDTO {
|
||||
name: string;
|
||||
order?: number;
|
||||
applyIfAccountId: number;
|
||||
applyIfTransactionType: string;
|
||||
|
||||
conditions: IBankRuleConditionDTO[];
|
||||
|
||||
assignCategory: BankRuleAssignCategory;
|
||||
assignAccountId: number;
|
||||
assignPayee?: string;
|
||||
assignMemo?: string;
|
||||
}
|
||||
|
||||
export interface ICreateBankRuleDTO extends IBankRuleCommonDTO {}
|
||||
export interface IEditBankRuleDTO extends IBankRuleCommonDTO {}
|
||||
|
||||
export interface IBankRuleEventCreatingPayload {
|
||||
createRuleDTO: CreateBankRuleDto;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
export interface IBankRuleEventCreatedPayload {
|
||||
createRuleDTO: CreateBankRuleDto;
|
||||
bankRule: BankRule;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IBankRuleEventEditingPayload {
|
||||
ruleId: number;
|
||||
oldBankRule: any;
|
||||
editRuleDTO: EditBankRuleDto;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
export interface IBankRuleEventEditedPayload {
|
||||
oldBankRule: BankRule;
|
||||
bankRule: BankRule;
|
||||
editRuleDTO: EditBankRuleDto;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IBankRuleEventDeletingPayload {
|
||||
oldBankRule: any;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
export interface IBankRuleEventDeletedPayload {
|
||||
ruleId: number;
|
||||
trx?: Knex.Transaction;
|
||||
}
|
||||
Reference in New Issue
Block a user