mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
fix: system repositories.
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import { difference, chain, uniq } from 'lodash';
|
||||
import { kebabCase } from 'lodash'
|
||||
import { kebabCase } from 'lodash';
|
||||
import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { ServiceError } from 'exceptions';
|
||||
import { IAccountDTO, IAccount, IAccountsFilter, IFilterMeta } from 'interfaces';
|
||||
import {
|
||||
IAccountDTO,
|
||||
IAccount,
|
||||
IAccountsFilter,
|
||||
IFilterMeta,
|
||||
} from 'interfaces';
|
||||
import {
|
||||
EventDispatcher,
|
||||
EventDispatcherInterface,
|
||||
@@ -27,15 +32,21 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Retrieve account type or throws service error.
|
||||
* @param {number} tenantId -
|
||||
* @param {number} accountTypeId -
|
||||
* @return {IAccountType}
|
||||
* @param {number} tenantId -
|
||||
* @param {number} accountTypeId -
|
||||
* @return {IAccountType}
|
||||
*/
|
||||
private async getAccountTypeOrThrowError(tenantId: number, accountTypeId: number) {
|
||||
const { AccountType } = this.tenancy.models(tenantId);
|
||||
private async getAccountTypeOrThrowError(
|
||||
tenantId: number,
|
||||
accountTypeId: number
|
||||
) {
|
||||
const { accountTypeRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating account type existance.', { tenantId, accountTypeId });
|
||||
const accountType = await AccountType.query().findById(accountTypeId);
|
||||
this.logger.info('[accounts] validating account type existance.', {
|
||||
tenantId,
|
||||
accountTypeId,
|
||||
});
|
||||
const accountType = await accountTypeRepository.findOneById(accountTypeId);
|
||||
|
||||
if (!accountType) {
|
||||
this.logger.info('[accounts] account type not found.');
|
||||
@@ -46,24 +57,34 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Retrieve parent account or throw service error.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} notAccountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} notAccountId
|
||||
*/
|
||||
private async getParentAccountOrThrowError(tenantId: number, accountId: number, notAccountId?: number) {
|
||||
private async getParentAccountOrThrowError(
|
||||
tenantId: number,
|
||||
accountId: number,
|
||||
notAccountId?: number
|
||||
) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating parent account existance.', {
|
||||
tenantId, accountId, notAccountId,
|
||||
tenantId,
|
||||
accountId,
|
||||
notAccountId,
|
||||
});
|
||||
const parentAccount = await Account.query().findById(accountId)
|
||||
const parentAccount = await Account.query()
|
||||
.findById(accountId)
|
||||
.onBuild((query) => {
|
||||
if (notAccountId) {
|
||||
query.whereNot('id', notAccountId);
|
||||
}
|
||||
});
|
||||
if (!parentAccount) {
|
||||
this.logger.info('[accounts] parent account not found.', { tenantId, accountId });
|
||||
this.logger.info('[accounts] parent account not found.', {
|
||||
tenantId,
|
||||
accountId,
|
||||
});
|
||||
throw new ServiceError('parent_account_not_found');
|
||||
}
|
||||
return parentAccount;
|
||||
@@ -71,17 +92,27 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Throws error if the account type was not unique on the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {string} accountCode
|
||||
* @param {number} notAccountId
|
||||
* @param {number} tenantId
|
||||
* @param {string} accountCode
|
||||
* @param {number} notAccountId
|
||||
*/
|
||||
private async isAccountCodeUniqueOrThrowError(tenantId: number, accountCode: string, notAccountId?: number) {
|
||||
private async isAccountCodeUniqueOrThrowError(
|
||||
tenantId: number,
|
||||
accountCode: string,
|
||||
notAccountId?: number
|
||||
) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating the account code unique on the storage.', {
|
||||
tenantId, accountCode, notAccountId,
|
||||
});
|
||||
const account = await Account.query().where('code', accountCode)
|
||||
this.logger.info(
|
||||
'[accounts] validating the account code unique on the storage.',
|
||||
{
|
||||
tenantId,
|
||||
accountCode,
|
||||
notAccountId,
|
||||
}
|
||||
);
|
||||
const account = await Account.query()
|
||||
.where('code', accountCode)
|
||||
.onBuild((query) => {
|
||||
if (notAccountId) {
|
||||
query.whereNot('id', notAccountId);
|
||||
@@ -89,17 +120,23 @@ export default class AccountsService {
|
||||
});
|
||||
|
||||
if (account.length > 0) {
|
||||
this.logger.info('[accounts] account code is not unique.', { tenantId, accountCode });
|
||||
this.logger.info('[accounts] account code is not unique.', {
|
||||
tenantId,
|
||||
accountCode,
|
||||
});
|
||||
throw new ServiceError('account_code_not_unique');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws service error if parent account has different type.
|
||||
* @param {IAccountDTO} accountDTO
|
||||
* @param {IAccount} parentAccount
|
||||
* @param {IAccountDTO} accountDTO
|
||||
* @param {IAccount} parentAccount
|
||||
*/
|
||||
private throwErrorIfParentHasDiffType(accountDTO: IAccountDTO, parentAccount: IAccount) {
|
||||
private throwErrorIfParentHasDiffType(
|
||||
accountDTO: IAccountDTO,
|
||||
parentAccount: IAccount
|
||||
) {
|
||||
if (accountDTO.accountTypeId !== parentAccount.accountTypeId) {
|
||||
throw new ServiceError('parent_has_different_type');
|
||||
}
|
||||
@@ -107,18 +144,23 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Retrieve account of throw service error in case account not found.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @return {IAccount}
|
||||
*/
|
||||
private async getAccountOrThrowError(tenantId: number, accountId: number) {
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating the account existance.', { tenantId, accountId });
|
||||
this.logger.info('[accounts] validating the account existance.', {
|
||||
tenantId,
|
||||
accountId,
|
||||
});
|
||||
const account = await accountRepository.findOneById(accountId);
|
||||
|
||||
if (!account) {
|
||||
this.logger.info('[accounts] the given account not found.', { accountId });
|
||||
this.logger.info('[accounts] the given account not found.', {
|
||||
accountId,
|
||||
});
|
||||
throw new ServiceError('account_not_found');
|
||||
}
|
||||
return account;
|
||||
@@ -127,13 +169,13 @@ export default class AccountsService {
|
||||
/**
|
||||
* Diff account type between new and old account, throw service error
|
||||
* if they have different account type.
|
||||
*
|
||||
*
|
||||
* @param {IAccount|IAccountDTO} oldAccount
|
||||
* @param {IAccount|IAccountDTO} newAccount
|
||||
*/
|
||||
private async isAccountTypeChangedOrThrowError(
|
||||
oldAccount: IAccount|IAccountDTO,
|
||||
newAccount: IAccount|IAccountDTO,
|
||||
oldAccount: IAccount | IAccountDTO,
|
||||
newAccount: IAccount | IAccountDTO
|
||||
) {
|
||||
if (oldAccount.accountTypeId !== newAccount.accountTypeId) {
|
||||
throw new ServiceError('account_type_not_allowed_to_changed');
|
||||
@@ -142,19 +184,29 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Validates the account name uniquiness.
|
||||
* @param {number} tenantId
|
||||
* @param {string} accountName
|
||||
* @param {number} tenantId
|
||||
* @param {string} accountName
|
||||
* @param {number} notAccountId - Ignore the account id.
|
||||
*/
|
||||
private async validateAccountNameUniquiness(tenantId: number, accountName: string, notAccountId?: number) {
|
||||
private async validateAccountNameUniquiness(
|
||||
tenantId: number,
|
||||
accountName: string,
|
||||
notAccountId?: number
|
||||
) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[accounts] validating account name uniquiness.', { tenantId, accountName, notAccountId });
|
||||
const foundAccount = await Account.query().findOne('name', accountName).onBuild((query) => {
|
||||
if (notAccountId) {
|
||||
query.whereNot('id', notAccountId);
|
||||
}
|
||||
this.logger.info('[accounts] validating account name uniquiness.', {
|
||||
tenantId,
|
||||
accountName,
|
||||
notAccountId,
|
||||
});
|
||||
const foundAccount = await Account.query()
|
||||
.findOne('name', accountName)
|
||||
.onBuild((query) => {
|
||||
if (notAccountId) {
|
||||
query.whereNot('id', notAccountId);
|
||||
}
|
||||
});
|
||||
if (foundAccount) {
|
||||
throw new ServiceError('account_name_not_unqiue');
|
||||
}
|
||||
@@ -162,9 +214,9 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Creates a new account on the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {IAccount} accountDTO
|
||||
* @returns {IAccount}
|
||||
* @param {number} tenantId
|
||||
* @param {IAccount} accountDTO
|
||||
* @returns {IAccount}
|
||||
*/
|
||||
public async newAccount(tenantId: number, accountDTO: IAccountDTO) {
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
@@ -180,7 +232,8 @@ export default class AccountsService {
|
||||
|
||||
if (accountDTO.parentAccountId) {
|
||||
const parentAccount = await this.getParentAccountOrThrowError(
|
||||
tenantId, accountDTO.parentAccountId
|
||||
tenantId,
|
||||
accountDTO.parentAccountId
|
||||
);
|
||||
this.throwErrorIfParentHasDiffType(accountDTO, parentAccount);
|
||||
|
||||
@@ -191,7 +244,10 @@ export default class AccountsService {
|
||||
...accountDTO,
|
||||
slug: kebabCase(accountDTO.name),
|
||||
});
|
||||
this.logger.info('[account] account created successfully.', { account, accountDTO });
|
||||
this.logger.info('[account] account created successfully.', {
|
||||
account,
|
||||
accountDTO,
|
||||
});
|
||||
|
||||
// Triggers `onAccountCreated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onCreated);
|
||||
@@ -201,21 +257,31 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Edits details of the given account.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {IAccountDTO} accountDTO
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {IAccountDTO} accountDTO
|
||||
*/
|
||||
public async editAccount(tenantId: number, accountId: number, accountDTO: IAccountDTO) {
|
||||
this.logger.info('[account] trying to edit account.', { tenantId, accountId });
|
||||
|
||||
public async editAccount(
|
||||
tenantId: number,
|
||||
accountId: number,
|
||||
accountDTO: IAccountDTO
|
||||
) {
|
||||
this.logger.info('[account] trying to edit account.', {
|
||||
tenantId,
|
||||
accountId,
|
||||
});
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
const oldAccount = await this.getAccountOrThrowError(tenantId, accountId);
|
||||
|
||||
// Validate account name uniquiness.
|
||||
await this.validateAccountNameUniquiness(tenantId, accountDTO.name, accountId);
|
||||
await this.validateAccountNameUniquiness(
|
||||
tenantId,
|
||||
accountDTO.name,
|
||||
accountId
|
||||
);
|
||||
|
||||
await this.isAccountTypeChangedOrThrowError(oldAccount, accountDTO);
|
||||
|
||||
|
||||
// Validate the account code not exists on the storage.
|
||||
if (accountDTO.code && accountDTO.code !== oldAccount.code) {
|
||||
await this.isAccountCodeUniqueOrThrowError(
|
||||
@@ -226,17 +292,21 @@ export default class AccountsService {
|
||||
}
|
||||
if (accountDTO.parentAccountId) {
|
||||
const parentAccount = await this.getParentAccountOrThrowError(
|
||||
tenantId, accountDTO.parentAccountId, oldAccount.id,
|
||||
tenantId,
|
||||
accountDTO.parentAccountId,
|
||||
oldAccount.id
|
||||
);
|
||||
this.throwErrorIfParentHasDiffType(accountDTO, parentAccount);
|
||||
}
|
||||
// Update the account on the storage.
|
||||
const account = await accountRepository.updateAndFetch({
|
||||
id: oldAccount.id,
|
||||
...accountDTO
|
||||
});
|
||||
const account = await accountRepository.update(
|
||||
{ ...accountDTO, },
|
||||
{ id: oldAccount.id }
|
||||
);
|
||||
this.logger.info('[account] account edited successfully.', {
|
||||
account, accountDTO, tenantId
|
||||
account,
|
||||
accountDTO,
|
||||
tenantId,
|
||||
});
|
||||
// Triggers `onAccountEdited` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onEdited);
|
||||
@@ -246,8 +316,8 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Retrieve the given account details.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
*/
|
||||
public async getAccount(tenantId: number, accountId: number) {
|
||||
return this.getAccountOrThrowError(tenantId, accountId);
|
||||
@@ -255,22 +325,24 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Detarmine if the given account id exists on the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
*/
|
||||
public async isAccountExists(tenantId: number, accountId: number) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[account] validating the account existance.', { tenantId, accountId });
|
||||
const foundAccounts = await Account.query()
|
||||
.where('id', accountId);
|
||||
this.logger.info('[account] validating the account existance.', {
|
||||
tenantId,
|
||||
accountId,
|
||||
});
|
||||
const foundAccounts = await Account.query().where('id', accountId);
|
||||
|
||||
return foundAccounts.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws error if the account was prefined.
|
||||
* @param {IAccount} account
|
||||
* @param {IAccount} account
|
||||
*/
|
||||
private throwErrorIfAccountPredefined(account: IAccount) {
|
||||
if (account.predefined) {
|
||||
@@ -281,14 +353,16 @@ export default class AccountsService {
|
||||
/**
|
||||
* Unlink the given parent account with children accounts.
|
||||
* @param {number} tenantId -
|
||||
* @param {number|number[]} parentAccountId -
|
||||
* @param {number|number[]} parentAccountId -
|
||||
*/
|
||||
private async unassociateChildrenAccountsFromParent(
|
||||
tenantId: number,
|
||||
parentAccountId: number | number[],
|
||||
parentAccountId: number | number[]
|
||||
) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const accountsIds = Array.isArray(parentAccountId) ? parentAccountId : [parentAccountId];
|
||||
const accountsIds = Array.isArray(parentAccountId)
|
||||
? parentAccountId
|
||||
: [parentAccountId];
|
||||
|
||||
await Account.query()
|
||||
.whereIn('parent_account_id', accountsIds)
|
||||
@@ -297,13 +371,17 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Throws service error if the account has associated transactions.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
*/
|
||||
private async throwErrorIfAccountHasTransactions(tenantId: number, accountId: number) {
|
||||
private async throwErrorIfAccountHasTransactions(
|
||||
tenantId: number,
|
||||
accountId: number
|
||||
) {
|
||||
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||
const accountTransactions = await AccountTransaction.query().where(
|
||||
'account_id', accountId,
|
||||
'account_id',
|
||||
accountId
|
||||
);
|
||||
if (accountTransactions.length > 0) {
|
||||
throw new ServiceError('account_has_associated_transactions');
|
||||
@@ -312,8 +390,8 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Deletes the account from the storage.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
*/
|
||||
public async deleteAccount(tenantId: number, accountId: number) {
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
@@ -330,7 +408,8 @@ export default class AccountsService {
|
||||
|
||||
await accountRepository.deleteById(account.id);
|
||||
this.logger.info('[account] account has been deleted successfully.', {
|
||||
tenantId, accountId,
|
||||
tenantId,
|
||||
accountId,
|
||||
});
|
||||
|
||||
// Triggers `onAccountDeleted` event.
|
||||
@@ -339,8 +418,8 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Retrieve the given accounts details or throw error if one account not exists.
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @return {IAccount[]}
|
||||
*/
|
||||
public async getAccountsOrThrowError(
|
||||
@@ -349,13 +428,19 @@ export default class AccountsService {
|
||||
): Promise<IAccount[]> {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
|
||||
this.logger.info('[account] trying to validate accounts not exist.', { tenantId, accountsIds });
|
||||
this.logger.info('[account] trying to validate accounts not exist.', {
|
||||
tenantId,
|
||||
accountsIds,
|
||||
});
|
||||
const storedAccounts = await Account.query().whereIn('id', accountsIds);
|
||||
const storedAccountsIds = storedAccounts.map((account) => account.id);
|
||||
const notFoundAccounts = difference(accountsIds, storedAccountsIds);
|
||||
|
||||
if (notFoundAccounts.length > 0) {
|
||||
this.logger.error('[account] accounts not exists on the storage.', { tenantId, notFoundAccounts });
|
||||
this.logger.error('[account] accounts not exists on the storage.', {
|
||||
tenantId,
|
||||
notFoundAccounts,
|
||||
});
|
||||
throw new ServiceError('accounts_not_found');
|
||||
}
|
||||
return storedAccounts;
|
||||
@@ -367,7 +452,9 @@ export default class AccountsService {
|
||||
* @return {IAccount[]} - Predefined accounts
|
||||
*/
|
||||
private validatePrefinedAccounts(accounts: IAccount[]) {
|
||||
const predefined = accounts.filter((account: IAccount) => account.predefined);
|
||||
const predefined = accounts.filter(
|
||||
(account: IAccount) => account.predefined
|
||||
);
|
||||
|
||||
if (predefined.length > 0) {
|
||||
this.logger.error('[accounts] some accounts predefined.', { predefined });
|
||||
@@ -378,10 +465,13 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Validating the accounts have associated transactions.
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
*/
|
||||
private async validateAccountsHaveTransactions(tenantId: number, accountsIds: number[]) {
|
||||
private async validateAccountsHaveTransactions(
|
||||
tenantId: number,
|
||||
accountsIds: number[]
|
||||
) {
|
||||
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||
const accountsTransactions = await AccountTransaction.query()
|
||||
.whereIn('account_id', accountsIds)
|
||||
@@ -403,11 +493,11 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Deletes the given accounts in bulk.
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
*/
|
||||
public async deleteAccounts(tenantId: number, accountsIds: number[]) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const { accountRepository } = this.tenancy.models(tenantId);
|
||||
const accounts = await this.getAccountsOrThrowError(tenantId, accountsIds);
|
||||
|
||||
// Validate the accounts are not predefined.
|
||||
@@ -420,10 +510,11 @@ export default class AccountsService {
|
||||
await this.unassociateChildrenAccountsFromParent(tenantId, accountsIds);
|
||||
|
||||
// Delete the accounts in one query.
|
||||
await Account.query().whereIn('id', accountsIds).delete();
|
||||
await accountRepository.deleteWhereIdIn(accountsIds);
|
||||
|
||||
this.logger.info('[account] given accounts deleted in bulk successfully.', {
|
||||
tenantId, accountsIds
|
||||
tenantId,
|
||||
accountsIds,
|
||||
});
|
||||
// Triggers `onBulkDeleted` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onBulkDeleted);
|
||||
@@ -431,12 +522,15 @@ export default class AccountsService {
|
||||
|
||||
/**
|
||||
* Activate accounts in bulk.
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @param {boolean} activate
|
||||
* @param {number} tenantId
|
||||
* @param {number[]} accountsIds
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
public async activateAccounts(tenantId: number, accountsIds: number[], activate: boolean = true) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
public async activateAccounts(
|
||||
tenantId: number,
|
||||
accountsIds: number[],
|
||||
activate: boolean = true
|
||||
) {
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
// Retrieve the given account or throw not found.
|
||||
@@ -445,32 +539,41 @@ export default class AccountsService {
|
||||
// Get all children accounts.
|
||||
const accountsGraph = await accountRepository.getDependencyGraph();
|
||||
const dependenciesAccounts = chain(accountsIds)
|
||||
.map(accountId => accountsGraph.dependenciesOf(accountId))
|
||||
.map((accountId) => accountsGraph.dependenciesOf(accountId))
|
||||
.flatten()
|
||||
.value();
|
||||
|
||||
// The children and parent accounts.
|
||||
const patchAccountsIds = uniq([...dependenciesAccounts, accountsIds]);
|
||||
|
||||
this.logger.info('[account] trying activate/inactive the given accounts ids.', { accountsIds });
|
||||
await Account.query().whereIn('id', patchAccountsIds)
|
||||
.patch({
|
||||
active: activate ? 1 : 0,
|
||||
});
|
||||
this.logger.info('[account] accounts have been activated successfully.', { tenantId, accountsIds });
|
||||
this.logger.info(
|
||||
'[account] trying activate/inactive the given accounts ids.',
|
||||
{ accountsIds }
|
||||
);
|
||||
// Activate or inactivate the given accounts ids in bulk.
|
||||
(activate) ?
|
||||
await accountRepository.activateByIds(patchAccountsIds) :
|
||||
await accountRepository.inactivateByIds(patchAccountsIds);
|
||||
|
||||
this.logger.info('[account] accounts have been activated successfully.', {
|
||||
tenantId,
|
||||
accountsIds,
|
||||
});
|
||||
// Triggers `onAccountBulkActivated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onActivated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates/Inactivates the given account.
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {boolean} activate
|
||||
* @param {number} tenantId
|
||||
* @param {number} accountId
|
||||
* @param {boolean} activate
|
||||
*/
|
||||
public async activateAccount(tenantId: number, accountId: number, activate?: boolean) {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
public async activateAccount(
|
||||
tenantId: number,
|
||||
accountId: number,
|
||||
activate?: boolean
|
||||
) {
|
||||
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||
|
||||
// Retrieve the given account or throw not found error.
|
||||
@@ -480,34 +583,44 @@ export default class AccountsService {
|
||||
const accountsGraph = await accountRepository.getDependencyGraph();
|
||||
const dependenciesAccounts = accountsGraph.dependenciesOf(accountId);
|
||||
|
||||
this.logger.info('[account] trying to activate/inactivate the given account id.');
|
||||
await Account.query()
|
||||
.whereIn('id', [...dependenciesAccounts, accountId])
|
||||
.patch({
|
||||
active: activate ? 1 : 0,
|
||||
})
|
||||
this.logger.info(
|
||||
'[account] trying to activate/inactivate the given account id.'
|
||||
);
|
||||
const patchAccountsIds = [...dependenciesAccounts, accountId];
|
||||
|
||||
// Activate and inactivate the given accounts ids.
|
||||
(activate) ?
|
||||
await accountRepository.activateByIds(patchAccountsIds) :
|
||||
await accountRepository.inactivateByIds(patchAccountsIds);
|
||||
|
||||
this.logger.info('[account] account have been activated successfully.', {
|
||||
tenantId,
|
||||
accountId
|
||||
accountId,
|
||||
});
|
||||
|
||||
// Triggers `onAccountActivated` event.
|
||||
this.eventDispatcher.dispatch(events.accounts.onActivated);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieve accounts datatable list.
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsFilter} accountsFilter
|
||||
* @param {number} tenantId
|
||||
* @param {IAccountsFilter} accountsFilter
|
||||
*/
|
||||
public async getAccountsList(
|
||||
tenantId: number,
|
||||
filter: IAccountsFilter,
|
||||
): Promise<{ accounts: IAccount[], filterMeta: IFilterMeta }> {
|
||||
filter: IAccountsFilter
|
||||
): Promise<{ accounts: IAccount[]; filterMeta: IFilterMeta }> {
|
||||
const { Account } = this.tenancy.models(tenantId);
|
||||
const dynamicList = await this.dynamicListService.dynamicList(tenantId, Account, filter);
|
||||
const dynamicList = await this.dynamicListService.dynamicList(
|
||||
tenantId,
|
||||
Account,
|
||||
filter
|
||||
);
|
||||
|
||||
this.logger.info('[accounts] trying to get accounts datatable list.', { tenantId, filter });
|
||||
this.logger.info('[accounts] trying to get accounts datatable list.', {
|
||||
tenantId,
|
||||
filter,
|
||||
});
|
||||
const accounts = await Account.query().onBuild((builder) => {
|
||||
builder.withGraphFetched('type');
|
||||
dynamicList.buildQuery()(builder);
|
||||
@@ -527,7 +640,7 @@ export default class AccountsService {
|
||||
* - Transfer the given account transactions to another account with the same root type.
|
||||
* - Delete the given account.
|
||||
* -------
|
||||
* @param {number} tenantId -
|
||||
* @param {number} tenantId -
|
||||
* @param {number} accountId -
|
||||
* @param {number} toAccountId -
|
||||
* @param {boolean} deleteAfterClosing -
|
||||
@@ -536,32 +649,47 @@ export default class AccountsService {
|
||||
tenantId: number,
|
||||
accountId: number,
|
||||
toAccountId: number,
|
||||
deleteAfterClosing: boolean,
|
||||
deleteAfterClosing: boolean
|
||||
) {
|
||||
this.logger.info('[account] trying to close account.', { tenantId, accountId, toAccountId, deleteAfterClosing });
|
||||
this.logger.info('[account] trying to close account.', {
|
||||
tenantId,
|
||||
accountId,
|
||||
toAccountId,
|
||||
deleteAfterClosing,
|
||||
});
|
||||
|
||||
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||
const { accountTypeRepository, accountRepository } = this.tenancy.repositories(tenantId);
|
||||
const {
|
||||
accountTypeRepository,
|
||||
accountRepository,
|
||||
} = this.tenancy.repositories(tenantId);
|
||||
|
||||
const account = await this.getAccountOrThrowError(tenantId, accountId);
|
||||
const toAccount = await this.getAccountOrThrowError(tenantId, toAccountId);
|
||||
|
||||
this.throwErrorIfAccountPredefined(account);
|
||||
|
||||
const accountType = await accountTypeRepository.findOneById(account.accountTypeId);
|
||||
const toAccountType = await accountTypeRepository.findOneById(toAccount.accountTypeId);
|
||||
const accountType = await accountTypeRepository.findOneById(
|
||||
account.accountTypeId
|
||||
);
|
||||
const toAccountType = await accountTypeRepository.findOneById(
|
||||
toAccount.accountTypeId
|
||||
);
|
||||
|
||||
if (accountType.rootType !== toAccountType.rootType) {
|
||||
throw new ServiceError('close_account_and_to_account_not_same_type');
|
||||
}
|
||||
const updateAccountBalanceOper = await accountRepository.balanceChange(accountId, account.balance || 0);
|
||||
const updateAccountBalanceOper = await accountRepository.balanceChange(
|
||||
accountId,
|
||||
account.balance || 0
|
||||
);
|
||||
|
||||
// Move transactiosn operation.
|
||||
const moveTransactionsOper = await AccountTransaction.query()
|
||||
.where('account_id', accountId)
|
||||
.patch({ accountId: toAccountId });
|
||||
|
||||
await Promise.all([ moveTransactionsOper, updateAccountBalanceOper ]);
|
||||
await Promise.all([moveTransactionsOper, updateAccountBalanceOper]);
|
||||
|
||||
if (deleteAfterClosing) {
|
||||
await accountRepository.deleteById(accountId);
|
||||
|
||||
@@ -4,17 +4,17 @@ import TenancyService from 'services/Tenancy/TenancyService';
|
||||
import { IAccountsTypesService, IAccountType } from 'interfaces';
|
||||
|
||||
@Service()
|
||||
export default class AccountsTypesService implements IAccountsTypesService{
|
||||
export default class AccountsTypesService implements IAccountsTypesService {
|
||||
@Inject()
|
||||
tenancy: TenancyService;
|
||||
|
||||
/**
|
||||
* Retrieve all accounts types.
|
||||
* @param {number} tenantId -
|
||||
* @param {number} tenantId -
|
||||
* @return {Promise<IAccountType>}
|
||||
*/
|
||||
async getAccountsTypes(tenantId: number): Promise<IAccountType> {
|
||||
const { accountTypeRepository } = this.tenancy.repositories(tenantId);
|
||||
return accountTypeRepository.all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user