mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
268 lines
7.1 KiB
TypeScript
268 lines
7.1 KiB
TypeScript
import { Inject, Service } from 'typedi';
|
|
import Currencies from 'js-money/lib/currency';
|
|
import {
|
|
ICurrencyEditDTO,
|
|
ICurrencyDTO,
|
|
ICurrenciesService,
|
|
ICurrency,
|
|
} from 'interfaces';
|
|
import {
|
|
EventDispatcher,
|
|
EventDispatcherInterface,
|
|
} from 'decorators/eventDispatcher';
|
|
import { ServiceError } from 'exceptions';
|
|
import TenancyService from 'services/Tenancy/TenancyService';
|
|
|
|
const ERRORS = {
|
|
CURRENCY_NOT_FOUND: 'currency_not_found',
|
|
CURRENCY_CODE_EXISTS: 'currency_code_exists',
|
|
BASE_CURRENCY_INVALID: 'BASE_CURRENCY_INVALID',
|
|
CANNOT_DELETE_BASE_CURRENCY: 'CANNOT_DELETE_BASE_CURRENCY'
|
|
};
|
|
|
|
@Service()
|
|
export default class CurrenciesService implements ICurrenciesService {
|
|
@Inject('logger')
|
|
logger: any;
|
|
|
|
@EventDispatcher()
|
|
eventDispatcher: EventDispatcherInterface;
|
|
|
|
@Inject()
|
|
tenancy: TenancyService;
|
|
|
|
/**
|
|
* Retrieve currency by given currency code or throw not found error.
|
|
* @param {number} tenantId
|
|
* @param {string} currencyCode
|
|
* @param {number} currencyId
|
|
*/
|
|
private async validateCurrencyCodeUniquiness(
|
|
tenantId: number,
|
|
currencyCode: string,
|
|
currencyId?: number
|
|
) {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
|
|
this.logger.info(
|
|
'[currencies] trying to validate currency code existance.',
|
|
{ tenantId, currencyCode }
|
|
);
|
|
const foundCurrency = await Currency.query().onBuild((query) => {
|
|
query.findOne('currency_code', currencyCode);
|
|
|
|
if (currencyId) {
|
|
query.whereNot('id', currencyId);
|
|
}
|
|
});
|
|
if (foundCurrency) {
|
|
this.logger.info('[currencies] the currency code already exists.', {
|
|
tenantId,
|
|
currencyCode,
|
|
});
|
|
throw new ServiceError(ERRORS.CURRENCY_CODE_EXISTS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve currency by the given currency code or throw service error.
|
|
* @param {number} tenantId
|
|
* @param {string} currencyCode
|
|
*/
|
|
private async getCurrencyByCodeOrThrowError(
|
|
tenantId: number,
|
|
currencyCode: string
|
|
) {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
|
|
this.logger.info(
|
|
'[currencies] trying to validate currency code existance.',
|
|
{ tenantId, currencyCode }
|
|
);
|
|
const foundCurrency = await Currency.query().findOne(
|
|
'currency_code',
|
|
currencyCode
|
|
);
|
|
|
|
if (!foundCurrency) {
|
|
this.logger.info('[currencies] the given currency code not exists.', {
|
|
tenantId,
|
|
currencyCode,
|
|
});
|
|
throw new ServiceError(ERRORS.CURRENCY_NOT_FOUND);
|
|
}
|
|
return foundCurrency;
|
|
}
|
|
|
|
/**
|
|
* Retrieve currency by given id or throw not found error.
|
|
* @param {number} tenantId
|
|
* @param {number} currencyId
|
|
*/
|
|
private async getCurrencyIdOrThrowError(
|
|
tenantId: number,
|
|
currencyId: number
|
|
) {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
|
|
this.logger.info(
|
|
'[currencies] trying to validate currency by id existance.',
|
|
{ tenantId, currencyId }
|
|
);
|
|
const foundCurrency = await Currency.query().findOne('id', currencyId);
|
|
|
|
if (!foundCurrency) {
|
|
this.logger.info('[currencies] the currency code not found.', {
|
|
tenantId,
|
|
currencyId,
|
|
});
|
|
throw new ServiceError(ERRORS.CURRENCY_NOT_FOUND);
|
|
}
|
|
return foundCurrency;
|
|
}
|
|
|
|
/**
|
|
* Creates a new currency.
|
|
* @param {number} tenantId
|
|
* @param {ICurrencyDTO} currencyDTO
|
|
*/
|
|
public async newCurrency(tenantId: number, currencyDTO: ICurrencyDTO) {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
this.logger.info('[currencies] try to insert new currency.', {
|
|
tenantId,
|
|
currencyDTO,
|
|
});
|
|
// Validate currency code uniquiness.
|
|
await this.validateCurrencyCodeUniquiness(
|
|
tenantId,
|
|
currencyDTO.currencyCode
|
|
);
|
|
|
|
await Currency.query().insert({ ...currencyDTO });
|
|
this.logger.info('[currencies] the currency inserted successfully.', {
|
|
tenantId,
|
|
currencyDTO,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Edit details of the given currency.
|
|
* @param {number} tenantId
|
|
* @param {number} currencyId
|
|
* @param {ICurrencyDTO} currencyDTO
|
|
*/
|
|
public async editCurrency(
|
|
tenantId: number,
|
|
currencyId: number,
|
|
currencyDTO: ICurrencyEditDTO
|
|
): Promise<ICurrency> {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
|
|
this.logger.info('[currencies] try to edit currency.', {
|
|
tenantId,
|
|
currencyId,
|
|
currencyDTO,
|
|
});
|
|
await this.getCurrencyIdOrThrowError(tenantId, currencyId);
|
|
|
|
const currency = await Currency.query().patchAndFetchById(currencyId, {
|
|
...currencyDTO,
|
|
});
|
|
this.logger.info('[currencies] the currency edited successfully.', {
|
|
tenantId,
|
|
currencyDTO,
|
|
});
|
|
|
|
return currency;
|
|
}
|
|
|
|
/**
|
|
* Validate cannot delete base currency.
|
|
* @param {number} tenantId
|
|
* @param {string} currencyCode
|
|
*/
|
|
validateCannotDeleteBaseCurrency(tenantId: number, currencyCode: string) {
|
|
const settings = this.tenancy.settings(tenantId);
|
|
const baseCurrency = settings.get({
|
|
group: 'organization',
|
|
key: 'base_currency',
|
|
});
|
|
if (baseCurrency === currencyCode) {
|
|
throw new ServiceError(ERRORS.CANNOT_DELETE_BASE_CURRENCY);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete the given currency code.
|
|
* @param {number} tenantId
|
|
* @param {string} currencyCode
|
|
* @return {Promise<}
|
|
*/
|
|
public async deleteCurrency(
|
|
tenantId: number,
|
|
currencyCode: string
|
|
): Promise<void> {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
this.logger.info('[currencies] trying to delete the given currency.', {
|
|
tenantId,
|
|
currencyCode,
|
|
});
|
|
|
|
await this.getCurrencyByCodeOrThrowError(tenantId, currencyCode);
|
|
|
|
// Validate currency code not equals base currency.
|
|
await this.validateCannotDeleteBaseCurrency(tenantId, currencyCode);
|
|
|
|
await Currency.query().where('currency_code', currencyCode).delete();
|
|
this.logger.info('[currencies] the currency deleted successfully.', {
|
|
tenantId,
|
|
currencyCode,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Listing currencies.
|
|
* @param {number} tenantId
|
|
* @return {Promise<ICurrency[]>}
|
|
*/
|
|
public async listCurrencies(tenantId: number): Promise<ICurrency[]> {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
|
|
const settings = this.tenancy.settings(tenantId);
|
|
const baseCurrency = settings.get({
|
|
group: 'organization',
|
|
key: 'base_currency',
|
|
});
|
|
|
|
const currencies = await Currency.query().onBuild((query) => {
|
|
query.orderBy('createdAt', 'ASC');
|
|
});
|
|
const formattedCurrencies = currencies.map((currency) => ({
|
|
isBaseCurrency: baseCurrency === currency.currencyCode,
|
|
...currency,
|
|
}));
|
|
return formattedCurrencies;
|
|
}
|
|
|
|
/**
|
|
* Seeds the given base currency to the currencies list.
|
|
* @param {number} tenantId
|
|
* @param {string} baseCurrency
|
|
*/
|
|
public async seedBaseCurrency(tenantId: number, baseCurrency: string) {
|
|
const { Currency } = this.tenancy.models(tenantId);
|
|
const currencyMeta = Currencies[baseCurrency];
|
|
|
|
const foundBaseCurrency = await Currency.query().findOne(
|
|
'currency_code',
|
|
baseCurrency
|
|
);
|
|
if (!foundBaseCurrency) {
|
|
await Currency.query().insert({
|
|
currency_code: currencyMeta.code,
|
|
currency_name: currencyMeta.name,
|
|
});
|
|
}
|
|
}
|
|
}
|