add server to monorepo.

This commit is contained in:
a.bouhuolia
2023-02-03 11:57:50 +02:00
parent 28e309981b
commit 80b97b5fdc
1303 changed files with 137049 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
import { Service, Inject } from 'typedi';
import async from 'async';
import { Knex } from 'knex';
import { uniq } from 'lodash';
import { ILedger, ISaveAccountsBalanceQueuePayload } from '@/interfaces';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { TenantMetadata } from '@/system/models';
@Service()
export class LedegrAccountsStorage {
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve depepants ids of the give accounts ids.
* @param {number[]} accountsIds
* @param depGraph
* @returns {number[]}
*/
private getDependantsAccountsIds = (
accountsIds: number[],
depGraph
): number[] => {
const depAccountsIds = [];
accountsIds.forEach((accountId: number) => {
const depAccountIds = depGraph.dependantsOf(accountId);
depAccountsIds.push(accountId, ...depAccountIds);
});
return uniq(depAccountsIds);
};
/**
*
* @param {number} tenantId
* @param {number[]} accountsIds
* @returns {number[]}
*/
private findDependantsAccountsIds = async (
tenantId: number,
accountsIds: number[],
trx?: Knex.Transaction
): Promise<number[]> => {
const { accountRepository } = this.tenancy.repositories(tenantId);
const accountsGraph = await accountRepository.getDependencyGraph(null, trx);
return this.getDependantsAccountsIds(accountsIds, accountsGraph);
};
/**
* Atomic mutation for accounts balances.
* @param {number} tenantId
* @param {ILedger} ledger
* @param {Knex.Transaction} trx -
* @returns {Promise<void>}
*/
public saveAccountsBalance = async (
tenantId: number,
ledger: ILedger,
trx?: Knex.Transaction
): Promise<void> => {
// Initiate a new queue for accounts balance mutation.
const saveAccountsBalanceQueue = async.queue(
this.saveAccountBalanceTask,
10
);
const effectedAccountsIds = ledger.getAccountsIds();
const dependAccountsIds = await this.findDependantsAccountsIds(
tenantId,
effectedAccountsIds,
trx
);
dependAccountsIds.forEach((accountId: number) => {
saveAccountsBalanceQueue.push({ tenantId, ledger, accountId, trx });
});
if (dependAccountsIds.length > 0) {
await saveAccountsBalanceQueue.drain();
}
};
/**
* Async task mutates the given account balance.
* @param {ISaveAccountsBalanceQueuePayload} task
* @returns {Promise<void>}
*/
private saveAccountBalanceTask = async (
task: ISaveAccountsBalanceQueuePayload
): Promise<void> => {
const { tenantId, ledger, accountId, trx } = task;
await this.saveAccountBalanceFromLedger(tenantId, ledger, accountId, trx);
};
/**
* Saves specific account balance from the given ledger.
* @param {number} tenantId
* @param {ILedger} ledger
* @param {number} accountId
* @param {Knex.Transaction} trx -
* @returns {Promise<void>}
*/
private saveAccountBalanceFromLedger = async (
tenantId: number,
ledger: ILedger,
accountId: number,
trx?: Knex.Transaction
): Promise<void> => {
const { Account } = this.tenancy.models(tenantId);
const account = await Account.query(trx).findById(accountId);
// Filters the ledger entries by the current acount.
const accountLedger = ledger.whereAccountId(accountId);
// Retrieves the given tenant metadata.
const tenantMeta = await TenantMetadata.query().findOne({ tenantId });
// Detarmines whether the account has foreign currency.
const isAccountForeign = account.currencyCode !== tenantMeta.baseCurrency;
// Calculates the closing foreign balance by the given currency if account was has
// foreign currency otherwise get closing balance.
const closingBalance = isAccountForeign
? accountLedger
.whereCurrencyCode(account.currencyCode)
.getForeignClosingBalance()
: accountLedger.getClosingBalance();
await this.saveAccountBalance(tenantId, accountId, closingBalance, trx);
};
/**
* Saves the account balance.
* @param {number} tenantId
* @param {number} accountId
* @param {number} change
* @param {Knex.Transaction} trx -
* @returns {Promise<void>}
*/
private saveAccountBalance = async (
tenantId: number,
accountId: number,
change: number,
trx?: Knex.Transaction
) => {
const { Account } = this.tenancy.models(tenantId);
// Ensure the account has atleast zero in amount.
await Account.query(trx)
.findById(accountId)
.whereNull('amount')
.patch({ amount: 0 });
await Account.changeAmount({ id: accountId }, 'amount', change, trx);
};
}