mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
refactor: currencies service.
refactor: exchange rates service.
This commit is contained in:
@@ -49,7 +49,7 @@ export default class AuthenticationService {
|
||||
* @param {string} password - Password.
|
||||
* @return {Promise<{user: IUser, token: string}>}
|
||||
*/
|
||||
async signIn(emailOrPhone: string, password: string): Promise<{user: IUser, token: string, tenant: ITenant }> {
|
||||
async signIn(emailOrPhone: string, password: string): Promise<{user: ISystemUser, token: string, tenant: ITenant }> {
|
||||
this.logger.info('[login] Someone trying to login.', { emailOrPhone, password });
|
||||
|
||||
const { systemUserRepository } = this.sysRepositories;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Inject, Service } from 'typedi';
|
||||
import { difference, upperFirst } from 'lodash';
|
||||
import { ServiceError } from "exceptions";
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import {
|
||||
import {
|
||||
IContact,
|
||||
IContactNewDTO,
|
||||
IContactEditDTO,
|
||||
|
||||
152
server/src/services/Currencies/CurrenciesService.ts
Normal file
152
server/src/services/Currencies/CurrenciesService.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { Inject, Container, Service } from 'typedi';
|
||||
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'
|
||||
};
|
||||
|
||||
@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 });
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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 currencies = await Currency.query().onBuild((query) => {
|
||||
query.orderBy('createdAt', 'ASC');
|
||||
});
|
||||
return currencies;
|
||||
}
|
||||
}
|
||||
166
server/src/services/ExchangeRates/ExchangeRatesService.ts
Normal file
166
server/src/services/ExchangeRates/ExchangeRatesService.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import moment from 'moment';
|
||||
import { difference } from 'lodash';
|
||||
import { Service, Inject } from 'typedi';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
} from 'decorators/eventDispatcher';
|
||||
import {
|
||||
IExchangeRateDTO,
|
||||
IExchangeRate,
|
||||
IExchangeRatesService,
|
||||
IExchangeRateEditDTO,
|
||||
IExchangeRateFilter,
|
||||
} from 'interfaces';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
|
||||
const ERRORS = {
|
||||
NOT_FOUND_EXCHANGE_RATES: 'NOT_FOUND_EXCHANGE_RATES',
|
||||
EXCHANGE_RATE_PERIOD_EXISTS: 'EXCHANGE_RATE_PERIOD_EXISTS',
|
||||
EXCHANGE_RATE_NOT_FOUND: 'EXCHANGE_RATE_NOT_FOUND',
|
||||
};
|
||||
|
||||
@Service()
|
||||
export default class ExchangeRatesService implements IExchangeRatesService {
|
||||
@Inject('logger')
|
||||
logger: any;
|
||||
|
||||
@EventDispatcher()
|
||||
eventDispatcher: EventDispatcherInterface;
|
||||
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Creates a new exchange rate.
|
||||
* @param {number} tenantId
|
||||
* @param {IExchangeRateDTO} exchangeRateDTO
|
||||
* @returns {Promise<IExchangeRate>}
|
||||
*/
|
||||
public async newExchangeRate(tenantId: number, exchangeRateDTO: IExchangeRateDTO): Promise<IExchangeRate> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[exchange_rates] trying to insert new exchange rate.', { tenantId, exchangeRateDTO });
|
||||
await this.validateExchangeRatePeriodExistance(tenantId, exchangeRateDTO);
|
||||
|
||||
const exchangeRate = await ExchangeRate.query().insertAndFetch({
|
||||
...exchangeRateDTO,
|
||||
date: moment(exchangeRateDTO.date).format('YYYY-MM-DD'),
|
||||
});
|
||||
this.logger.info('[exchange_rates] inserted successfully.', { tenantId, exchangeRateDTO });
|
||||
return exchangeRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the exchange rate details.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} exchangeRateId - Exchange rate id.
|
||||
* @param {IExchangeRateEditDTO} editExRateDTO - Edit exchange rate DTO.
|
||||
*/
|
||||
public async editExchangeRate(tenantId: number, exchangeRateId: number, editExRateDTO: IExchangeRateEditDTO): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[exchange_rates] trying to edit exchange rate.', { tenantId, exchangeRateId, editExRateDTO });
|
||||
await this.validateExchangeRateExistance(tenantId, exchangeRateId);
|
||||
|
||||
await ExchangeRate.query().where('id', exchangeRateId).update({ ...editExRateDTO });
|
||||
this.logger.info('[exchange_rates] exchange rate edited successfully.', { tenantId, exchangeRateId, editExRateDTO });
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the given exchange rate.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} exchangeRateId - Exchange rate id.
|
||||
*/
|
||||
public async deleteExchangeRate(tenantId: number, exchangeRateId: number): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
await this.validateExchangeRateExistance(tenantId, exchangeRateId);
|
||||
|
||||
await ExchangeRate.query().findById(exchangeRateId).delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listing exchange rates details.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IExchangeRateFilter} exchangeRateFilter - Exchange rates list filter.
|
||||
*/
|
||||
public async listExchangeRates(tenantId: number, exchangeRateFilter: IExchangeRateFilter): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
const exchangeRates = await ExchangeRate.query()
|
||||
.pagination(exchangeRateFilter.page - 1, exchangeRateFilter.pageSize);
|
||||
|
||||
return exchangeRates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes exchange rates in bulk.
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} exchangeRatesIds
|
||||
*/
|
||||
public async deleteBulkExchangeRates(tenantId: number, exchangeRatesIds: number[]): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[exchange_rates] trying delete in bulk.', { tenantId, exchangeRatesIds });
|
||||
await this.validateExchangeRatesIdsExistance(tenantId, exchangeRatesIds);
|
||||
|
||||
await ExchangeRate.query().whereIn('id', exchangeRatesIds).delete();
|
||||
this.logger.info('[exchange_rates] deleted successfully.', { tenantId, exchangeRatesIds });
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates period of the exchange rate existance.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IExchangeRateDTO} exchangeRateDTO - Exchange rate DTO.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
private async validateExchangeRatePeriodExistance(tenantId: number, exchangeRateDTO: IExchangeRateDTO): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[exchange_rates] trying to validate period existance.', { tenantId });
|
||||
const foundExchangeRate = await ExchangeRate.query()
|
||||
.where('currency_code', exchangeRateDTO.currencyCode)
|
||||
.where('date', exchangeRateDTO.date);
|
||||
|
||||
if (foundExchangeRate.length > 0) {
|
||||
this.logger.info('[exchange_rates] given exchange rate period exists.', { tenantId });
|
||||
throw new ServiceError(ERRORS.EXCHANGE_RATE_PERIOD_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given echange rate id existance.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} exchangeRateId - Exchange rate id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateExchangeRateExistance(tenantId: number, exchangeRateId: number) {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[exchange_rates] trying to validate exchange rate id existance.', { tenantId, exchangeRateId });
|
||||
const foundExchangeRate = await ExchangeRate.query().findById(exchangeRateId);
|
||||
|
||||
if (!foundExchangeRate) {
|
||||
this.logger.info('[exchange_rates] exchange rate not found.', { tenantId, exchangeRateId });
|
||||
throw new ServiceError(ERRORS.EXCHANGE_RATE_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates exchange rates ids existance.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number[]} exchangeRatesIds - Exchange rates ids.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
private async validateExchangeRatesIdsExistance(tenantId: number, exchangeRatesIds: number[]): Promise<void> {
|
||||
const { ExchangeRate } = this.tenancy.models(tenantId);
|
||||
|
||||
const storedExchangeRates = await ExchangeRate.query().whereIn('id', exchangeRatesIds);
|
||||
const storedExchangeRatesIds = storedExchangeRates.map((category) => category.id);
|
||||
const notFoundExRates = difference(exchangeRatesIds, storedExchangeRatesIds);
|
||||
|
||||
if (notFoundExRates.length > 0) {
|
||||
throw new ServiceError(ERRORS.NOT_FOUND_EXCHANGE_RATES);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ export default class TenantsManagerService implements ITenantManager{
|
||||
|
||||
/**
|
||||
* Throws error if the tenant database is not built yut.
|
||||
* @param tenant
|
||||
* @param {ITenant} tenant
|
||||
*/
|
||||
private throwErrorIfTenantNotBuilt(tenant: ITenant) {
|
||||
if (!tenant.initializedAt) {
|
||||
|
||||
Reference in New Issue
Block a user