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,151 @@
import R from 'ramda';
import moment from 'moment';
import {
ICashflowAccountTransaction,
ICashflowAccountTransactionsQuery,
INumberFormatQuery,
} from '@/interfaces';
import FinancialSheet from '../FinancialSheet';
import { runningAmount } from 'utils';
export default class CashflowAccountTransactionReport extends FinancialSheet {
private transactions: any;
private openingBalance: number;
private runningBalance: any;
private numberFormat: INumberFormatQuery;
private baseCurrency: string;
private query: ICashflowAccountTransactionsQuery;
/**
* Constructor method.
* @param {IAccountTransaction[]} transactions -
* @param {number} openingBalance -
* @param {ICashflowAccountTransactionsQuery} query -
*/
constructor(
transactions,
openingBalance: number,
query: ICashflowAccountTransactionsQuery
) {
super();
this.transactions = transactions;
this.openingBalance = openingBalance;
this.runningBalance = runningAmount(this.openingBalance);
this.query = query;
this.numberFormat = query.numberFormat;
this.baseCurrency = 'USD';
}
/**
*Transformes the account transaction to to cashflow transaction node.
* @param {IAccountTransaction} transaction
* @returns {ICashflowAccountTransaction}
*/
private transactionNode = (transaction: any): ICashflowAccountTransaction => {
return {
date: transaction.date,
formattedDate: moment(transaction.date).format('YYYY-MM-DD'),
withdrawal: transaction.credit,
deposit: transaction.debit,
formattedDeposit: this.formatNumber(transaction.debit),
formattedWithdrawal: this.formatNumber(transaction.credit),
referenceId: transaction.referenceId,
referenceType: transaction.referenceType,
formattedTransactionType: transaction.referenceTypeFormatted,
transactionNumber: transaction.transactionNumber,
referenceNumber: transaction.referenceNumber,
runningBalance: this.runningBalance.amount(),
formattedRunningBalance: this.formatNumber(this.runningBalance.amount()),
balance: 0,
formattedBalance: '',
};
};
/**
* Associate cashflow transaction node with running balance attribute.
* @param {IAccountTransaction} transaction
* @returns {ICashflowAccountTransaction}
*/
private transactionRunningBalance = (
transaction: ICashflowAccountTransaction
): ICashflowAccountTransaction => {
const amount = transaction.deposit - transaction.withdrawal;
const biggerThanZero = R.lt(0, amount);
const lowerThanZero = R.gt(0, amount);
const absAmount = Math.abs(amount);
R.when(R.always(biggerThanZero), this.runningBalance.decrement)(absAmount);
R.when(R.always(lowerThanZero), this.runningBalance.increment)(absAmount);
const runningBalance = this.runningBalance.amount();
return {
...transaction,
runningBalance,
formattedRunningBalance: this.formatNumber(runningBalance),
};
};
/**
* Associate to balance attribute to cashflow transaction node.
* @param {ICashflowAccountTransaction} transaction
* @returns {ICashflowAccountTransaction}
*/
private transactionBalance = (
transaction: ICashflowAccountTransaction
): ICashflowAccountTransaction => {
const balance =
transaction.runningBalance +
transaction.withdrawal * -1 +
transaction.deposit;
return {
...transaction,
balance,
formattedBalance: this.formatNumber(balance),
};
};
/**
* Transformes the given account transaction to cashflow report transaction.
* @param {ICashflowAccountTransaction} transaction
* @returns {ICashflowAccountTransaction}
*/
private transactionTransformer = (
transaction
): ICashflowAccountTransaction => {
return R.compose(
this.transactionBalance,
this.transactionRunningBalance,
this.transactionNode
)(transaction);
};
/**
* Retrieve the report transactions node.
* @param {} transactions
* @returns {ICashflowAccountTransaction[]}
*/
private transactionsNode = (transactions): ICashflowAccountTransaction[] => {
return R.map(this.transactionTransformer)(transactions);
};
/**
* Retrieve the reprot data node.
* @returns {ICashflowAccountTransaction[]}
*/
public reportData(): ICashflowAccountTransaction[] {
return this.transactionsNode(this.transactions);
}
}

View File

@@ -0,0 +1,65 @@
import { Service, Inject } from 'typedi';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { ICashflowAccountTransactionsQuery, IPaginationMeta } from '@/interfaces';
@Service()
export default class CashflowAccountTransactionsRepo {
@Inject()
tenancy: HasTenancyService;
/**
* Retrieve the cashflow account transactions.
* @param {number} tenantId -
* @param {ICashflowAccountTransactionsQuery} query -
*/
async getCashflowAccountTransactions(
tenantId: number,
query: ICashflowAccountTransactionsQuery
) {
const { AccountTransaction } = this.tenancy.models(tenantId);
return AccountTransaction.query()
.where('account_id', query.accountId)
.orderBy([
{ column: 'date', order: 'desc' },
{ column: 'created_at', order: 'desc' },
])
.pagination(query.page - 1, query.pageSize);
}
/**
* Retrieve the cashflow account opening balance.
* @param {number} tenantId
* @param {number} accountId
* @param {IPaginationMeta} pagination
* @return {Promise<number>}
*/
async getCashflowAccountOpeningBalance(
tenantId: number,
accountId: number,
pagination: IPaginationMeta
): Promise<number> {
const { AccountTransaction } = this.tenancy.models(tenantId);
// Retrieve the opening balance of credit and debit balances.
const openingBalancesSubquery = AccountTransaction.query()
.where('account_id', accountId)
.orderBy([
{ column: 'date', order: 'desc' },
{ column: 'created_at', order: 'desc' },
])
.limit(pagination.total)
.offset(pagination.pageSize * (pagination.page - 1));
// Sumation of credit and debit balance.
const openingBalances = await AccountTransaction.query()
.sum('credit as credit')
.sum('debit as debit')
.from(openingBalancesSubquery.as('T'))
.first();
const openingBalance = openingBalances.debit - openingBalances.credit;
return openingBalance;
}
}

View File

@@ -0,0 +1,108 @@
import { Service, Inject } from 'typedi';
import { includes } from 'lodash';
import * as qim from 'qim';
import { ICashflowAccountTransactionsQuery, IAccount } from '@/interfaces';
import TenancyService from '@/services/Tenancy/TenancyService';
import FinancialSheet from '../FinancialSheet';
import CashflowAccountTransactionsRepo from './CashflowAccountTransactionsRepo';
import CashflowAccountTransactionsReport from './CashflowAccountTransactions';
import { ACCOUNT_TYPE } from '@/data/AccountTypes';
import { ServiceError } from '@/exceptions';
import { ERRORS } from './constants';
import I18nService from '@/services/I18n/I18nService';
@Service()
export default class CashflowAccountTransactionsService extends FinancialSheet {
@Inject()
tenancy: TenancyService;
@Inject()
cashflowTransactionsRepo: CashflowAccountTransactionsRepo;
@Inject()
i18nService: I18nService;
/**
* Defaults balance sheet filter query.
* @return {IBalanceSheetQuery}
*/
private get defaultQuery(): Partial<ICashflowAccountTransactionsQuery> {
return {
pageSize: 50,
page: 1,
numberFormat: {
precision: 2,
divideOn1000: false,
showZero: false,
formatMoney: 'total',
negativeFormat: 'mines',
},
};
}
/**
* Retrieve the cashflow accouynt transactions report data.
* @param {number} tenantId -
* @param {ICashflowAccountTransactionsQuery} query -
* @return {Promise<IInvetoryItemDetailDOO>}
*/
public async cashflowAccountTransactions(
tenantId: number,
query: ICashflowAccountTransactionsQuery
) {
const { Account } = this.tenancy.models(tenantId);
const parsedQuery = { ...this.defaultQuery, ...query };
// Retrieve the given account or throw not found service error.
const account = await Account.query().findById(parsedQuery.accountId);
// Validates the cashflow account type.
this.validateCashflowAccountType(account);
// Retrieve the cashflow account transactions.
const { results: transactions, pagination } =
await this.cashflowTransactionsRepo.getCashflowAccountTransactions(
tenantId,
parsedQuery
);
// Retrieve the cashflow account opening balance.
const openingBalance =
await this.cashflowTransactionsRepo.getCashflowAccountOpeningBalance(
tenantId,
parsedQuery.accountId,
pagination
);
// Retrieve the computed report.
const report = new CashflowAccountTransactionsReport(
transactions,
openingBalance,
parsedQuery
);
const reportTranasctions = report.reportData();
return {
transactions: this.i18nService.i18nApply(
[[qim.$each, 'formattedTransactionType']],
reportTranasctions,
tenantId
),
pagination,
};
}
/**
* Validates the cashflow account type.
* @param {IAccount} account -
*/
private validateCashflowAccountType(account: IAccount) {
const cashflowTypes = [
ACCOUNT_TYPE.CASH,
ACCOUNT_TYPE.CREDIT_CARD,
ACCOUNT_TYPE.BANK,
];
if (!includes(cashflowTypes, account.accountType)) {
throw new ServiceError(ERRORS.ACCOUNT_ID_HAS_INVALID_TYPE);
}
}
}

View File

@@ -0,0 +1,3 @@
export const ERRORS = {
ACCOUNT_ID_HAS_INVALID_TYPE: 'ACCOUNT_ID_HAS_INVALID_TYPE',
};