mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +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 { AccountsModule } from '../Accounts/Accounts.module';
|
||||||
import { ExpensesModule } from '../Expenses/Expenses.module';
|
import { ExpensesModule } from '../Expenses/Expenses.module';
|
||||||
import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module';
|
import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module';
|
||||||
|
import { TaxRatesModule } from '../TaxRates/TaxRate.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -91,6 +92,7 @@ import { ItemCategoryModule } from '../ItemCategories/ItemCategory.module';
|
|||||||
ItemCategoryModule,
|
ItemCategoryModule,
|
||||||
AccountsModule,
|
AccountsModule,
|
||||||
ExpensesModule,
|
ExpensesModule,
|
||||||
|
TaxRatesModule
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [
|
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 { Expense } from '@/modules/Expenses/models/Expense.model';
|
||||||
import ExpenseCategory from '@/modules/Expenses/models/ExpenseCategory.model';
|
import ExpenseCategory from '@/modules/Expenses/models/ExpenseCategory.model';
|
||||||
import { ItemCategory } from '@/modules/ItemCategories/models/ItemCategory.model';
|
import { ItemCategory } from '@/modules/ItemCategories/models/ItemCategory.model';
|
||||||
|
import { TaxRateModel } from '@/modules/TaxRates/models/TaxRate.model';
|
||||||
|
|
||||||
const models = [
|
const models = [
|
||||||
Item,
|
Item,
|
||||||
@@ -18,6 +19,7 @@ const models = [
|
|||||||
Expense,
|
Expense,
|
||||||
ExpenseCategory,
|
ExpenseCategory,
|
||||||
ItemCategory,
|
ItemCategory,
|
||||||
|
TaxRateModel
|
||||||
];
|
];
|
||||||
|
|
||||||
const modelProviders = models.map((model) => {
|
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