mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 14:50:32 +00:00
feat(server): wip activate/inactivate tax rate
This commit is contained in:
@@ -33,6 +33,20 @@ export class TaxRatesController extends BaseController {
|
|||||||
asyncMiddleware(this.editTaxRate.bind(this)),
|
asyncMiddleware(this.editTaxRate.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
);
|
);
|
||||||
|
router.post(
|
||||||
|
'/:id/active',
|
||||||
|
[param('id').exists().toInt()],
|
||||||
|
this.validationResult,
|
||||||
|
asyncMiddleware(this.activateTaxRate.bind(this)),
|
||||||
|
this.handleServiceErrors
|
||||||
|
);
|
||||||
|
router.post(
|
||||||
|
'/:id/inactive',
|
||||||
|
[param('id').exists().toInt()],
|
||||||
|
this.validationResult,
|
||||||
|
asyncMiddleware(this.inactivateTaxRate.bind(this)),
|
||||||
|
this.handleServiceErrors
|
||||||
|
);
|
||||||
router.delete(
|
router.delete(
|
||||||
'/:id',
|
'/:id',
|
||||||
[param('id').exists().toInt()],
|
[param('id').exists().toInt()],
|
||||||
@@ -64,7 +78,9 @@ export class TaxRatesController extends BaseController {
|
|||||||
body('name').exists(),
|
body('name').exists(),
|
||||||
body('code').exists().isString(),
|
body('code').exists().isString(),
|
||||||
body('rate').exists().isNumeric().toFloat(),
|
body('rate').exists().isNumeric().toFloat(),
|
||||||
|
body('description').optional().trim().isString(),
|
||||||
body('is_non_recoverable').optional().isBoolean().default(false),
|
body('is_non_recoverable').optional().isBoolean().default(false),
|
||||||
|
body('is_compound').optional().isBoolean().default(false),
|
||||||
body('status').optional().toUpperCase().isIn(['ARCHIVED', 'ACTIVE']),
|
body('status').optional().toUpperCase().isIn(['ARCHIVED', 'ACTIVE']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -173,6 +189,52 @@ export class TaxRatesController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inactivates the given tax rate.
|
||||||
|
* @param req
|
||||||
|
* @param res
|
||||||
|
* @param next
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async inactivateTaxRate(req: Request, res: Response, next) {
|
||||||
|
const { tenantId } = req;
|
||||||
|
const { id: taxRateId } = req.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.taxRatesApplication.inactivateTaxRate(tenantId, taxRateId);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
id: taxRateId,
|
||||||
|
message: 'The given tax rate has been inactivated successfully.',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inactivates the given tax rate.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async activateTaxRate(req: Request, res: Response, next) {
|
||||||
|
const { tenantId } = req;
|
||||||
|
const { id: taxRateId } = req.params;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.taxRatesApplication.activateTaxRate(tenantId, taxRateId);
|
||||||
|
|
||||||
|
return res.status(200).send({
|
||||||
|
id: taxRateId,
|
||||||
|
message: 'The given tax rate has been activated successfully.',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles service errors.
|
* Handles service errors.
|
||||||
* @param {Error} error
|
* @param {Error} error
|
||||||
@@ -197,6 +259,16 @@ export class TaxRatesController extends BaseController {
|
|||||||
errors: [{ type: ERRORS.TAX_RATE_NOT_FOUND, code: 200 }],
|
errors: [{ type: ERRORS.TAX_RATE_NOT_FOUND, code: 200 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (error.errorType === ERRORS.TAX_RATE_ALREADY_INACTIVE) {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: ERRORS.TAX_RATE_ALREADY_INACTIVE, code: 300 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (error.errorType === ERRORS.TAX_RATE_ALREADY_ACTIVE) {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: ERRORS.TAX_RATE_ALREADY_ACTIVE, code: 400 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ exports.up = (knex) => {
|
|||||||
table.string('name');
|
table.string('name');
|
||||||
table.string('code');
|
table.string('code');
|
||||||
table.decimal('rate');
|
table.decimal('rate');
|
||||||
|
table.string('description');
|
||||||
table.boolean('is_non_recoverable');
|
table.boolean('is_non_recoverable');
|
||||||
table.boolean('is_compound');
|
table.boolean('is_compound');
|
||||||
table.integer('status');
|
table.boolean('active').defaultTo(false);
|
||||||
|
table.date('deleted_at');
|
||||||
table.timestamps();
|
table.timestamps();
|
||||||
})
|
})
|
||||||
.table('items_entries', (table) => {
|
.table('items_entries', (table) => {
|
||||||
@@ -43,9 +45,6 @@ exports.up = (knex) => {
|
|||||||
.references('id')
|
.references('id')
|
||||||
.inTable('tax_rates');
|
.inTable('tax_rates');
|
||||||
table.decimal('tax_rate').unsigned();
|
table.decimal('tax_rate').unsigned();
|
||||||
})
|
|
||||||
.table('sales_invoices', (table) => {
|
|
||||||
table.rename('balance', 'amount');
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
exports.up = function (knex) {
|
||||||
|
return knex.table('sales_invoices', (table) => {
|
||||||
|
table.renameColumn('balance', 'amount');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (knex) {};
|
||||||
@@ -5,14 +5,20 @@ export interface ITaxRate {
|
|||||||
name: string;
|
name: string;
|
||||||
code: string;
|
code: string;
|
||||||
rate: number;
|
rate: number;
|
||||||
|
description: string;
|
||||||
|
IsNonRecoverable: boolean;
|
||||||
|
IsCompound: boolean;
|
||||||
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICommonTaxRateDTO {
|
export interface ICommonTaxRateDTO {
|
||||||
name: string;
|
name: string;
|
||||||
code: string;
|
code: string;
|
||||||
rate: number;
|
rate: number;
|
||||||
|
description: string;
|
||||||
IsNonRecoverable: boolean;
|
IsNonRecoverable: boolean;
|
||||||
IsCompound: boolean;
|
IsCompound: boolean;
|
||||||
|
active: boolean;
|
||||||
}
|
}
|
||||||
export interface ICreateTaxRateDTO extends ICommonTaxRateDTO {}
|
export interface ICreateTaxRateDTO extends ICommonTaxRateDTO {}
|
||||||
export interface IEditTaxRateDTO extends ICommonTaxRateDTO {}
|
export interface IEditTaxRateDTO extends ICommonTaxRateDTO {}
|
||||||
@@ -47,6 +53,18 @@ export interface ITaxRateDeletingPayload {
|
|||||||
tenantId: number;
|
tenantId: number;
|
||||||
trx: Knex.Transaction;
|
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 {
|
export interface ITaxRateDeletedPayload {
|
||||||
oldTaxRate: ITaxRate;
|
oldTaxRate: ITaxRate;
|
||||||
tenantId: number;
|
tenantId: number;
|
||||||
|
|||||||
64
packages/server/src/services/TaxRates/ActivateTaxRate.ts
Normal file
64
packages/server/src/services/TaxRates/ActivateTaxRate.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import {
|
||||||
|
ITaxRateActivatedPayload,
|
||||||
|
ITaxRateActivatingPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import UnitOfWork from '../UnitOfWork';
|
||||||
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
import { CommandTaxRatesValidators } from './CommandTaxRatesValidators';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ActivateTaxRateService {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private eventPublisher: EventPublisher;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private uow: UnitOfWork;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private validators: CommandTaxRatesValidators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the given tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} taxRateId
|
||||||
|
* @param {IEditTaxRateDTO} taxRateEditDTO
|
||||||
|
* @returns {Promise<ITaxRate>}
|
||||||
|
*/
|
||||||
|
public activateTaxRate(tenantId: number, taxRateId: number) {
|
||||||
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const oldTaxRate = TaxRate.query().findById(taxRateId);
|
||||||
|
|
||||||
|
// Validates the tax rate existance.
|
||||||
|
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||||
|
|
||||||
|
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||||
|
// Triggers `onTaxRateActivating` event.
|
||||||
|
await this.eventPublisher.emitAsync(events.taxRates.onActivating, {
|
||||||
|
taxRateId,
|
||||||
|
tenantId,
|
||||||
|
trx,
|
||||||
|
} as ITaxRateActivatingPayload);
|
||||||
|
|
||||||
|
const taxRate = await TaxRate.query(trx)
|
||||||
|
.findById(taxRateId)
|
||||||
|
.patch({ active: 1 });
|
||||||
|
|
||||||
|
// Triggers `onTaxRateCreated` event.
|
||||||
|
await this.eventPublisher.emitAsync(events.taxRates.onActivated, {
|
||||||
|
taxRateId,
|
||||||
|
tenantId,
|
||||||
|
trx,
|
||||||
|
} as ITaxRateActivatedPayload);
|
||||||
|
|
||||||
|
return taxRate;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,26 @@ export class CommandTaxRatesValidators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given tax rate active.
|
||||||
|
* @param {ITaxRate} taxRate
|
||||||
|
*/
|
||||||
|
public validateTaxRateNotActive(taxRate: ITaxRate) {
|
||||||
|
if (taxRate.active) {
|
||||||
|
throw new ServiceError(ERRORS.TAX_RATE_ALREADY_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given tax rate inactive.
|
||||||
|
* @param {ITaxRate} taxRate
|
||||||
|
*/
|
||||||
|
public validateTaxRateNotInactive(taxRate: ITaxRate) {
|
||||||
|
if (!taxRate.active) {
|
||||||
|
throw new ServiceError(ERRORS.TAX_RATE_ALREADY_INACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the tax code uniquiness.
|
* Validates the tax code uniquiness.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
|
|||||||
67
packages/server/src/services/TaxRates/InactivateTaxRate.ts
Normal file
67
packages/server/src/services/TaxRates/InactivateTaxRate.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import {
|
||||||
|
ITaxRateActivatedPayload,
|
||||||
|
ITaxRateActivatingPayload,
|
||||||
|
} from '@/interfaces';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import UnitOfWork from '../UnitOfWork';
|
||||||
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
import { CommandTaxRatesValidators } from './CommandTaxRatesValidators';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class InactivateTaxRateService {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private eventPublisher: EventPublisher;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private uow: UnitOfWork;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private validators: CommandTaxRatesValidators;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the given tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} taxRateId
|
||||||
|
* @param {IEditTaxRateDTO} taxRateEditDTO
|
||||||
|
* @returns {Promise<ITaxRate>}
|
||||||
|
*/
|
||||||
|
public inactivateTaxRate(tenantId: number, taxRateId: number) {
|
||||||
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const oldTaxRate = TaxRate.query().findById(taxRateId);
|
||||||
|
|
||||||
|
// Validates the tax rate existance.
|
||||||
|
this.validators.validateTaxRateExistance(oldTaxRate);
|
||||||
|
|
||||||
|
//
|
||||||
|
this.validators.validateTaxRateNotInactive(oldTaxRate);
|
||||||
|
|
||||||
|
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||||
|
// Triggers `onTaxRateActivating` event.
|
||||||
|
await this.eventPublisher.emitAsync(events.taxRates.onInactivating, {
|
||||||
|
taxRateId,
|
||||||
|
tenantId,
|
||||||
|
trx,
|
||||||
|
} as ITaxRateActivatingPayload);
|
||||||
|
|
||||||
|
const taxRate = await TaxRate.query(trx)
|
||||||
|
.findById(taxRateId)
|
||||||
|
.patch({ active: 0 });
|
||||||
|
|
||||||
|
// Triggers `onTaxRateCreated` event.
|
||||||
|
await this.eventPublisher.emitAsync(events.taxRates.onInactivated, {
|
||||||
|
taxRateId,
|
||||||
|
tenantId,
|
||||||
|
trx,
|
||||||
|
} as ITaxRateActivatedPayload);
|
||||||
|
|
||||||
|
return taxRate;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ import { DeleteTaxRateService } from './DeleteTaxRate';
|
|||||||
import { EditTaxRateService } from './EditTaxRate';
|
import { EditTaxRateService } from './EditTaxRate';
|
||||||
import { GetTaxRateService } from './GetTaxRate';
|
import { GetTaxRateService } from './GetTaxRate';
|
||||||
import { GetTaxRatesService } from './GetTaxRates';
|
import { GetTaxRatesService } from './GetTaxRates';
|
||||||
|
import { ActivateTaxRateService } from './ActivateTaxRate';
|
||||||
|
import { InactivateTaxRateService } from './InactivateTaxRate';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class TaxRatesApplication {
|
export class TaxRatesApplication {
|
||||||
@@ -23,6 +25,12 @@ export class TaxRatesApplication {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private getTaxRatesService: GetTaxRatesService;
|
private getTaxRatesService: GetTaxRatesService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private activateTaxRateService: ActivateTaxRateService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private inactivateTaxRateService: InactivateTaxRateService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new tax rate.
|
* Creates a new tax rate.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -80,4 +88,22 @@ export class TaxRatesApplication {
|
|||||||
public getTaxRates(tenantId: number) {
|
public getTaxRates(tenantId: number) {
|
||||||
return this.getTaxRatesService.getTaxRates(tenantId);
|
return this.getTaxRatesService.getTaxRates(tenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activates the given tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} taxRateId
|
||||||
|
*/
|
||||||
|
public activateTaxRate(tenantId: number, taxRateId: number) {
|
||||||
|
return this.activateTaxRateService.activateTaxRate(tenantId, taxRateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inactivates the given tax rate.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} taxRateId
|
||||||
|
*/
|
||||||
|
public inactivateTaxRate(tenantId: number, taxRateId: number) {
|
||||||
|
return this.inactivateTaxRateService.inactivateTaxRate(tenantId, taxRateId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,6 @@ export const ERRORS = {
|
|||||||
TAX_CODE_NOT_UNIQUE: 'TAX_CODE_NOT_UNIQUE',
|
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_CODE_NOT_FOUND: 'ITEM_ENTRY_TAX_RATE_CODE_NOT_FOUND',
|
||||||
ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND: 'ITEM_ENTRY_TAX_RATE_ID_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'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -570,5 +570,11 @@ export default {
|
|||||||
|
|
||||||
onDeleting: 'onTaxRateDeleting',
|
onDeleting: 'onTaxRateDeleting',
|
||||||
onDeleted: 'onTaxRateDeleted',
|
onDeleted: 'onTaxRateDeleted',
|
||||||
|
|
||||||
|
onActivating: 'onTaxRateActivating',
|
||||||
|
onActivated: 'onTaxRateActivated',
|
||||||
|
|
||||||
|
onInactivating: 'onTaxRateInactivating',
|
||||||
|
onInactivated: 'onTaxRateInactivated'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user