mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ITaxRateActivatedPayload,
|
||||
ITaxRateActivatingPayload,
|
||||
} from '../TaxRates.types';
|
||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidator.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateTaxRateService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventEmitter - The event emitter.
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
* @param {CommandTaxRatesValidators} validators - The tax rates validators.
|
||||
* @param {typeof TaxRateModel} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Activates the given tax rate.
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public async activateTaxRate(taxRateId: number) {
|
||||
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
||||
|
||||
// Validates the tax rate existance.
|
||||
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||
|
||||
// Validates the tax rate inactive.
|
||||
this.validators.validateTaxRateNotActive(oldTaxRate);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onTaxRateActivating` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onActivating, {
|
||||
taxRateId,
|
||||
trx,
|
||||
} as ITaxRateActivatingPayload);
|
||||
|
||||
const taxRate = await this.taxRateModel()
|
||||
.query(trx)
|
||||
.findById(taxRateId)
|
||||
.patch({ active: true });
|
||||
|
||||
// Triggers `onTaxRateCreated` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onActivated, {
|
||||
taxRateId,
|
||||
trx,
|
||||
} as ITaxRateActivatedPayload);
|
||||
|
||||
return taxRate;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Knex } from 'knex';
|
||||
import { difference } from 'lodash';
|
||||
// import { IItemEntryDTO } from '@/modules/Items/';
|
||||
import { ERRORS } from '../constants';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { IItemEntryDTO } from '@/modules/TransactionItemEntry/ItemEntry.types';
|
||||
import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CommandTaxRatesValidators {
|
||||
/**
|
||||
* @param {TenantModelProxy<typeof TaxRateModel>} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Validates the tax rate existance.
|
||||
* @param {TaxRate | undefined | null} taxRate
|
||||
*/
|
||||
public validateTaxRateExistance(taxRate: TaxRateModel | undefined | null) {
|
||||
if (!taxRate) {
|
||||
throw new ServiceError(ERRORS.TAX_RATE_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given tax rate active.
|
||||
* @param {TaxRateModel} taxRate
|
||||
*/
|
||||
public validateTaxRateNotActive(taxRate: TaxRateModel) {
|
||||
if (taxRate.active) {
|
||||
throw new ServiceError(ERRORS.TAX_RATE_ALREADY_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the given tax rate inactive.
|
||||
* @param {TaxRateModel} taxRate
|
||||
*/
|
||||
public validateTaxRateNotInactive(taxRate: TaxRateModel) {
|
||||
if (!taxRate.active) {
|
||||
throw new ServiceError(ERRORS.TAX_RATE_ALREADY_INACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tax code uniquiness.
|
||||
* @param {number} tenantId
|
||||
* @param {string} taxCode
|
||||
* @param {Knex.Transaction} trx -
|
||||
*/
|
||||
public async validateTaxCodeUnique(taxCode: string, trx?: Knex.Transaction) {
|
||||
const foundTaxCode = await this.taxRateModel()
|
||||
.query(trx)
|
||||
.findOne({ code: taxCode });
|
||||
|
||||
if (foundTaxCode) {
|
||||
throw new ServiceError(ERRORS.TAX_CODE_NOT_UNIQUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tax codes of the given item entries DTO.
|
||||
* @param {IItemEntryDTO[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
public async validateItemEntriesTaxCode(itemEntriesDTO: ItemEntryDto[]) {
|
||||
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxCode);
|
||||
const taxCodes = filteredTaxEntries.map((e) => e.taxCode);
|
||||
|
||||
// Can't validate if there is no tax codes.
|
||||
if (taxCodes.length === 0) return;
|
||||
|
||||
const foundTaxCodes = await this.taxRateModel()
|
||||
.query()
|
||||
.whereIn('code', taxCodes);
|
||||
const foundCodes = foundTaxCodes.map((tax) => tax.code);
|
||||
|
||||
const notFoundTaxCodes = difference(taxCodes, foundCodes);
|
||||
|
||||
if (notFoundTaxCodes.length > 0) {
|
||||
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the tax rate id of the given item entries DTO.
|
||||
* @param {ItemEntryDto[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
public async validateItemEntriesTaxCodeId(itemEntriesDTO: ItemEntryDto[]) {
|
||||
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxRateId);
|
||||
const taxRatesIds = filteredTaxEntries.map((e) => e.taxRateId);
|
||||
|
||||
// Can't validate if there is no tax codes.
|
||||
if (taxRatesIds.length === 0) return;
|
||||
|
||||
const foundTaxCodes = await this.taxRateModel()
|
||||
.query()
|
||||
.whereIn('id', taxRatesIds);
|
||||
const foundTaxRatesIds = foundTaxCodes.map((tax) => tax.id);
|
||||
|
||||
const notFoundTaxCodes = difference(taxRatesIds, foundTaxRatesIds);
|
||||
|
||||
if (notFoundTaxCodes.length > 0) {
|
||||
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ICreateTaxRateDTO,
|
||||
ITaxRateCreatedPayload,
|
||||
ITaxRateCreatingPayload,
|
||||
} from '../TaxRates.types';
|
||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidator.service';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
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';
|
||||
import { CreateTaxRateDto } from '../dtos/TaxRate.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CreateTaxRate {
|
||||
/**
|
||||
* @param {EventEmitter2} eventEmitter - The event emitter.
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
* @param {CommandTaxRatesValidators} validators - The tax rates validators.
|
||||
* @param {typeof TaxRateModel} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new tax rate.
|
||||
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
||||
*/
|
||||
public async createTaxRate(
|
||||
createTaxRateDTO: CreateTaxRateDto,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
// Validates the tax code uniquiness.
|
||||
await this.validators.validateTaxCodeUnique(createTaxRateDTO.code, trx);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onTaxRateCreating` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onCreating, {
|
||||
createTaxRateDTO,
|
||||
trx,
|
||||
} as ITaxRateCreatingPayload);
|
||||
|
||||
const taxRate = await this.taxRateModel()
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...createTaxRateDTO,
|
||||
});
|
||||
|
||||
// Triggers `onTaxRateCreated` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onCreated, {
|
||||
createTaxRateDTO,
|
||||
taxRate,
|
||||
trx,
|
||||
} as ITaxRateCreatedPayload);
|
||||
|
||||
return taxRate;
|
||||
}, trx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ITaxRateDeletedPayload,
|
||||
ITaxRateDeletingPayload,
|
||||
} from '../TaxRates.types';
|
||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidator.service';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteTaxRateService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventEmitter - The event emitter.
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
* @param {CommandTaxRatesValidators} validators - The tax rates validators.
|
||||
* @param {typeof TaxRateModel} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given tax rate.
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async deleteTaxRate(taxRateId: number): Promise<void> {
|
||||
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
||||
|
||||
// Validates the tax rate existance.
|
||||
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onTaxRateDeleting` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onDeleting, {
|
||||
oldTaxRate,
|
||||
trx,
|
||||
} as ITaxRateDeletingPayload);
|
||||
|
||||
await this.taxRateModel().query(trx).findById(taxRateId).delete();
|
||||
|
||||
// Triggers `onTaxRateDeleted` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onDeleted, {
|
||||
oldTaxRate,
|
||||
trx,
|
||||
} as ITaxRateDeletedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
IEditTaxRateDTO,
|
||||
ITaxRateEditedPayload,
|
||||
ITaxRateEditingPayload,
|
||||
} from '../TaxRates.types';
|
||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidator.service';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { EditTaxRateDto } from '../dtos/TaxRate.dto';
|
||||
|
||||
@Injectable()
|
||||
export class EditTaxRateService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventEmitter - The event emitter.
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
* @param {CommandTaxRatesValidators} validators - The tax rates validators.
|
||||
* @param {TenantModelProxy<typeof TaxRateModel>} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Determines whether the tax rate, name or code have been changed.
|
||||
* @param {ITaxRate} taxRate
|
||||
* @param {IEditTaxRateDTO} editTaxRateDTO
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isTaxRateDTOChanged = (
|
||||
taxRate: TaxRateModel,
|
||||
editTaxRateDTO: EditTaxRateDto,
|
||||
) => {
|
||||
return (
|
||||
taxRate.rate !== editTaxRateDTO.rate ||
|
||||
taxRate.name !== editTaxRateDTO.name ||
|
||||
taxRate.code !== editTaxRateDTO.code
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Edits the given tax rate or creates a new if the rate or name have been changed.
|
||||
* @param {number} tenantId
|
||||
* @param {ITaxRate} oldTaxRate
|
||||
* @param {IEditTaxRateDTO} editTaxRateDTO
|
||||
* @param {Knex.Transaction} trx
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
private async editTaxRateOrCreate(
|
||||
oldTaxRate: TaxRateModel,
|
||||
editTaxRateDTO: EditTaxRateDto,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const isTaxDTOChanged = this.isTaxRateDTOChanged(
|
||||
oldTaxRate,
|
||||
editTaxRateDTO,
|
||||
);
|
||||
if (isTaxDTOChanged) {
|
||||
// Soft deleting the old tax rate.
|
||||
await this.taxRateModel().query(trx).findById(oldTaxRate.id).delete();
|
||||
|
||||
// Create a new tax rate with new edited data.
|
||||
return this.taxRateModel()
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...omit(oldTaxRate, ['id']),
|
||||
...editTaxRateDTO,
|
||||
});
|
||||
} else {
|
||||
return this.taxRateModel()
|
||||
.query(trx)
|
||||
.patchAndFetchById(oldTaxRate.id, {
|
||||
...editTaxRateDTO,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the given tax rate.
|
||||
* @param {number} taxRateId - The tax rate id.
|
||||
* @param {IEditTaxRateDTO} editTaxRateDTO - The tax rate data to edit.
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public async editTaxRate(taxRateId: number, editTaxRateDTO: EditTaxRateDto) {
|
||||
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
||||
|
||||
// Validates the tax rate existance.
|
||||
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onTaxRateEditing` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onEditing, {
|
||||
editTaxRateDTO,
|
||||
trx,
|
||||
} as ITaxRateEditingPayload);
|
||||
|
||||
const taxRate = await this.editTaxRateOrCreate(
|
||||
oldTaxRate,
|
||||
editTaxRateDTO,
|
||||
trx,
|
||||
);
|
||||
// Triggers `onTaxRateEdited` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onEdited, {
|
||||
editTaxRateDTO,
|
||||
oldTaxRate,
|
||||
taxRate,
|
||||
trx,
|
||||
} as ITaxRateEditedPayload);
|
||||
|
||||
return taxRate;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
ITaxRateActivatedPayload,
|
||||
ITaxRateActivatingPayload,
|
||||
} from '../TaxRates.types';
|
||||
import { Knex } from 'knex';
|
||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidator.service';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class InactivateTaxRateService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventEmitter - The event emitter.
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
* @param {CommandTaxRatesValidators} validators - The tax rates validators.
|
||||
* @param {typeof TaxRateModel} taxRateModel - The tax rate model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: TenantModelProxy<typeof TaxRateModel>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Edits the given tax rate.
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public async inactivateTaxRate(taxRateId: number) {
|
||||
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
||||
|
||||
// Validates the tax rate existance.
|
||||
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||
|
||||
// Validates the tax rate active.
|
||||
this.validators.validateTaxRateNotInactive(oldTaxRate);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onTaxRateActivating` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onInactivating, {
|
||||
taxRateId,
|
||||
trx,
|
||||
} as ITaxRateActivatingPayload);
|
||||
|
||||
const taxRate = await this.taxRateModel()
|
||||
.query(trx)
|
||||
.findById(taxRateId)
|
||||
.patch({ active: false });
|
||||
|
||||
// Triggers `onTaxRateCreated` event.
|
||||
await this.eventEmitter.emitAsync(events.taxRates.onInactivated, {
|
||||
taxRateId,
|
||||
trx,
|
||||
} as ITaxRateActivatedPayload);
|
||||
|
||||
return taxRate;
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user