mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
refactor: tax rates to nestjs
This commit is contained in:
@@ -34,6 +34,7 @@ import { TransformerModule } from '../Transformer/Transformer.module';
|
||||
import { AccountsModule } from '../Accounts/Accounts.module';
|
||||
import { ExpensesModule } from '../Expenses/Expenses.module';
|
||||
import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module';
|
||||
import { TaxRatesModule } from '../TaxRates/TaxRate.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -91,6 +92,7 @@ import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module';
|
||||
ItemCategoryModule,
|
||||
AccountsModule,
|
||||
ExpensesModule,
|
||||
TaxRatesModule
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { keyBy, sumBy } from 'lodash';
|
||||
// import { ItemEntry } from '@/models';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
// import { IItem, IItemEntry, IItemEntryDTO } from '@/interfaces';
|
||||
|
||||
// @Service()
|
||||
// export class ItemEntriesTaxTransactions {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
|
||||
// /**
|
||||
// * Associates tax amount withheld to the model.
|
||||
// * @param model
|
||||
// * @returns
|
||||
// */
|
||||
// public assocTaxAmountWithheldFromEntries(model: any) {
|
||||
// const entries = model.entries.map((entry) => ItemEntry.fromJson(entry));
|
||||
// const taxAmountWithheld = sumBy(entries, 'taxAmount');
|
||||
|
||||
// if (taxAmountWithheld) {
|
||||
// model.taxAmountWithheld = taxAmountWithheld;
|
||||
// }
|
||||
// return model;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Associates tax rate id from tax code to entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {} model
|
||||
// */
|
||||
// public assocTaxRateIdFromCodeToEntries =
|
||||
// (tenantId: number) => async (entries: any) => {
|
||||
// const entriesWithCode = entries.filter((entry) => entry.taxCode);
|
||||
// const taxCodes = entriesWithCode.map((entry) => entry.taxCode);
|
||||
|
||||
// const { TaxRate } = this.tenancy.models(tenantId);
|
||||
// const foundTaxCodes = await TaxRate.query().whereIn('code', taxCodes);
|
||||
|
||||
// const taxCodesMap = keyBy(foundTaxCodes, 'code');
|
||||
|
||||
// return entries.map((entry) => {
|
||||
// if (entry.taxCode) {
|
||||
// entry.taxRateId = taxCodesMap[entry.taxCode]?.id;
|
||||
// }
|
||||
// return entry;
|
||||
// });
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Associates tax rate from tax id to entries.
|
||||
// * @param {number} tenantId
|
||||
// * @returns {Promise<IItemEntry[]>}
|
||||
// */
|
||||
// public assocTaxRateFromTaxIdToEntries =
|
||||
// (tenantId: number) => async (entries: IItemEntry[]) => {
|
||||
// const entriesWithId = entries.filter((e) => e.taxRateId);
|
||||
// const taxRateIds = entriesWithId.map((e) => e.taxRateId);
|
||||
|
||||
// const { TaxRate } = this.tenancy.models(tenantId);
|
||||
// const foundTaxes = await TaxRate.query().whereIn('id', taxRateIds);
|
||||
|
||||
// const taxRatesMap = keyBy(foundTaxes, 'id');
|
||||
|
||||
// return entries.map((entry) => {
|
||||
// if (entry.taxRateId) {
|
||||
// entry.taxRate = taxRatesMap[entry.taxRateId]?.rate;
|
||||
// }
|
||||
// return entry;
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,55 @@
|
||||
// import { Knex } from 'knex';
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
|
||||
// @Service()
|
||||
// export class SyncItemTaxRateOnEditTaxRate {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to item default sell tax rate.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemId
|
||||
// * @param {number} sellTaxRateId
|
||||
// */
|
||||
// public updateItemSellTaxRate = async (
|
||||
// tenantId: number,
|
||||
// oldSellTaxRateId: number,
|
||||
// sellTaxRateId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
// // Can't continue if the old and new sell tax rate id are equal.
|
||||
// if (oldSellTaxRateId === sellTaxRateId) return;
|
||||
|
||||
// await Item.query().where('sellTaxRateId', oldSellTaxRateId).update({
|
||||
// sellTaxRateId,
|
||||
// });
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to item default purchase tax rate.
|
||||
// * @param {number} tenantId
|
||||
// * @param {number} itemId
|
||||
// * @param {number} purchaseTaxRateId
|
||||
// */
|
||||
// public updateItemPurchaseTaxRate = async (
|
||||
// tenantId: number,
|
||||
// oldPurchaseTaxRateId: number,
|
||||
// purchaseTaxRateId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) => {
|
||||
// const { Item } = this.tenancy.models(tenantId);
|
||||
|
||||
// // Can't continue if the old and new sell tax rate id are equal.
|
||||
// if (oldPurchaseTaxRateId === purchaseTaxRateId) return;
|
||||
|
||||
// await Item.query(trx)
|
||||
// .where('purchaseTaxRateId', oldPurchaseTaxRateId)
|
||||
// .update({
|
||||
// purchaseTaxRateId,
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,45 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { ITaxRateEditedPayload } from '@/interfaces';
|
||||
// import { runAfterTransaction } from '../UnitOfWork/TransactionsHooks';
|
||||
|
||||
// @Service()
|
||||
// export class SyncItemTaxRateOnEditTaxSubscriber {
|
||||
// @Inject()
|
||||
// private syncItemRateOnEdit: SyncItemTaxRateOnEditTaxRate;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handles.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.taxRates.onEdited,
|
||||
// this.handleSyncNewTaxRateToItemTaxRate
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Syncs the new tax rate created to default item tax rates.
|
||||
// * @param {ITaxRateEditedPayload} payload -
|
||||
// */
|
||||
// private handleSyncNewTaxRateToItemTaxRate = async ({
|
||||
// taxRate,
|
||||
// tenantId,
|
||||
// oldTaxRate,
|
||||
// trx,
|
||||
// }: ITaxRateEditedPayload) => {
|
||||
// runAfterTransaction(trx, async () => {
|
||||
// await this.syncItemRateOnEdit.updateItemPurchaseTaxRate(
|
||||
// tenantId,
|
||||
// oldTaxRate.id,
|
||||
// taxRate.id
|
||||
// );
|
||||
// await this.syncItemRateOnEdit.updateItemSellTaxRate(
|
||||
// tenantId,
|
||||
// oldTaxRate.id,
|
||||
// taxRate.id
|
||||
// );
|
||||
// });
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,89 @@
|
||||
import { CreateTaxRate } from './commands/CreateTaxRate.service';
|
||||
import { DeleteTaxRateService } from './commands/DeleteTaxRate.service';
|
||||
import { EditTaxRateService } from './commands/EditTaxRate.service';
|
||||
import { GetTaxRateService } from './queries/GetTaxRate.service';
|
||||
// import { GetTaxRatesService } from './queries/GetTaxRates';
|
||||
import { ActivateTaxRateService } from './commands/ActivateTaxRate.service';
|
||||
import { InactivateTaxRateService } from './commands/InactivateTaxRate';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ICreateTaxRateDTO, IEditTaxRateDTO } from './TaxRates.types';
|
||||
|
||||
@Injectable()
|
||||
export class TaxRatesApplication {
|
||||
constructor(
|
||||
private readonly createTaxRateService: CreateTaxRate,
|
||||
private readonly editTaxRateService: EditTaxRateService,
|
||||
private readonly deleteTaxRateService: DeleteTaxRateService,
|
||||
private readonly getTaxRateService: GetTaxRateService,
|
||||
private readonly activateTaxRateService: ActivateTaxRateService,
|
||||
private readonly inactivateTaxRateService: InactivateTaxRateService,
|
||||
// private readonly getTaxRatesService: GetTaxRatesService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new tax rate.
|
||||
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public createTaxRate(createTaxRateDTO: ICreateTaxRateDTO) {
|
||||
return this.createTaxRateService.createTaxRate(createTaxRateDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the given tax rate.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taxRateId
|
||||
* @param {IEditTaxRateDTO} taxRateEditDTO
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public editTaxRate(taxRateId: number, editTaxRateDTO: IEditTaxRateDTO) {
|
||||
return this.editTaxRateService.editTaxRate(taxRateId, editTaxRateDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given tax rate.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public deleteTaxRate(taxRateId: number) {
|
||||
return this.deleteTaxRateService.deleteTaxRate(taxRateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the given tax rate.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public getTaxRate(tenantId: number, taxRateId: number) {
|
||||
return this.getTaxRateService.getTaxRate(taxRateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tax rates list.
|
||||
* @param {number} tenantId
|
||||
* @returns {Promise<ITaxRate[]>}
|
||||
*/
|
||||
public getTaxRates(tenantId: number) {
|
||||
// return this.getTaxRatesService.getTaxRates(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the given tax rate.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taxRateId
|
||||
*/
|
||||
public activateTaxRate(taxRateId: number) {
|
||||
return this.activateTaxRateService.activateTaxRate(taxRateId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inactivates the given tax rate.
|
||||
* @param {number} tenantId
|
||||
* @param {number} taxRateId
|
||||
*/
|
||||
public inactivateTaxRate(taxRateId: number) {
|
||||
return this.inactivateTaxRateService.inactivateTaxRate(taxRateId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { TaxRatesApplication } from './TaxRate.application';
|
||||
import { ICreateTaxRateDTO, IEditTaxRateDTO } from './TaxRates.types';
|
||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||
|
||||
@Controller('tax-rates')
|
||||
@PublicRoute()
|
||||
export class TaxRatesController {
|
||||
constructor(private readonly taxRatesApplication: TaxRatesApplication) {}
|
||||
|
||||
@Post()
|
||||
public createTaxRate(@Body() createTaxRateDTO: ICreateTaxRateDTO) {
|
||||
return this.taxRatesApplication.createTaxRate(createTaxRateDTO);
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
public editTaxRate(
|
||||
@Param('id') taxRateId: number,
|
||||
@Body() editTaxRateDTO: IEditTaxRateDTO,
|
||||
) {
|
||||
return this.taxRatesApplication.editTaxRate(taxRateId, editTaxRateDTO);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
public deleteTaxRate(@Param('id') taxRateId: number) {
|
||||
return this.taxRatesApplication.deleteTaxRate(taxRateId);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
public getTaxRate(
|
||||
@Param('tenantId') tenantId: number,
|
||||
@Param('id') taxRateId: number,
|
||||
) {
|
||||
return this.taxRatesApplication.getTaxRate(tenantId, taxRateId);
|
||||
}
|
||||
|
||||
@Get()
|
||||
public getTaxRates(@Param('tenantId') tenantId: number) {
|
||||
return this.taxRatesApplication.getTaxRates(tenantId);
|
||||
}
|
||||
|
||||
@Put(':id/activate')
|
||||
public activateTaxRate(@Param('id') taxRateId: number) {
|
||||
return this.taxRatesApplication.activateTaxRate(taxRateId);
|
||||
}
|
||||
|
||||
@Put(':id/inactivate')
|
||||
public inactivateTaxRate(@Param('id') taxRateId: number) {
|
||||
return this.taxRatesApplication.inactivateTaxRate(taxRateId);
|
||||
}
|
||||
}
|
||||
30
packages/server-nest/src/modules/TaxRates/TaxRate.module.ts
Normal file
30
packages/server-nest/src/modules/TaxRates/TaxRate.module.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||
import { TaxRatesController } from './TaxRate.controller';
|
||||
import { CreateTaxRate } from './commands/CreateTaxRate.service';
|
||||
import { InactivateTaxRateService } from './commands/InactivateTaxRate';
|
||||
import { ActivateTaxRateService } from './commands/ActivateTaxRate.service';
|
||||
import { GetTaxRateService } from './queries/GetTaxRate.service';
|
||||
import { DeleteTaxRateService } from './commands/DeleteTaxRate.service';
|
||||
import { EditTaxRateService } from './commands/EditTaxRate.service';
|
||||
import { CommandTaxRatesValidators } from './commands/CommandTaxRatesValidator.service';
|
||||
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { TaxRatesApplication } from './TaxRate.application';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [TaxRatesController],
|
||||
providers: [
|
||||
CreateTaxRate,
|
||||
EditTaxRateService,
|
||||
DeleteTaxRateService,
|
||||
GetTaxRateService,
|
||||
ActivateTaxRateService,
|
||||
InactivateTaxRateService,
|
||||
CommandTaxRatesValidators,
|
||||
TransformerInjectable,
|
||||
TenancyContext,
|
||||
TaxRatesApplication
|
||||
],
|
||||
})
|
||||
export class TaxRatesModule {}
|
||||
90
packages/server-nest/src/modules/TaxRates/TaxRates.types.ts
Normal file
90
packages/server-nest/src/modules/TaxRates/TaxRates.types.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { Knex } from 'knex';
|
||||
import { TaxRateModel } from './models/TaxRate.model';
|
||||
|
||||
export interface ITaxRate {
|
||||
id?: number;
|
||||
name: string;
|
||||
code: string;
|
||||
rate: number;
|
||||
description: string;
|
||||
IsNonRecoverable: boolean;
|
||||
IsCompound: boolean;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface ICommonTaxRateDTO {
|
||||
name: string;
|
||||
code: string;
|
||||
rate: number;
|
||||
description: string;
|
||||
IsNonRecoverable: boolean;
|
||||
IsCompound: boolean;
|
||||
active: boolean;
|
||||
}
|
||||
export interface ICreateTaxRateDTO extends ICommonTaxRateDTO {}
|
||||
export interface IEditTaxRateDTO extends ICommonTaxRateDTO {}
|
||||
|
||||
export interface ITaxRateCreatingPayload {
|
||||
createTaxRateDTO: ICreateTaxRateDTO;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ITaxRateCreatedPayload {
|
||||
createTaxRateDTO: ICreateTaxRateDTO;
|
||||
taxRate: TaxRateModel;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ITaxRateEditingPayload {
|
||||
oldTaxRate: TaxRateModel;
|
||||
editTaxRateDTO: IEditTaxRateDTO;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ITaxRateEditedPayload {
|
||||
editTaxRateDTO: IEditTaxRateDTO;
|
||||
oldTaxRate: TaxRateModel;
|
||||
taxRate: TaxRateModel;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ITaxRateDeletingPayload {
|
||||
oldTaxRate: TaxRateModel;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ITaxRateActivatingPayload {
|
||||
taxRateId: number;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface ITaxRateActivatedPayload {
|
||||
taxRateId: number;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ITaxRateDeletedPayload {
|
||||
oldTaxRate: TaxRateModel;
|
||||
// tenantId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface ITaxTransaction {
|
||||
id?: number;
|
||||
taxRateId: number;
|
||||
referenceType: string;
|
||||
referenceId: number;
|
||||
rate: number;
|
||||
taxAccountId: number;
|
||||
}
|
||||
|
||||
export enum TaxRateAction {
|
||||
CREATE = 'Create',
|
||||
EDIT = 'Edit',
|
||||
DELETE = 'Delete',
|
||||
VIEW = 'View',
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Exportable } from '../Export/Exportable';
|
||||
// import { TaxRatesApplication } from './TaxRate.application';
|
||||
|
||||
// @Service()
|
||||
// export class TaxRatesExportable extends Exportable {
|
||||
// @Inject()
|
||||
// private taxRatesApplication: TaxRatesApplication;
|
||||
|
||||
// /**
|
||||
// * Retrieves the accounts data to exportable sheet.
|
||||
// * @param {number} tenantId
|
||||
// * @returns
|
||||
// */
|
||||
// public exportable(tenantId: number) {
|
||||
// return this.taxRatesApplication.getTaxRates(tenantId);
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,18 @@
|
||||
export const TaxRatesSampleData = [
|
||||
{
|
||||
'Tax Name': 'Value Added Tax',
|
||||
Code: 'VAT-STD',
|
||||
Rate: '20',
|
||||
Description: 'Standard VAT rate applied to most goods and services.',
|
||||
'Is Non Recoverable': 'F',
|
||||
Active: 'T',
|
||||
},
|
||||
{
|
||||
'Tax Name': 'Luxury Goods Tax',
|
||||
Code: 'TAX-LUXURY',
|
||||
Rate: '25',
|
||||
Description: 'Tax imposed on the sale of luxury items.',
|
||||
'Is Non Recoverable': 'T',
|
||||
Active: 'T',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,46 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Knex } from 'knex';
|
||||
// import { ICreateTaxRateDTO } from '@/interfaces';
|
||||
// import { CreateTaxRate } from './commands/CreateTaxRate.service';
|
||||
// import { Importable } from '../Import/Importable';
|
||||
// import { TaxRatesSampleData } from './TaxRatesImportable.SampleData';
|
||||
|
||||
// @Service()
|
||||
// export class TaxRatesImportable extends Importable {
|
||||
// @Inject()
|
||||
// private createTaxRateService: CreateTaxRate;
|
||||
|
||||
// /**
|
||||
// * Importing to tax rate creating service.
|
||||
// * @param {number} tenantId -
|
||||
// * @param {ICreateTaxRateDTO} ICreateTaxRateDTO -
|
||||
// * @param {Knex.Transaction} trx -
|
||||
// * @returns
|
||||
// */
|
||||
// public importable(
|
||||
// tenantId: number,
|
||||
// createAccountDTO: ICreateTaxRateDTO,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// return this.createTaxRateService.createTaxRate(
|
||||
// tenantId,
|
||||
// createAccountDTO,
|
||||
// trx
|
||||
// );
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Concurrrency controlling of the importing process.
|
||||
// * @returns {number}
|
||||
// */
|
||||
// public get concurrency() {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Retrieves the sample data that used to download accounts sample sheet.
|
||||
// */
|
||||
// public sampleData(): any[] {
|
||||
// return TaxRatesSampleData;
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,99 @@
|
||||
// import { sumBy, chain, keyBy } from 'lodash';
|
||||
// import { IItemEntry, ITaxTransaction } from '@/interfaces';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { Knex } from 'knex';
|
||||
|
||||
// @Service()
|
||||
// export class WriteTaxTransactionsItemEntries {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
|
||||
// /**
|
||||
// * Writes the tax transactions from the given item entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// */
|
||||
// public async writeTaxTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// itemEntries: IItemEntry[],
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// const { TaxRateTransaction, TaxRate } = this.tenancy.models(tenantId);
|
||||
// const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
||||
|
||||
// const entriesTaxRateIds = aggregatedEntries.map((entry) => entry.taxRateId);
|
||||
|
||||
// const taxRates = await TaxRate.query(trx).whereIn('id', entriesTaxRateIds);
|
||||
// const taxRatesById = keyBy(taxRates, 'id');
|
||||
|
||||
// const taxTransactions = aggregatedEntries.map((entry) => ({
|
||||
// taxRateId: entry.taxRateId,
|
||||
// referenceType: entry.referenceType,
|
||||
// referenceId: entry.referenceId,
|
||||
// rate: entry.taxRate || taxRatesById[entry.taxRateId]?.rate,
|
||||
// })) as ITaxTransaction[];
|
||||
|
||||
// await TaxRateTransaction.query(trx).upsertGraph(taxTransactions);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Rewrites the tax rate transactions from the given item entries.
|
||||
// * @param {number} tenantId
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// * @param {string} referenceType
|
||||
// * @param {number} referenceId
|
||||
// * @param {Knex.Transaction} trx
|
||||
// */
|
||||
// public async rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// itemEntries: IItemEntry[],
|
||||
// referenceType: string,
|
||||
// referenceId: number,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// await Promise.all([
|
||||
// this.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// referenceId,
|
||||
// referenceType,
|
||||
// trx
|
||||
// ),
|
||||
// this.writeTaxTransactionsFromItemEntries(tenantId, itemEntries, trx),
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Aggregates by tax code id and sums the amount.
|
||||
// * @param {IItemEntry[]} itemEntries
|
||||
// * @returns {IItemEntry[]}
|
||||
// */
|
||||
// private aggregateItemEntriesByTaxCode = (
|
||||
// itemEntries: IItemEntry[]
|
||||
// ): IItemEntry[] => {
|
||||
// return chain(itemEntries.filter((item) => item.taxRateId))
|
||||
// .groupBy((item) => item.taxRateId)
|
||||
// .values()
|
||||
// .map((group) => ({ ...group[0], amount: sumBy(group, 'amount') }))
|
||||
// .value();
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the tax transactions from the given item entries.
|
||||
// * @param {number} tenantId - Tenant id.
|
||||
// * @param {string} referenceType - Reference type.
|
||||
// * @param {number} referenceId - Reference id.
|
||||
// */
|
||||
// public async removeTaxTransactionsFromItemEntries(
|
||||
// tenantId: number,
|
||||
// referenceId: number,
|
||||
// referenceType: string,
|
||||
// trx?: Knex.Transaction
|
||||
// ) {
|
||||
// const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
||||
|
||||
// await TaxRateTransaction.query(trx)
|
||||
// .where({ referenceType, referenceId })
|
||||
// .delete();
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,59 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateTaxRateService {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: 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,111 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class CommandTaxRatesValidators {
|
||||
constructor(
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: 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 {number} tenantId
|
||||
* @param {IItemEntryDTO[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
// public async validateItemEntriesTaxCode(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
// 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 {IItemEntryDTO[]} itemEntriesDTO
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
// public async validateItemEntriesTaxCodeId(itemEntriesDTO: IItemEntryDTO[]) {
|
||||
// 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,63 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class CreateTaxRate {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: typeof TaxRateModel,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new tax rate.
|
||||
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
||||
*/
|
||||
public async createTaxRate(
|
||||
createTaxRateDTO: ICreateTaxRateDTO,
|
||||
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,51 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteTaxRateService {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: 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,108 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class EditTaxRateService {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: typeof TaxRateModel,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Detarmines whether the tax rate, name or code have been changed.
|
||||
* @param {ITaxRate} taxRate
|
||||
* @param {IEditTaxRateDTO} editTaxRateDTO
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isTaxRateDTOChanged = (
|
||||
taxRate: TaxRateModel,
|
||||
editTaxRateDTO: IEditTaxRateDTO
|
||||
) => {
|
||||
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: IEditTaxRateDTO,
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async editTaxRate(
|
||||
taxRateId: number,
|
||||
editTaxRateDTO: IEditTaxRateDTO
|
||||
) {
|
||||
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,59 @@
|
||||
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';
|
||||
|
||||
@Injectable()
|
||||
export class InactivateTaxRateService {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
8
packages/server-nest/src/modules/TaxRates/constants.ts
Normal file
8
packages/server-nest/src/modules/TaxRates/constants.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const ERRORS = {
|
||||
TAX_RATE_NOT_FOUND: 'TAX_RATE_NOT_FOUND',
|
||||
TAX_CODE_NOT_UNIQUE: 'TAX_CODE_NOT_UNIQUE',
|
||||
ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND: 'ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND',
|
||||
ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND: 'ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND',
|
||||
TAX_RATE_ALREADY_ACTIVE: 'TAX_RATE_ALREADY_ACTIVE',
|
||||
TAX_RATE_ALREADY_INACTIVE: 'TAX_RATE_ALREADY_INACTIVE'
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
import { mixin, Model, raw } from 'objection';
|
||||
// import TenantModel from 'models/TenantModel';
|
||||
// import ModelSearchable from './ModelSearchable';
|
||||
// import SoftDeleteQueryBuilder from '@/collection/SoftDeleteQueryBuilder';
|
||||
// import TaxRateMeta from './TaxRate.settings';
|
||||
// import ModelSetting from './ModelSetting';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
|
||||
export class TaxRateModel extends BaseModel {
|
||||
active!: boolean;
|
||||
code!: string;
|
||||
name!: string;
|
||||
rate!: number;
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'tax_rates';
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft delete query builder.
|
||||
*/
|
||||
// static get QueryBuilder() {
|
||||
// return SoftDeleteQueryBuilder;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Timestamps columns.
|
||||
*/
|
||||
get timestamps() {
|
||||
return ['createdAt', 'updatedAt'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tax rate meta.
|
||||
*/
|
||||
// static get meta() {
|
||||
// return TaxRateMeta;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Virtual attributes.
|
||||
*/
|
||||
static get virtualAttributes() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Model modifiers.
|
||||
*/
|
||||
static get modifiers() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Relationship mapping.
|
||||
*/
|
||||
static get relationMappings() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TaxRateTransformer } from './TaxRate.transformer';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
|
||||
@Injectable()
|
||||
export class GetTaxRateService {
|
||||
constructor(
|
||||
@Inject(TaxRateModel.name)
|
||||
private readonly taxRateModel: typeof TaxRateModel,
|
||||
private readonly validators: CommandTaxRatesValidators,
|
||||
private readonly transformer: TransformerInjectable,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieves the given tax rate.
|
||||
* @param {number} taxRateId
|
||||
* @returns {Promise<ITaxRate>}
|
||||
*/
|
||||
public async getTaxRate(taxRateId: number) {
|
||||
const taxRate = await this.taxRateModel.query().findById(taxRateId);
|
||||
|
||||
// Validates the tax rate existance.
|
||||
this.validators.validateTaxRateExistance(taxRate);
|
||||
|
||||
// Transforms the tax rate.
|
||||
return this.transformer.transform(
|
||||
taxRate,
|
||||
new TaxRateTransformer()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import HasTenancyService from '../Tenancy/TenancyService';
|
||||
// import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
|
||||
// import { TaxRateTransformer } from './TaxRate.transformer';
|
||||
|
||||
// @Service()
|
||||
// export class GetTaxRatesService {
|
||||
// @Inject()
|
||||
// private tenancy: HasTenancyService;
|
||||
|
||||
// @Inject()
|
||||
// private transformer: TransformerInjectable;
|
||||
|
||||
// /**
|
||||
// * Retrieves the tax rates list.
|
||||
// * @param {number} tenantId
|
||||
// * @returns {Promise<ITaxRate[]>}
|
||||
// */
|
||||
// public async getTaxRates(tenantId: number) {
|
||||
// const { TaxRate } = this.tenancy.models(tenantId);
|
||||
|
||||
// // Retrieves the tax rates.
|
||||
// const taxRates = await TaxRate.query().orderBy('name', 'ASC');
|
||||
|
||||
// // Transforms the tax rates.
|
||||
// return this.transformer.transform(
|
||||
// tenantId,
|
||||
// taxRates,
|
||||
// new TaxRateTransformer()
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Transformer } from '@/modules/Transformer/Transformer';
|
||||
import { TaxRateModel } from '../models/TaxRate.model';
|
||||
|
||||
export class TaxRateTransformer extends Transformer {
|
||||
/**
|
||||
* Include these attributes to tax rate object.
|
||||
* @returns {Array}
|
||||
*/
|
||||
public includeAttributes = (): string[] => {
|
||||
return ['nameFormatted', 'rateFormatted'];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the formatted rate.
|
||||
* @param taxRate
|
||||
* @returns {string}
|
||||
*/
|
||||
public rateFormatted = (taxRate: TaxRateModel): string => {
|
||||
return `${taxRate.rate}%`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the tax rate name.
|
||||
* @param taxRate
|
||||
* @returns {string}
|
||||
*/
|
||||
protected nameFormatted = (taxRate: TaxRateModel): string => {
|
||||
return `${taxRate.name} [${taxRate.rate}%]`;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import { IBillCreatingPayload, IBillEditingPayload } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
|
||||
// @Service()
|
||||
// export class BillTaxRateValidateSubscriber {
|
||||
// @Inject()
|
||||
// private taxRateDTOValidator: CommandTaxRatesValidators;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreating,
|
||||
// this.validateBillEntriesTaxCodeExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreating,
|
||||
// this.validateBillEntriesTaxIdExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEditing,
|
||||
// this.validateBillEntriesTaxCodeExistanceOnEditing
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEditing,
|
||||
// this.validateBillEntriesTaxIdExistanceOnEditing
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Validate bill entries tax rate code existance when creating.
|
||||
// * @param {IBillCreatingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxCodeExistanceOnCreating = async ({
|
||||
// billDTO,
|
||||
// tenantId,
|
||||
// }: IBillCreatingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validate the tax rate id existance when creating.
|
||||
// * @param {IBillCreatingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxIdExistanceOnCreating = async ({
|
||||
// billDTO,
|
||||
// tenantId,
|
||||
// }: IBillCreatingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validate bill entries tax rate code existance when editing.
|
||||
// * @param {IBillEditingPayload}
|
||||
// */
|
||||
// private validateBillEntriesTaxCodeExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// billDTO,
|
||||
// }: IBillEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validates the bill entries tax rate id existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload} payload -
|
||||
// */
|
||||
// private validateBillEntriesTaxIdExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// billDTO,
|
||||
// }: IBillEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// billDTO.entries
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,92 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// ISaleInvoiceCreatingPaylaod,
|
||||
// ISaleInvoiceEditingPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { CommandTaxRatesValidators } from '../commands/CommandTaxRatesValidator.service';
|
||||
|
||||
// @Service()
|
||||
// export class SaleInvoiceTaxRateValidateSubscriber {
|
||||
// @Inject()
|
||||
// private taxRateDTOValidator: CommandTaxRatesValidators;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreating,
|
||||
// this.validateSaleInvoiceEntriesTaxCodeExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreating,
|
||||
// this.validateSaleInvoiceEntriesTaxIdExistanceOnCreating
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEditing,
|
||||
// this.validateSaleInvoiceEntriesTaxCodeExistanceOnEditing
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEditing,
|
||||
// this.validateSaleInvoiceEntriesTaxIdExistanceOnEditing
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Validate invoice entries tax rate code existance when creating.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxCodeExistanceOnCreating = async ({
|
||||
// saleInvoiceDTO,
|
||||
// tenantId,
|
||||
// }: ISaleInvoiceCreatingPaylaod) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validate the tax rate id existance when creating.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxIdExistanceOnCreating = async ({
|
||||
// saleInvoiceDTO,
|
||||
// tenantId,
|
||||
// }: ISaleInvoiceCreatingPaylaod) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validate invoice entries tax rate code existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload}
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxCodeExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// saleInvoiceDTO,
|
||||
// }: ISaleInvoiceEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Validates the invoice entries tax rate id existance when editing.
|
||||
// * @param {ISaleInvoiceEditingPayload} payload -
|
||||
// */
|
||||
// private validateSaleInvoiceEntriesTaxIdExistanceOnEditing = async ({
|
||||
// tenantId,
|
||||
// saleInvoiceDTO,
|
||||
// }: ISaleInvoiceEditingPayload) => {
|
||||
// await this.taxRateDTOValidator.validateItemEntriesTaxCodeId(
|
||||
// tenantId,
|
||||
// saleInvoiceDTO.entries
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,87 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// IBIllEventDeletedPayload,
|
||||
// IBillCreatedPayload,
|
||||
// IBillEditedPayload,
|
||||
// ISaleInvoiceCreatedPayload,
|
||||
// ISaleInvoiceDeletedPayload,
|
||||
// ISaleInvoiceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
|
||||
// @Service()
|
||||
// export class WriteBillTaxTransactionsSubscriber {
|
||||
// @Inject()
|
||||
// private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.bill.onCreated,
|
||||
// this.writeInvoiceTaxTransactionsOnCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onEdited,
|
||||
// this.rewriteInvoiceTaxTransactionsOnEdited
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.bill.onDeleted,
|
||||
// this.removeInvoiceTaxTransactionsOnDeleted
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Writes the bill tax transactions on invoice created.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||
// tenantId,
|
||||
// bill,
|
||||
// trx,
|
||||
// }: IBillCreatedPayload) => {
|
||||
// await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// bill.entries,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Rewrites the bill tax transactions on invoice edited.
|
||||
// * @param {IBillEditedPayload} payload -
|
||||
// */
|
||||
// private rewriteInvoiceTaxTransactionsOnEdited = async ({
|
||||
// tenantId,
|
||||
// bill,
|
||||
// trx,
|
||||
// }: IBillEditedPayload) => {
|
||||
// await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// bill.entries,
|
||||
// 'Bill',
|
||||
// bill.id,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the invoice tax transactions on invoice deleted.
|
||||
// * @param {IBIllEventDeletedPayload}
|
||||
// */
|
||||
// private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||
// tenantId,
|
||||
// oldBill,
|
||||
// trx,
|
||||
// }: IBIllEventDeletedPayload) => {
|
||||
// await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// oldBill.id,
|
||||
// 'Bill',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -0,0 +1,84 @@
|
||||
// import { Inject, Service } from 'typedi';
|
||||
// import {
|
||||
// ISaleInvoiceCreatedPayload,
|
||||
// ISaleInvoiceDeletedPayload,
|
||||
// ISaleInvoiceEditedPayload,
|
||||
// } from '@/interfaces';
|
||||
// import events from '@/subscribers/events';
|
||||
// import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||
|
||||
// @Service()
|
||||
// export class WriteInvoiceTaxTransactionsSubscriber {
|
||||
// @Inject()
|
||||
// private writeTaxTransactions: WriteTaxTransactionsItemEntries;
|
||||
|
||||
// /**
|
||||
// * Attaches events with handlers.
|
||||
// */
|
||||
// public attach(bus) {
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onCreated,
|
||||
// this.writeInvoiceTaxTransactionsOnCreated
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onEdited,
|
||||
// this.rewriteInvoiceTaxTransactionsOnEdited
|
||||
// );
|
||||
// bus.subscribe(
|
||||
// events.saleInvoice.onDelete,
|
||||
// this.removeInvoiceTaxTransactionsOnDeleted
|
||||
// );
|
||||
// return bus;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Writes the invoice tax transactions on invoice created.
|
||||
// * @param {ISaleInvoiceCreatingPaylaod}
|
||||
// */
|
||||
// private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||
// tenantId,
|
||||
// saleInvoice,
|
||||
// trx
|
||||
// }: ISaleInvoiceCreatedPayload) => {
|
||||
// await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// saleInvoice.entries,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Rewrites the invoice tax transactions on invoice edited.
|
||||
// * @param {ISaleInvoiceEditedPayload} payload -
|
||||
// */
|
||||
// private rewriteInvoiceTaxTransactionsOnEdited = async ({
|
||||
// tenantId,
|
||||
// saleInvoice,
|
||||
// trx,
|
||||
// }: ISaleInvoiceEditedPayload) => {
|
||||
// await this.writeTaxTransactions.rewriteTaxRateTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// saleInvoice.entries,
|
||||
// 'SaleInvoice',
|
||||
// saleInvoice.id,
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * Removes the invoice tax transactions on invoice deleted.
|
||||
// * @param {ISaleInvoiceEditingPayload}
|
||||
// */
|
||||
// private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||
// tenantId,
|
||||
// oldSaleInvoice,
|
||||
// trx
|
||||
// }: ISaleInvoiceDeletedPayload) => {
|
||||
// await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||
// tenantId,
|
||||
// oldSaleInvoice.id,
|
||||
// 'SaleInvoice',
|
||||
// trx
|
||||
// );
|
||||
// };
|
||||
// }
|
||||
@@ -9,6 +9,7 @@ import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction
|
||||
import { Expense } from '@/modules/Expenses/models/Expense.model';
|
||||
import ExpenseCategory from '@/modules/Expenses/models/ExpenseCategory.model';
|
||||
import { ItemCategory } from '@/modules/ItemCategories/models/ItemCategory.model';
|
||||
import { TaxRateModel } from '@/modules/TaxRates/models/TaxRate.model';
|
||||
|
||||
const models = [
|
||||
Item,
|
||||
@@ -18,6 +19,7 @@ const models = [
|
||||
Expense,
|
||||
ExpenseCategory,
|
||||
ItemCategory,
|
||||
TaxRateModel
|
||||
];
|
||||
|
||||
const modelProviders = models.map((model) => {
|
||||
|
||||
36
packages/server-nest/test/tax-rates.e2e-spec.ts
Normal file
36
packages/server-nest/test/tax-rates.e2e-spec.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as request from 'supertest';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { app } from './init-app-test';
|
||||
|
||||
describe('Item Categories(e2e)', () => {
|
||||
it('/tax-rates (POST)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.post('/tax-rates')
|
||||
.set('organization-id', '4064541lv40nhca')
|
||||
.send({
|
||||
name: faker.person.fullName(),
|
||||
rate: 2,
|
||||
code: faker.string.uuid(),
|
||||
active: 1,
|
||||
})
|
||||
.expect(201);
|
||||
});
|
||||
|
||||
it('/tax-rates/:id (DELETE)', async () => {
|
||||
const response = await request(app.getHttpServer())
|
||||
.post('/tax-rates')
|
||||
.set('organization-id', '4064541lv40nhca')
|
||||
.send({
|
||||
name: faker.person.fullName(),
|
||||
rate: 2,
|
||||
code: faker.string.uuid(),
|
||||
active: 1,
|
||||
});
|
||||
const taxRateId = response.body.id;
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.delete(`/tax-rates/${taxRateId}`)
|
||||
.set('organization-id', '4064541lv40nhca')
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user