mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 04:10:32 +00:00
401 lines
10 KiB
TypeScript
401 lines
10 KiB
TypeScript
import { Inject, Injectable, Scope } from '@nestjs/common';
|
|
import * as R from 'ramda';
|
|
import { Knex } from 'knex';
|
|
import { isEmpty } from 'lodash';
|
|
import {
|
|
IAccountTransactionsGroupBy,
|
|
IBalanceSheetQuery,
|
|
} from './BalanceSheet.types';
|
|
import { BalanceSheetQuery } from './BalanceSheetQuery';
|
|
import { FinancialDatePeriods } from '../../common/FinancialDatePeriods';
|
|
import { BalanceSheetRepositoryNetIncome } from './BalanceSheetRepositoryNetIncome';
|
|
import { ILedger } from '@/modules/Ledger/types/Ledger.types';
|
|
import { Ledger } from '@/modules/Ledger/Ledger';
|
|
import { transformToMapBy } from '@/utils/transform-to-map-by';
|
|
import { Account } from '@/modules/Accounts/models/Account.model';
|
|
import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction.model';
|
|
|
|
|
|
@Injectable({ scope: Scope.TRANSIENT })
|
|
export class BalanceSheetRepository extends R.compose(
|
|
BalanceSheetRepositoryNetIncome,
|
|
FinancialDatePeriods
|
|
)(class {}) {
|
|
/**
|
|
*
|
|
*/
|
|
@Inject(Account.name)
|
|
public readonly accountModel: typeof Account;
|
|
|
|
@Inject(AccountTransaction.name)
|
|
public readonly accountTransactionModel: typeof AccountTransaction;
|
|
|
|
/**
|
|
* @param {number}
|
|
*/
|
|
public readonly tenantId: number;
|
|
|
|
/**
|
|
* @param {BalanceSheetQuery}
|
|
*/
|
|
public readonly query: BalanceSheetQuery;
|
|
|
|
/**
|
|
* @param {}
|
|
*/
|
|
public accounts: any;
|
|
|
|
/**
|
|
* @param {}
|
|
*/
|
|
public accountsGraph: any;
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public accountsByType: any;
|
|
|
|
/**
|
|
* PY from date.
|
|
* @param {Date}
|
|
*/
|
|
public readonly PYFromDate: Date;
|
|
|
|
/**
|
|
* PY to date.
|
|
* @param {Date}
|
|
*/
|
|
public readonly PYToDate: Date;
|
|
|
|
/**
|
|
* PP to date.
|
|
* @param {Date}
|
|
*/
|
|
public readonly PPToDate: Date;
|
|
|
|
/**
|
|
* PP from date.
|
|
* @param {Date}
|
|
*/
|
|
public readonly PPFromDate: Date;
|
|
|
|
/**
|
|
* Total closing accounts ledger.
|
|
* @param {Ledger}
|
|
*/
|
|
public totalAccountsLedger: Ledger;
|
|
|
|
/**
|
|
* Total income accounts ledger.
|
|
*/
|
|
public incomeLedger: Ledger;
|
|
|
|
/**
|
|
* Total expense accounts ledger.
|
|
*/
|
|
public expensesLedger: Ledger;
|
|
|
|
/**
|
|
* Transactions group type.
|
|
* @param {IAccountTransactionsGroupBy}
|
|
*/
|
|
public transactionsGroupType: IAccountTransactionsGroupBy =
|
|
IAccountTransactionsGroupBy.Month;
|
|
|
|
// -----------------------
|
|
// # Date Periods
|
|
// -----------------------
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public periodsAccountsLedger: Ledger;
|
|
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public periodsOpeningAccountLedger: Ledger;
|
|
|
|
// -----------------------
|
|
// # Previous Year (PY).
|
|
// -----------------------
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PYPeriodsOpeningAccountLedger: Ledger;
|
|
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PYPeriodsAccountsLedger: Ledger;
|
|
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PYTotalAccountsLedger: ILedger;
|
|
|
|
// -----------------------
|
|
// # Previous Period (PP).
|
|
// -----------------------
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PPTotalAccountsLedger: Ledger;
|
|
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PPPeriodsAccountsLedger: ILedger;
|
|
|
|
/**
|
|
* @param {Ledger}
|
|
*/
|
|
public PPPeriodsOpeningAccountLedger: ILedger;
|
|
|
|
/**
|
|
* Constructor method.
|
|
* @param {number} tenantId
|
|
* @param {IBalanceSheetQuery} query
|
|
*/
|
|
public setQuery(query: IBalanceSheetQuery) {
|
|
this.query = new BalanceSheetQuery(query);
|
|
|
|
this.transactionsGroupType = this.getGroupByFromDisplayColumnsBy(
|
|
this.query.displayColumnsBy
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Async initialize.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public asyncInitialize = async (query: IBalanceSheetQuery) => {
|
|
this.setQuery(query);
|
|
|
|
await this.initAccounts();
|
|
await this.initAccountsGraph();
|
|
|
|
await this.initAccountsTotalLedger();
|
|
|
|
// Date periods.
|
|
if (this.query.isDatePeriodsColumnsType()) {
|
|
await this.initTotalDatePeriods();
|
|
}
|
|
// Previous Year (PY).
|
|
if (this.query.isPreviousYearActive()) {
|
|
await this.initTotalPreviousYear();
|
|
}
|
|
if (
|
|
this.query.isPreviousYearActive() &&
|
|
this.query.isDatePeriodsColumnsType()
|
|
) {
|
|
await this.initPeriodsPreviousYear();
|
|
}
|
|
// Previous Period (PP).
|
|
if (this.query.isPreviousPeriodActive()) {
|
|
await this.initTotalPreviousPeriod();
|
|
}
|
|
if (
|
|
this.query.isPreviousPeriodActive() &&
|
|
this.query.isDatePeriodsColumnsType()
|
|
) {
|
|
await this.initPeriodsPreviousPeriod();
|
|
}
|
|
//
|
|
await this.asyncInitializeNetIncome();
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Accounts
|
|
// ----------------------------
|
|
public initAccounts = async () => {
|
|
const accounts = await this.getAccounts();
|
|
|
|
this.accounts = accounts;
|
|
this.accountsByType = transformToMapBy(accounts, 'accountType');
|
|
this.accountsByParentType = transformToMapBy(accounts, 'accountParentType');
|
|
};
|
|
|
|
/**
|
|
* Initialize accounts graph.
|
|
*/
|
|
public initAccountsGraph = async () => {
|
|
this.accountsGraph = this.accountModel.toDependencyGraph(this.accounts);
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Closing Total
|
|
// ----------------------------
|
|
/**
|
|
* Initialize accounts closing total based on the given query.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initAccountsTotalLedger = async (): Promise<void> => {
|
|
const totalByAccount = await this.closingAccountsTotal(this.query.toDate);
|
|
|
|
// Inject to the repository.
|
|
this.totalAccountsLedger = Ledger.fromTransactions(totalByAccount);
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Date periods.
|
|
// ----------------------------
|
|
/**
|
|
* Initialize date periods total.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initTotalDatePeriods = async (): Promise<void> => {
|
|
// Retrieves grouped transactions by given date group.
|
|
const periodsByAccount = await this.accountsDatePeriods(
|
|
this.query.fromDate,
|
|
this.query.toDate,
|
|
this.transactionsGroupType
|
|
);
|
|
// Retrieves opening balance of grouped transactions.
|
|
const periodsOpeningByAccount = await this.closingAccountsTotal(
|
|
this.query.fromDate
|
|
);
|
|
// Inject to the repository.
|
|
this.periodsAccountsLedger = Ledger.fromTransactions(periodsByAccount);
|
|
this.periodsOpeningAccountLedger = Ledger.fromTransactions(
|
|
periodsOpeningByAccount
|
|
);
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Previous Year (PY).
|
|
// ----------------------------
|
|
/**
|
|
* Initialize total of previous year.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initTotalPreviousYear = async (): Promise<void> => {
|
|
const PYTotalsByAccounts = await this.closingAccountsTotal(
|
|
this.query.PYToDate
|
|
);
|
|
// Inject to the repository.
|
|
this.PYTotalAccountsLedger = Ledger.fromTransactions(PYTotalsByAccounts);
|
|
};
|
|
|
|
/**
|
|
* Initialize date periods of previous year.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initPeriodsPreviousYear = async (): Promise<void> => {
|
|
const PYPeriodsBYAccounts = await this.accountsDatePeriods(
|
|
this.query.PYFromDate,
|
|
this.query.PYToDate,
|
|
this.transactionsGroupType
|
|
);
|
|
// Retrieves opening balance of grouped transactions.
|
|
const periodsOpeningByAccount = await this.closingAccountsTotal(
|
|
this.query.PYFromDate
|
|
);
|
|
// Inject to the repository.
|
|
this.PYPeriodsAccountsLedger = Ledger.fromTransactions(PYPeriodsBYAccounts);
|
|
this.PYPeriodsOpeningAccountLedger = Ledger.fromTransactions(
|
|
periodsOpeningByAccount
|
|
);
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Previous Year (PP).
|
|
// ----------------------------
|
|
/**
|
|
* Initialize total of previous year.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initTotalPreviousPeriod = async (): Promise<void> => {
|
|
const PPTotalsByAccounts = await this.closingAccountsTotal(
|
|
this.query.PPToDate
|
|
);
|
|
// Inject to the repository.
|
|
this.PPTotalAccountsLedger = Ledger.fromTransactions(PPTotalsByAccounts);
|
|
};
|
|
|
|
/**
|
|
* Initialize date periods of previous year.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public initPeriodsPreviousPeriod = async (): Promise<void> => {
|
|
const PPPeriodsBYAccounts = await this.accountsDatePeriods(
|
|
this.query.PPFromDate,
|
|
this.query.PPToDate,
|
|
this.transactionsGroupType
|
|
);
|
|
// Retrieves opening balance of grouped transactions.
|
|
const periodsOpeningByAccount = await this.closingAccountsTotal(
|
|
this.query.PPFromDate
|
|
);
|
|
// Inject to the repository.
|
|
this.PPPeriodsAccountsLedger = Ledger.fromTransactions(PPPeriodsBYAccounts);
|
|
this.PPPeriodsOpeningAccountLedger = Ledger.fromTransactions(
|
|
periodsOpeningByAccount
|
|
);
|
|
};
|
|
|
|
// ----------------------------
|
|
// # Utils
|
|
// ----------------------------
|
|
/**
|
|
* Retrieve accounts of the report.
|
|
* @return {Promise<IAccount[]>}
|
|
*/
|
|
public getAccounts = () => {
|
|
return this.accountModel.query();
|
|
};
|
|
|
|
/**
|
|
* Closing accounts date periods.
|
|
* @param {Date} fromDate
|
|
* @param {Date} toDate
|
|
* @param {string} datePeriodsType
|
|
* @returns
|
|
*/
|
|
public accountsDatePeriods = async (
|
|
fromDate: Date,
|
|
toDate: Date,
|
|
datePeriodsType: string
|
|
) => {
|
|
return this.accountTransactionModel.query().onBuild((query) => {
|
|
query.sum('credit as credit');
|
|
query.sum('debit as debit');
|
|
query.groupBy('accountId');
|
|
query.select(['accountId']);
|
|
|
|
query.modify('groupByDateFormat', datePeriodsType);
|
|
query.modify('filterDateRange', fromDate, toDate);
|
|
query.withGraphFetched('account');
|
|
|
|
this.commonFilterBranchesQuery(query);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Retrieve the opening balance transactions of the report.
|
|
* @param {Date|string} openingDate -
|
|
*/
|
|
public closingAccountsTotal = async (openingDate: Date | string) => {
|
|
return this.accountTransactionModel.query().onBuild((query) => {
|
|
query.sum('credit as credit');
|
|
query.sum('debit as debit');
|
|
query.groupBy('accountId');
|
|
query.select(['accountId']);
|
|
|
|
query.modify('filterDateRange', null, openingDate);
|
|
query.withGraphFetched('account');
|
|
|
|
this.commonFilterBranchesQuery(query);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Common branches filter query.
|
|
* @param {Knex.QueryBuilder} query
|
|
*/
|
|
public commonFilterBranchesQuery = (query: Knex.QueryBuilder) => {
|
|
if (!isEmpty(this.query.branchesIds)) {
|
|
query.modify('filterByBranches', this.query.branchesIds);
|
|
}
|
|
};
|
|
}
|