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,214 @@
import { sumBy } from 'lodash';
import * as R from 'ramda';
import {
ITrialBalanceSheetQuery,
ITrialBalanceAccount,
IAccount,
ITrialBalanceTotal,
ITrialBalanceSheetData,
IAccountType,
} from '@/interfaces';
import FinancialSheet from '../FinancialSheet';
import { allPassedConditionsPass, flatToNestedArray } from 'utils';
export default class TrialBalanceSheet extends FinancialSheet {
tenantId: number;
query: ITrialBalanceSheetQuery;
accounts: IAccount & { type: IAccountType }[];
journalFinancial: any;
baseCurrency: string;
/**
* Constructor method.
* @param {number} tenantId
* @param {ITrialBalanceSheetQuery} query
* @param {IAccount[]} accounts
* @param journalFinancial
*/
constructor(
tenantId: number,
query: ITrialBalanceSheetQuery,
accounts: IAccount & { type: IAccountType }[],
journalFinancial: any,
baseCurrency: string
) {
super();
this.tenantId = tenantId;
this.query = query;
this.accounts = accounts;
this.journalFinancial = journalFinancial;
this.numberFormat = this.query.numberFormat;
this.baseCurrency = baseCurrency;
}
/**
* Account mapper.
* @param {IAccount} account
* @return {ITrialBalanceAccount}
*/
private accountTransformer = (
account: IAccount & { type: IAccountType }
): ITrialBalanceAccount => {
const trial = this.journalFinancial.getTrialBalanceWithDepands(account.id);
return {
id: account.id,
parentAccountId: account.parentAccountId,
name: account.name,
code: account.code,
accountNormal: account.accountNormal,
credit: trial.credit,
debit: trial.debit,
balance: trial.balance,
currencyCode: this.baseCurrency,
formattedCredit: this.formatNumber(trial.credit),
formattedDebit: this.formatNumber(trial.debit),
formattedBalance: this.formatNumber(trial.balance),
};
};
/**
* Filters trial balance sheet accounts nodes based on the given report query.
* @param {ITrialBalanceAccount} accountNode
* @returns {boolean}
*/
private accountFilter = (accountNode: ITrialBalanceAccount): boolean => {
const { noneTransactions, noneZero, onlyActive } = this.query;
// Conditions pair filter detarminer.
const condsPairFilters = [
[noneTransactions, this.filterNoneTransactions],
[noneZero, this.filterNoneZero],
[onlyActive, this.filterActiveOnly],
];
return allPassedConditionsPass(condsPairFilters)(accountNode);
};
/**
* Fitlers the accounts nodes.
* @param {ITrialBalanceAccount[]} accountsNodes
* @returns {ITrialBalanceAccount[]}
*/
private accountsFilter = (
accountsNodes: ITrialBalanceAccount[]
): ITrialBalanceAccount[] => {
return accountsNodes.filter(this.accountFilter);
};
/**
* Mappes the given account object to trial balance account node.
* @param {IAccount[]} accountsNodes
* @returns {ITrialBalanceAccount[]}
*/
private accountsMapper = (
accountsNodes: IAccount[]
): ITrialBalanceAccount[] => {
return accountsNodes.map(this.accountTransformer);
};
/**
* Detarmines whether the given account node is not none transactions.
* @param {ITrialBalanceAccount} accountNode
* @returns {boolean}
*/
private filterNoneTransactions = (
accountNode: ITrialBalanceAccount
): boolean => {
const entries = this.journalFinancial.getAccountEntriesWithDepents(
accountNode.id
);
return entries.length > 0;
};
/**
* Detarmines whether the given account none zero.
* @param {ITrialBalanceAccount} accountNode
* @returns {boolean}
*/
private filterNoneZero = (accountNode: ITrialBalanceAccount): boolean => {
return accountNode.balance !== 0;
};
/**
* Detarmines whether the given account is active.
* @param {ITrialBalanceAccount} accountNode
* @returns {boolean}
*/
private filterActiveOnly = (accountNode: ITrialBalanceAccount): boolean => {
return accountNode.credit !== 0 || accountNode.debit !== 0;
};
/**
* Transformes the flatten nodes to nested nodes.
* @param {ITrialBalanceAccount[]} flattenAccounts
* @returns {ITrialBalanceAccount[]}
*/
private nestedAccountsNode = (
flattenAccounts: ITrialBalanceAccount[]
): ITrialBalanceAccount[] => {
return flatToNestedArray(flattenAccounts, {
id: 'id',
parentId: 'parentAccountId',
});
};
/**
* Retrieve trial balance total section.
* @param {ITrialBalanceAccount[]} accountsBalances
* @return {ITrialBalanceTotal}
*/
private tatalSection(
accountsBalances: ITrialBalanceAccount[]
): ITrialBalanceTotal {
const credit = sumBy(accountsBalances, 'credit');
const debit = sumBy(accountsBalances, 'debit');
const balance = sumBy(accountsBalances, 'balance');
const currencyCode = this.baseCurrency;
return {
credit,
debit,
balance,
currencyCode,
formattedCredit: this.formatTotalNumber(credit),
formattedDebit: this.formatTotalNumber(debit),
formattedBalance: this.formatTotalNumber(balance),
};
}
/**
* Retrieve accounts section of trial balance report.
* @param {IAccount[]} accounts
* @returns {ITrialBalanceAccount[]}
*/
private accountsSection(accounts: IAccount & { type: IAccountType }[]) {
return R.compose(
this.nestedAccountsNode,
this.accountsFilter,
this.accountsMapper
)(accounts);
}
/**
* Retrieve trial balance sheet statement data.
* Note: Retruns null in case there is no transactions between the given date periods.
*
* @return {ITrialBalanceSheetData}
*/
public reportData(): ITrialBalanceSheetData {
// Don't return noting if the journal has no transactions.
if (this.journalFinancial.isEmpty()) {
return null;
}
// Retrieve accounts nodes.
const accounts = this.accountsSection(this.accounts);
// Retrieve account node.
const total = this.tatalSection(accounts);
return { accounts, total };
}
}

View File

@@ -0,0 +1,136 @@
import { Service, Inject } from 'typedi';
import moment from 'moment';
import TenancyService from '@/services/Tenancy/TenancyService';
import Journal from '@/services/Accounting/JournalPoster';
import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, ITrialBalanceStatement } from '@/interfaces';
import TrialBalanceSheet from './TrialBalanceSheet';
import FinancialSheet from '../FinancialSheet';
import InventoryService from '@/services/Inventory/Inventory';
import { parseBoolean } from 'utils';
import { Tenant } from '@/system/models';
@Service()
export default class TrialBalanceSheetService extends FinancialSheet {
@Inject()
tenancy: TenancyService;
@Inject()
inventoryService: InventoryService;
@Inject('logger')
logger: any;
/**
* Defaults trial balance sheet filter query.
* @return {IBalanceSheetQuery}
*/
get defaultQuery(): ITrialBalanceSheetQuery {
return {
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
toDate: moment().endOf('year').format('YYYY-MM-DD'),
numberFormat: {
divideOn1000: false,
negativeFormat: 'mines',
showZero: false,
formatMoney: 'total',
precision: 2,
},
basis: 'accural',
noneZero: false,
noneTransactions: true,
onlyActive: false,
accountIds: [],
};
}
/**
* Retrieve the trial balance sheet meta.
* @param {number} tenantId - Tenant id.
* @returns {ITrialBalanceSheetMeta}
*/
reportMetadata(tenantId: number): ITrialBalanceSheetMeta {
const settings = this.tenancy.settings(tenantId);
const isCostComputeRunning = this.inventoryService.isItemsCostComputeRunning(
tenantId
);
const organizationName = settings.get({
group: 'organization',
key: 'name',
});
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
return {
isCostComputeRunning: parseBoolean(isCostComputeRunning, false),
organizationName,
baseCurrency,
};
}
/**
* Retrieve trial balance sheet statement.
* -------------
* @param {number} tenantId
* @param {IBalanceSheetQuery} query
*
* @return {IBalanceSheetStatement}
*/
public async trialBalanceSheet(
tenantId: number,
query: ITrialBalanceSheetQuery
): Promise<ITrialBalanceStatement> {
const filter = {
...this.defaultQuery,
...query,
};
const {
accountRepository,
transactionsRepository,
} = this.tenancy.repositories(tenantId);
const tenant = await Tenant.query()
.findById(tenantId)
.withGraphFetched('metadata');
this.logger.info('[trial_balance_sheet] trying to calcualte the report.', {
tenantId,
filter,
});
// Retrieve all accounts on the storage.
const accounts = await accountRepository.all();
const accountsGraph = await accountRepository.getDependencyGraph();
// Retrieve all journal transactions based on the given query.
const transactions = await transactionsRepository.journal({
fromDate: query.fromDate,
toDate: query.toDate,
sumationCreditDebit: true,
branchesIds: query.branchesIds
});
// Transform transactions array to journal collection.
const transactionsJournal = Journal.fromTransactions(
transactions,
tenantId,
accountsGraph
);
// Trial balance report instance.
const trialBalanceInstance = new TrialBalanceSheet(
tenantId,
filter,
accounts,
transactionsJournal,
tenant.metadata.baseCurrency,
);
// Trial balance sheet data.
const trialBalanceSheetData = trialBalanceInstance.reportData();
return {
data: trialBalanceSheetData,
query: filter,
meta: this.reportMetadata(tenantId),
};
}
}