mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
fix(server): pull-request nodes
This commit is contained in:
@@ -40,7 +40,7 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
* Retrieves the sales tax liability summary.
|
||||||
* @param {Request} req -
|
* @param {Request} req -
|
||||||
* @param {Response} res -
|
* @param {Response} res -
|
||||||
* @param {NextFunction} next -
|
* @param {NextFunction} next -
|
||||||
@@ -50,7 +50,7 @@ export default class SalesTaxLiabilitySummary extends BaseFinancialReportControl
|
|||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
) {
|
) {
|
||||||
const { tenantId, settings } = req;
|
const { tenantId } = req;
|
||||||
const filter = this.matchedQueryData(req);
|
const filter = this.matchedQueryData(req);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -184,8 +184,15 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.trim()
|
.trim()
|
||||||
.escape(),
|
.escape(),
|
||||||
check('entries.*.tax_code').optional({ nullable: true }).trim().escape(),
|
check('entries.*.tax_code')
|
||||||
check('entries.*.tax_rate').optional().isNumeric().toFloat(),
|
.optional({ nullable: true })
|
||||||
|
.trim()
|
||||||
|
.escape()
|
||||||
|
.isString(),
|
||||||
|
check('entries.*.tax_rate_id')
|
||||||
|
.optional({ nullable: true })
|
||||||
|
.isNumeric()
|
||||||
|
.toInt(),
|
||||||
check('entries.*.warehouse_id')
|
check('entries.*.warehouse_id')
|
||||||
.optional({ nullable: true })
|
.optional({ nullable: true })
|
||||||
.isNumeric()
|
.isNumeric()
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import { body, param } from 'express-validator';
|
|||||||
import BaseController from '@/api/controllers/BaseController';
|
import BaseController from '@/api/controllers/BaseController';
|
||||||
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
import asyncMiddleware from '@/api/middleware/asyncMiddleware';
|
||||||
import { TaxRatesApplication } from '@/services/TaxRates/TaxRatesApplication';
|
import { TaxRatesApplication } from '@/services/TaxRates/TaxRatesApplication';
|
||||||
import { HookNextFunction } from 'mongoose';
|
import CheckAbilities from '@/api/middleware/CheckPolicies';
|
||||||
import { ServiceError } from '@/exceptions';
|
import { ServiceError } from '@/exceptions';
|
||||||
import { ERRORS } from '@/services/TaxRates/constants';
|
import { ERRORS } from '@/services/TaxRates/constants';
|
||||||
|
import { AbilitySubject, TaxRateAction } from '@/interfaces';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class TaxRatesController extends BaseController {
|
export class TaxRatesController extends BaseController {
|
||||||
@@ -21,6 +22,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/',
|
'/',
|
||||||
|
CheckAbilities(TaxRateAction.CREATE, AbilitySubject.TaxRate),
|
||||||
this.taxRateValidationSchema,
|
this.taxRateValidationSchema,
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.createTaxRate.bind(this)),
|
asyncMiddleware(this.createTaxRate.bind(this)),
|
||||||
@@ -28,6 +30,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/:id',
|
'/:id',
|
||||||
|
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
|
||||||
[param('id').exists().toInt(), ...this.taxRateValidationSchema],
|
[param('id').exists().toInt(), ...this.taxRateValidationSchema],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.editTaxRate.bind(this)),
|
asyncMiddleware(this.editTaxRate.bind(this)),
|
||||||
@@ -35,6 +38,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/:id/active',
|
'/:id/active',
|
||||||
|
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
|
||||||
[param('id').exists().toInt()],
|
[param('id').exists().toInt()],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.activateTaxRate.bind(this)),
|
asyncMiddleware(this.activateTaxRate.bind(this)),
|
||||||
@@ -42,6 +46,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.post(
|
router.post(
|
||||||
'/:id/inactive',
|
'/:id/inactive',
|
||||||
|
CheckAbilities(TaxRateAction.EDIT, AbilitySubject.TaxRate),
|
||||||
[param('id').exists().toInt()],
|
[param('id').exists().toInt()],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.inactivateTaxRate.bind(this)),
|
asyncMiddleware(this.inactivateTaxRate.bind(this)),
|
||||||
@@ -49,6 +54,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.delete(
|
router.delete(
|
||||||
'/:id',
|
'/:id',
|
||||||
|
CheckAbilities(TaxRateAction.DELETE, AbilitySubject.TaxRate),
|
||||||
[param('id').exists().toInt()],
|
[param('id').exists().toInt()],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.deleteTaxRate.bind(this)),
|
asyncMiddleware(this.deleteTaxRate.bind(this)),
|
||||||
@@ -56,6 +62,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/:id',
|
'/:id',
|
||||||
|
CheckAbilities(TaxRateAction.VIEW, AbilitySubject.TaxRate),
|
||||||
[param('id').exists().toInt()],
|
[param('id').exists().toInt()],
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getTaxRate.bind(this)),
|
asyncMiddleware(this.getTaxRate.bind(this)),
|
||||||
@@ -63,6 +70,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
'/',
|
'/',
|
||||||
|
CheckAbilities(TaxRateAction.VIEW, AbilitySubject.TaxRate),
|
||||||
this.validationResult,
|
this.validationResult,
|
||||||
asyncMiddleware(this.getTaxRates.bind(this)),
|
asyncMiddleware(this.getTaxRates.bind(this)),
|
||||||
this.handleServiceErrors
|
this.handleServiceErrors
|
||||||
@@ -81,7 +89,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
body('description').optional().trim().isString(),
|
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('is_compound').optional().isBoolean().default(false),
|
||||||
body('status').optional().toUpperCase().isIn(['ARCHIVED', 'ACTIVE']),
|
body('active').optional().isBoolean().default(false),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,12 +250,7 @@ export class TaxRatesController extends BaseController {
|
|||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @param {NextFunction} next
|
* @param {NextFunction} next
|
||||||
*/
|
*/
|
||||||
private handleServiceErrors(
|
private handleServiceErrors(error: Error, req: Request, res: Response, next) {
|
||||||
error: Error,
|
|
||||||
req: Request,
|
|
||||||
res: Response,
|
|
||||||
next: HookNextFunction
|
|
||||||
) {
|
|
||||||
if (error instanceof ServiceError) {
|
if (error instanceof ServiceError) {
|
||||||
if (error.errorType === ERRORS.TAX_CODE_NOT_UNIQUE) {
|
if (error.errorType === ERRORS.TAX_CODE_NOT_UNIQUE) {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ exports.up = (knex) => {
|
|||||||
.unsigned()
|
.unsigned()
|
||||||
.references('id')
|
.references('id')
|
||||||
.inTable('tax_rates');
|
.inTable('tax_rates');
|
||||||
table.string('tax_code');
|
|
||||||
table.decimal('tax_rate');
|
|
||||||
})
|
})
|
||||||
.table('sales_invoices', (table) => {
|
.table('sales_invoices', (table) => {
|
||||||
table.boolean('is_inclusive_tax').defaultTo(false);
|
table.boolean('is_inclusive_tax').defaultTo(false);
|
||||||
@@ -35,7 +33,7 @@ exports.up = (knex) => {
|
|||||||
.inTable('tax_rates');
|
.inTable('tax_rates');
|
||||||
table.string('reference_type');
|
table.string('reference_type');
|
||||||
table.integer('reference_id');
|
table.integer('reference_id');
|
||||||
table.decimal('tax_amount');
|
table.decimal('rate').unsigned();
|
||||||
table.integer('tax_account_id').unsigned();
|
table.integer('tax_account_id').unsigned();
|
||||||
})
|
})
|
||||||
.table('accounts_transactions', (table) => {
|
.table('accounts_transactions', (table) => {
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
exports.up = function (knex) {
|
|
||||||
return knex.table('sales_invoices', (table) => {
|
|
||||||
table.renameColumn('balance', 'amount');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.down = function (knex) {};
|
|
||||||
@@ -153,3 +153,11 @@ export enum AccountAction {
|
|||||||
VIEW = 'View',
|
VIEW = 'View',
|
||||||
TransactionsLocking = 'TransactionsLocking',
|
TransactionsLocking = 'TransactionsLocking',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum TaxRateAction {
|
||||||
|
CREATE = 'Create',
|
||||||
|
EDIT = 'Edit',
|
||||||
|
DELETE = 'Delete',
|
||||||
|
VIEW = 'View',
|
||||||
|
}
|
||||||
@@ -54,14 +54,6 @@ export interface IItemDTO {
|
|||||||
sellDescription: string;
|
sellDescription: string;
|
||||||
purchaseDescription: string;
|
purchaseDescription: string;
|
||||||
|
|
||||||
// Used as an override if the default Tax Code for the selected `costAccountId` is not correct
|
|
||||||
purchaseTaxCode: string;
|
|
||||||
purchaseTaxId: string;
|
|
||||||
|
|
||||||
// Used as an override if the default Tax Code for the selected `sellAccountId` is not correct
|
|
||||||
saleTaxCode: string;
|
|
||||||
saleTaxId: string;
|
|
||||||
|
|
||||||
quantityOnHand: number;
|
quantityOnHand: number;
|
||||||
|
|
||||||
note: string;
|
note: string;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ export interface IItemEntry {
|
|||||||
projectRefInvoicedAmount?: number;
|
projectRefInvoicedAmount?: number;
|
||||||
|
|
||||||
taxRateId: number | null;
|
taxRateId: number | null;
|
||||||
taxCode: string;
|
|
||||||
taxRate: number;
|
taxRate: number;
|
||||||
taxAmount: number;
|
taxAmount: number;
|
||||||
|
|
||||||
@@ -57,9 +56,8 @@ export interface IItemEntryDTO {
|
|||||||
projectRefType?: ProjectLinkRefType;
|
projectRefType?: ProjectLinkRefType;
|
||||||
projectRefInvoicedAmount?: number;
|
projectRefInvoicedAmount?: number;
|
||||||
|
|
||||||
taxCodeId?: number;
|
taxRateId?: number;
|
||||||
taxCode?: string;
|
taxCode?: string;
|
||||||
taxRate?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ProjectLinkRefType {
|
export enum ProjectLinkRefType {
|
||||||
|
|||||||
@@ -76,6 +76,13 @@ export interface ITaxTransaction {
|
|||||||
taxRateId: number;
|
taxRateId: number;
|
||||||
referenceType: string;
|
referenceType: string;
|
||||||
referenceId: number;
|
referenceId: number;
|
||||||
taxAmount: number;
|
rate: number;
|
||||||
taxAccountId: number;
|
taxAccountId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum TaxRateAction {
|
||||||
|
CREATE = 'Create',
|
||||||
|
EDIT = 'Edit',
|
||||||
|
DELETE = 'Delete',
|
||||||
|
VIEW = 'View',
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,8 +80,6 @@ import { ProjectBillableExpensesSubscriber } from '@/services/Projects/Projects/
|
|||||||
import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/ProjectBillableBillSubscriber';
|
import { ProjectBillableBillSubscriber } from '@/services/Projects/Projects/ProjectBillableBillSubscriber';
|
||||||
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
import { SyncActualTimeTaskSubscriber } from '@/services/Projects/Times/SyncActualTimeTaskSubscriber';
|
||||||
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
import { SaleInvoiceTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleInvoiceTaxRateValidateSubscriber';
|
||||||
import { SaleEstimateTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleEstimateTaxRateValidateSubscriber';
|
|
||||||
import { SaleReceiptTaxRateValidateSubscriber } from '@/services/TaxRates/subscribers/SaleReceiptTaxRateValidateSubscriber';
|
|
||||||
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
import { WriteInvoiceTaxTransactionsSubscriber } from '@/services/TaxRates/subscribers/WriteInvoiceTaxTransactionsSubscriber';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
@@ -192,8 +190,6 @@ export const susbcribers = () => {
|
|||||||
|
|
||||||
// Tax Rates
|
// Tax Rates
|
||||||
SaleInvoiceTaxRateValidateSubscriber,
|
SaleInvoiceTaxRateValidateSubscriber,
|
||||||
SaleEstimateTaxRateValidateSubscriber,
|
WriteInvoiceTaxTransactionsSubscriber,
|
||||||
SaleReceiptTaxRateValidateSubscriber,
|
|
||||||
WriteInvoiceTaxTransactionsSubscriber
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,30 +29,14 @@ export default class AccountTransaction extends TenantModel {
|
|||||||
* Virtual attributes.
|
* Virtual attributes.
|
||||||
*/
|
*/
|
||||||
static get virtualAttributes() {
|
static get virtualAttributes() {
|
||||||
return ['referenceTypeFormatted'];
|
return ['referenceTypeFormatted', 'creditLocal', 'debitLocal'];
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the credit amount in foreign currency.
|
|
||||||
* @return {number}
|
|
||||||
*/
|
|
||||||
get creditFcy() {
|
|
||||||
return this.credit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the debit amount in foreign currency.
|
|
||||||
* @return {number}
|
|
||||||
*/
|
|
||||||
get debitFcy() {
|
|
||||||
return this.debit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the credit amount in base currency.
|
* Retrieves the credit amount in base currency.
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
get creditBcy() {
|
get creditLocal() {
|
||||||
return this.credit * this.exchangeRate;
|
return this.credit * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,26 +44,10 @@ export default class AccountTransaction extends TenantModel {
|
|||||||
* Retrieves the debit amount in base currency.
|
* Retrieves the debit amount in base currency.
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
get debitBcy() {
|
get debitLocal() {
|
||||||
return this.debit * this.exchangeRate;
|
return this.debit * this.exchangeRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the tax amount in foreign currency.
|
|
||||||
* @return {number}
|
|
||||||
*/
|
|
||||||
get taxAmountFcy() {
|
|
||||||
return (this.creditFcy - this.debitFcy) * this.taxRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the tax amount in base currency.
|
|
||||||
* @return {number}
|
|
||||||
*/
|
|
||||||
get taxAmountBcy() {
|
|
||||||
return (this.creditBcy - this.debitBcy) * this.taxRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve formatted reference type.
|
* Retrieve formatted reference type.
|
||||||
* @return {string}
|
* @return {string}
|
||||||
|
|||||||
@@ -6,15 +6,11 @@ import {
|
|||||||
SalesTaxLiabilitySummaryTotal,
|
SalesTaxLiabilitySummaryTotal,
|
||||||
} from '@/interfaces/SalesTaxLiabilitySummary';
|
} from '@/interfaces/SalesTaxLiabilitySummary';
|
||||||
import { tableRowMapper } from '@/utils';
|
import { tableRowMapper } from '@/utils';
|
||||||
import { ITableColumn, ITableColumnAccessor, ITableRow } from '@/interfaces';
|
import { ITableColumn, ITableRow } from '@/interfaces';
|
||||||
import { FinancialSheetStructure } from '../FinancialSheetStructure';
|
import { FinancialSheetStructure } from '../FinancialSheetStructure';
|
||||||
import { FinancialTable } from '../FinancialTable';
|
import { FinancialTable } from '../FinancialTable';
|
||||||
import AgingReport from '../AgingSummary/AgingReport';
|
import AgingReport from '../AgingSummary/AgingReport';
|
||||||
|
import { IROW_TYPE } from './_constants';
|
||||||
enum IROW_TYPE {
|
|
||||||
TaxRate = 'TaxRate',
|
|
||||||
Total = 'Total',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SalesTaxLiabilitySummaryTable extends R.compose(
|
export class SalesTaxLiabilitySummaryTable extends R.compose(
|
||||||
FinancialSheetStructure,
|
FinancialSheetStructure,
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export enum IROW_TYPE {
|
||||||
|
TaxRate = 'TaxRate',
|
||||||
|
Total = 'Total',
|
||||||
|
}
|
||||||
@@ -70,20 +70,25 @@ export class CommandSaleInvoiceDTOTransformer {
|
|||||||
isInclusiveTax: saleInvoiceDTO.isInclusiveTax,
|
isInclusiveTax: saleInvoiceDTO.isInclusiveTax,
|
||||||
...entry,
|
...entry,
|
||||||
}));
|
}));
|
||||||
const entries = await composeAsync(
|
const asyncEntries = await composeAsync(
|
||||||
// Associate tax rate id from tax code to entries.
|
// Associate tax rate id from tax code to entries.
|
||||||
this.taxDTOTransformer.assocTaxRateIdFromCodeToEntries(tenantId),
|
this.taxDTOTransformer.assocTaxRateIdFromCodeToEntries(tenantId),
|
||||||
// Sets default cost and sell account to invoice items entries.
|
// Sets default cost and sell account to invoice items entries.
|
||||||
this.itemsEntriesService.setItemsEntriesDefaultAccounts(tenantId)
|
this.itemsEntriesService.setItemsEntriesDefaultAccounts(tenantId)
|
||||||
)(initialEntries);
|
)(initialEntries);
|
||||||
|
|
||||||
|
const entries = R.compose(
|
||||||
|
// Remove tax code from entries.
|
||||||
|
R.map(R.omit(['taxCode']))
|
||||||
|
)(asyncEntries);
|
||||||
|
|
||||||
const initialDTO = {
|
const initialDTO = {
|
||||||
...formatDateFields(
|
...formatDateFields(
|
||||||
omit(saleInvoiceDTO, ['delivered', 'entries', 'fromEstimateId']),
|
omit(saleInvoiceDTO, ['delivered', 'entries', 'fromEstimateId']),
|
||||||
['invoiceDate', 'dueDate']
|
['invoiceDate', 'dueDate']
|
||||||
),
|
),
|
||||||
// Avoid rewrite the deliver date in edit mode when already published.
|
// Avoid rewrite the deliver date in edit mode when already published.
|
||||||
amount,
|
balance: amount,
|
||||||
currencyCode: customer.currencyCode,
|
currencyCode: customer.currencyCode,
|
||||||
exchangeRate: saleInvoiceDTO.exchangeRate || 1,
|
exchangeRate: saleInvoiceDTO.exchangeRate || 1,
|
||||||
...(saleInvoiceDTO.delivered &&
|
...(saleInvoiceDTO.delivered &&
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
import { Inject, Service } from 'typedi';
|
||||||
import {
|
import {
|
||||||
ITaxRateActivatedPayload,
|
ITaxRateActivatedPayload,
|
||||||
ITaxRateActivatingPayload,
|
ITaxRateActivatingPayload,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import UnitOfWork from '../UnitOfWork';
|
import UnitOfWork from '../UnitOfWork';
|
||||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
import HasTenancyService from '../Tenancy/TenancyService';
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
import { Knex } from 'knex';
|
|
||||||
import { CommandTaxRatesValidators } from './CommandTaxRatesValidators';
|
import { CommandTaxRatesValidators } from './CommandTaxRatesValidators';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export class ActivateTaxRateService {
|
|||||||
private validators: CommandTaxRatesValidators;
|
private validators: CommandTaxRatesValidators;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the given tax rate.
|
* Activates the given tax rate.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {number} taxRateId
|
* @param {number} taxRateId
|
||||||
* @param {IEditTaxRateDTO} taxRateEditDTO
|
* @param {IEditTaxRateDTO} taxRateEditDTO
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export class CommandTaxRatesValidators {
|
|||||||
* Validates the tax codes of the given item entries DTO.
|
* Validates the tax codes of the given item entries DTO.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IItemEntryDTO[]} itemEntriesDTO
|
* @param {IItemEntryDTO[]} itemEntriesDTO
|
||||||
|
* @throws {ServiceError}
|
||||||
*/
|
*/
|
||||||
public async validateItemEntriesTaxCode(
|
public async validateItemEntriesTaxCode(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -92,17 +93,17 @@ export class CommandTaxRatesValidators {
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
itemEntriesDTO: IItemEntryDTO[]
|
itemEntriesDTO: IItemEntryDTO[]
|
||||||
) {
|
) {
|
||||||
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxCodeId);
|
const filteredTaxEntries = itemEntriesDTO.filter((e) => e.taxRateId);
|
||||||
const taxCodes = filteredTaxEntries.map((e) => e.taxCodeId);
|
const taxRatesIds = filteredTaxEntries.map((e) => e.taxRateId);
|
||||||
|
|
||||||
// Can't validate if there is no tax codes.
|
// Can't validate if there is no tax codes.
|
||||||
if (taxCodes.length === 0) return;
|
if (taxRatesIds.length === 0) return;
|
||||||
|
|
||||||
const { TaxRate } = this.tenancy.models(tenantId);
|
const { TaxRate } = this.tenancy.models(tenantId);
|
||||||
const foundTaxCodes = await TaxRate.query().whereIn('id', taxCodes);
|
const foundTaxCodes = await TaxRate.query().whereIn('id', taxRatesIds);
|
||||||
const foundCodes = foundTaxCodes.map((tax) => tax.id);
|
const foundTaxRatesIds = foundTaxCodes.map((tax) => tax.id);
|
||||||
|
|
||||||
const notFoundTaxCodes = difference(taxCodes, foundCodes);
|
const notFoundTaxCodes = difference(taxRatesIds, foundTaxRatesIds);
|
||||||
|
|
||||||
if (notFoundTaxCodes.length > 0) {
|
if (notFoundTaxCodes.length > 0) {
|
||||||
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND);
|
throw new ServiceError(ERRORS.ITEM_ENTRY_TAX_RATE_ID_NOT_FOUND);
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ export class CreateTaxRate {
|
|||||||
trx,
|
trx,
|
||||||
} as ITaxRateCreatingPayload);
|
} as ITaxRateCreatingPayload);
|
||||||
|
|
||||||
const taxRate = await TaxRate.query(trx).insert({ ...createTaxRateDTO });
|
const taxRate = await TaxRate.query(trx).insertAndFetch({
|
||||||
|
...createTaxRateDTO,
|
||||||
|
});
|
||||||
|
|
||||||
// Triggers `onTaxRateCreated` event.
|
// Triggers `onTaxRateCreated` event.
|
||||||
await this.eventPublisher.emitAsync(events.taxRates.onCreated, {
|
await this.eventPublisher.emitAsync(events.taxRates.onCreated, {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { sumBy, chain, keyBy } from 'lodash';
|
|||||||
import { IItemEntry, ITaxTransaction } from '@/interfaces';
|
import { IItemEntry, ITaxTransaction } from '@/interfaces';
|
||||||
import HasTenancyService from '../Tenancy/TenancyService';
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class WriteTaxTransactionsItemEntries {
|
export class WriteTaxTransactionsItemEntries {
|
||||||
@@ -15,24 +16,51 @@ export class WriteTaxTransactionsItemEntries {
|
|||||||
*/
|
*/
|
||||||
public async writeTaxTransactionsFromItemEntries(
|
public async writeTaxTransactionsFromItemEntries(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
itemEntries: IItemEntry[]
|
itemEntries: IItemEntry[],
|
||||||
|
trx?: Knex.Transaction
|
||||||
) {
|
) {
|
||||||
const { TaxRateTransaction, TaxRate } = this.tenancy.models(tenantId);
|
const { TaxRateTransaction, TaxRate } = this.tenancy.models(tenantId);
|
||||||
const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
const aggregatedEntries = this.aggregateItemEntriesByTaxCode(itemEntries);
|
||||||
|
|
||||||
const entriesTaxRateIds = aggregatedEntries.map((entry) => entry.taxRateId);
|
const entriesTaxRateIds = aggregatedEntries.map((entry) => entry.taxRateId);
|
||||||
|
|
||||||
const taxRates = await TaxRate.query().whereIn('id', entriesTaxRateIds);
|
const taxRates = await TaxRate.query(trx).whereIn('id', entriesTaxRateIds);
|
||||||
const taxRatesById = keyBy(taxRates, 'id');
|
const taxRatesById = keyBy(taxRates, 'id');
|
||||||
|
|
||||||
const taxTransactions = aggregatedEntries.map((entry) => ({
|
const taxTransactions = aggregatedEntries.map((entry) => ({
|
||||||
taxRateId: entry.taxRateId,
|
taxRateId: entry.taxRateId,
|
||||||
referenceType: entry.referenceType,
|
referenceType: entry.referenceType,
|
||||||
referenceId: entry.referenceId,
|
referenceId: entry.referenceId,
|
||||||
taxAmount: entry.taxRate || taxRatesById[entry.taxRateId]?.rate,
|
rate: entry.taxRate || taxRatesById[entry.taxRateId]?.rate,
|
||||||
})) as ITaxTransaction[];
|
})) as ITaxTransaction[];
|
||||||
|
|
||||||
await TaxRateTransaction.query().upsertGraph(taxTransactions);
|
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),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,11 +87,12 @@ export class WriteTaxTransactionsItemEntries {
|
|||||||
public async removeTaxTransactionsFromItemEntries(
|
public async removeTaxTransactionsFromItemEntries(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
referenceId: number,
|
referenceId: number,
|
||||||
referenceType: string
|
referenceType: string,
|
||||||
|
trx?: Knex.Transaction
|
||||||
) {
|
) {
|
||||||
const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
const { TaxRateTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
await TaxRateTransaction.query()
|
await TaxRateTransaction.query(trx)
|
||||||
.where({ referenceType, referenceId })
|
.where({ referenceType, referenceId })
|
||||||
.delete();
|
.delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import {
|
|
||||||
ISaleEstimateCreatingPayload,
|
|
||||||
ISaleEstimateEditingPayload,
|
|
||||||
ISaleInvoiceCreatingPaylaod,
|
|
||||||
ISaleInvoiceEditingPayload,
|
|
||||||
} from '@/interfaces';
|
|
||||||
import events from '@/subscribers/events';
|
|
||||||
import { CommandTaxRatesValidators } from '../CommandTaxRatesValidators';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class SaleEstimateTaxRateValidateSubscriber {
|
|
||||||
@Inject()
|
|
||||||
private taxRateDTOValidator: CommandTaxRatesValidators;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches events with handlers.
|
|
||||||
*/
|
|
||||||
public attach(bus) {
|
|
||||||
bus.subscribe(
|
|
||||||
events.saleEstimate.onCreating,
|
|
||||||
this.validateSaleEstimateEntriesTaxCodeExistanceOnCreating
|
|
||||||
);
|
|
||||||
bus.subscribe(
|
|
||||||
events.saleEstimate.onEditing,
|
|
||||||
this.validateSaleEstimateEntriesTaxCodeExistanceOnEditing
|
|
||||||
);
|
|
||||||
return bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate invoice entries tax rate code existance.
|
|
||||||
* @param {ISaleInvoiceCreatingPaylaod}
|
|
||||||
*/
|
|
||||||
private validateSaleEstimateEntriesTaxCodeExistanceOnCreating = async ({
|
|
||||||
estimateDTO,
|
|
||||||
tenantId,
|
|
||||||
}: ISaleEstimateCreatingPayload) => {
|
|
||||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
|
||||||
tenantId,
|
|
||||||
estimateDTO.entries
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {ISaleInvoiceEditingPayload}
|
|
||||||
*/
|
|
||||||
private validateSaleEstimateEntriesTaxCodeExistanceOnEditing = async ({
|
|
||||||
tenantId,
|
|
||||||
estimateDTO,
|
|
||||||
}: ISaleEstimateEditingPayload) => {
|
|
||||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
|
||||||
tenantId,
|
|
||||||
estimateDTO.entries
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,10 @@ export class SaleInvoiceTaxRateValidateSubscriber {
|
|||||||
events.saleInvoice.onEditing,
|
events.saleInvoice.onEditing,
|
||||||
this.validateSaleInvoiceEntriesTaxCodeExistanceOnEditing
|
this.validateSaleInvoiceEntriesTaxCodeExistanceOnEditing
|
||||||
);
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onEditing,
|
||||||
|
this.validateSaleInvoiceEntriesTaxIdExistanceOnEditing
|
||||||
|
);
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,4 +75,18 @@ export class SaleInvoiceTaxRateValidateSubscriber {
|
|||||||
saleInvoiceDTO.entries
|
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
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import { Inject, Service } from 'typedi';
|
|
||||||
import {
|
|
||||||
ISaleReceiptCreatingPayload,
|
|
||||||
ISaleReceiptEditingPayload,
|
|
||||||
} from '@/interfaces';
|
|
||||||
import events from '@/subscribers/events';
|
|
||||||
import { CommandTaxRatesValidators } from '../CommandTaxRatesValidators';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class SaleReceiptTaxRateValidateSubscriber {
|
|
||||||
@Inject()
|
|
||||||
private taxRateDTOValidator: CommandTaxRatesValidators;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attaches events with handlers.
|
|
||||||
*/
|
|
||||||
public attach(bus) {
|
|
||||||
bus.subscribe(
|
|
||||||
events.saleReceipt.onCreating,
|
|
||||||
this.validateSaleReceiptEntriesTaxCodeExistanceOnCreating
|
|
||||||
);
|
|
||||||
bus.subscribe(
|
|
||||||
events.saleReceipt.onEditing,
|
|
||||||
this.validateSaleReceiptEntriesTaxCodeExistanceOnEditing
|
|
||||||
);
|
|
||||||
return bus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate receipt entries tax rate code existance.
|
|
||||||
* @param {ISaleInvoiceCreatingPaylaod}
|
|
||||||
*/
|
|
||||||
private validateSaleReceiptEntriesTaxCodeExistanceOnCreating = async ({
|
|
||||||
tenantId,
|
|
||||||
saleReceiptDTO,
|
|
||||||
}: ISaleReceiptCreatingPayload) => {
|
|
||||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
|
||||||
tenantId,
|
|
||||||
saleReceiptDTO.entries
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {ISaleInvoiceEditingPayload}
|
|
||||||
*/
|
|
||||||
private validateSaleReceiptEntriesTaxCodeExistanceOnEditing = async ({
|
|
||||||
tenantId,
|
|
||||||
saleReceiptDTO,
|
|
||||||
}: ISaleReceiptEditingPayload) => {
|
|
||||||
await this.taxRateDTOValidator.validateItemEntriesTaxCode(
|
|
||||||
tenantId,
|
|
||||||
saleReceiptDTO.entries
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ import { Inject, Service } from 'typedi';
|
|||||||
import {
|
import {
|
||||||
ISaleInvoiceCreatedPayload,
|
ISaleInvoiceCreatedPayload,
|
||||||
ISaleInvoiceDeletedPayload,
|
ISaleInvoiceDeletedPayload,
|
||||||
|
ISaleInvoiceEditedPayload,
|
||||||
} from '@/interfaces';
|
} from '@/interfaces';
|
||||||
import events from '@/subscribers/events';
|
import events from '@/subscribers/events';
|
||||||
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
import { WriteTaxTransactionsItemEntries } from '../WriteTaxTransactionsItemEntries';
|
||||||
@@ -19,6 +20,10 @@ export class WriteInvoiceTaxTransactionsSubscriber {
|
|||||||
events.saleInvoice.onCreated,
|
events.saleInvoice.onCreated,
|
||||||
this.writeInvoiceTaxTransactionsOnCreated
|
this.writeInvoiceTaxTransactionsOnCreated
|
||||||
);
|
);
|
||||||
|
bus.subscribe(
|
||||||
|
events.saleInvoice.onEdited,
|
||||||
|
this.rewriteInvoiceTaxTransactionsOnEdited
|
||||||
|
);
|
||||||
bus.subscribe(
|
bus.subscribe(
|
||||||
events.saleInvoice.onDelete,
|
events.saleInvoice.onDelete,
|
||||||
this.removeInvoiceTaxTransactionsOnDeleted
|
this.removeInvoiceTaxTransactionsOnDeleted
|
||||||
@@ -27,16 +32,36 @@ export class WriteInvoiceTaxTransactionsSubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate receipt entries tax rate code existance.
|
* Writes the invoice tax transactions on invoice created.
|
||||||
* @param {ISaleInvoiceCreatingPaylaod}
|
* @param {ISaleInvoiceCreatingPaylaod}
|
||||||
*/
|
*/
|
||||||
private writeInvoiceTaxTransactionsOnCreated = async ({
|
private writeInvoiceTaxTransactionsOnCreated = async ({
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoice,
|
saleInvoice,
|
||||||
|
trx
|
||||||
}: ISaleInvoiceCreatedPayload) => {
|
}: ISaleInvoiceCreatedPayload) => {
|
||||||
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
await this.writeTaxTransactions.writeTaxTransactionsFromItemEntries(
|
||||||
tenantId,
|
tenantId,
|
||||||
saleInvoice.entries
|
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
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,11 +72,13 @@ export class WriteInvoiceTaxTransactionsSubscriber {
|
|||||||
private removeInvoiceTaxTransactionsOnDeleted = async ({
|
private removeInvoiceTaxTransactionsOnDeleted = async ({
|
||||||
tenantId,
|
tenantId,
|
||||||
oldSaleInvoice,
|
oldSaleInvoice,
|
||||||
|
trx
|
||||||
}: ISaleInvoiceDeletedPayload) => {
|
}: ISaleInvoiceDeletedPayload) => {
|
||||||
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
await this.writeTaxTransactions.removeTaxTransactionsFromItemEntries(
|
||||||
tenantId,
|
tenantId,
|
||||||
oldSaleInvoice.id,
|
oldSaleInvoice.id,
|
||||||
'SaleInvoice'
|
'SaleInvoice',
|
||||||
|
trx
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user