From c4692d171675e47920fbd942ce15076d7b10c193 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 30 Jan 2025 01:57:29 +0200 Subject: [PATCH] refactor: balance sheet to nestjs --- .../BalanceSheet/BalanceSheet.controller.ts | 15 +- .../BalanceSheet/BalanceSheet.module.ts | 0 .../modules}/BalanceSheet/BalanceSheet.ts | 0 .../BalanceSheet/BalanceSheet.types.ts | 2 + .../BalanceSheet/BalanceSheetAccounts.ts | 43 +- .../BalanceSheet/BalanceSheetAggregators.ts | 37 +- .../BalanceSheet/BalanceSheetApplication.ts | 0 .../modules}/BalanceSheet/BalanceSheetBase.ts | 7 +- .../BalanceSheetComparsionPreviousPeriod.ts | 29 +- .../BalanceSheetComparsionPreviousYear.ts | 21 +- .../BalanceSheet/BalanceSheetDatePeriods.ts | 12 +- .../BalanceSheetExportInjectable.ts | 0 .../BalanceSheet/BalanceSheetFiltering.ts | 20 +- .../BalanceSheet/BalanceSheetInjectable.ts | 0 .../modules}/BalanceSheet/BalanceSheetMeta.ts | 11 +- .../BalanceSheet/BalanceSheetNetIncome.ts | 38 +- .../BalanceSheetNetIncomeDatePeriods.ts | 24 +- .../BalanceSheetNetIncomeDatePeriodsPP.ts | 12 +- .../BalanceSheetNetIncomeDatePeriodsPY.ts | 41 +- .../BalanceSheet/BalanceSheetNetIncomePP.ts | 8 +- .../BalanceSheet/BalanceSheetNetIncomePY.ts | 31 +- .../BalanceSheet/BalanceSheetPdfInjectable.ts | 5 +- .../BalanceSheet/BalanceSheetPercentage.ts | 83 +-- .../BalanceSheet/BalanceSheetQuery.ts | 0 .../BalanceSheet/BalanceSheetRepository.ts | 43 +- .../BalanceSheetRepositoryNetIncome.ts | 7 +- .../BalanceSheet/BalanceSheetSchema.ts | 11 +- .../BalanceSheet/BalanceSheetTable.ts | 0 .../BalanceSheetTableDatePeriods.ts | 34 +- .../BalanceSheetTableInjectable.ts | 3 +- .../BalanceSheetTablePercentage.ts | 0 .../BalanceSheetTablePreviousPeriod.ts | 47 +- .../BalanceSheetTablePreviousYear.ts | 36 +- .../BalanceSheet/BalanceSheetTotal.ts | 0 .../modules}/BalanceSheet/constants.ts | 0 pnpm-lock.yaml | 13 +- temp/CashFlowStatement/CashFlow.ts | 705 ++++++++++++++++++ temp/CashFlowStatement/CashFlowDatePeriods.ts | 412 ++++++++++ temp/CashFlowStatement/CashFlowRepository.ts | 163 ++++ temp/CashFlowStatement/CashFlowService.ts | 109 +++ temp/CashFlowStatement/CashFlowTable.ts | 374 ++++++++++ temp/CashFlowStatement/Cashflow.controller.ts | 56 ++ temp/CashFlowStatement/Cashflow.module.ts | 27 + temp/CashFlowStatement/Cashflow.types.ts | 299 ++++++++ .../CashflowExportInjectable.ts | 37 + .../CashflowSheetApplication.ts | 66 ++ temp/CashFlowStatement/CashflowSheetMeta.ts | 36 + .../CashflowTableInjectable.ts | 36 + .../CashflowTablePdfInjectable.ts | 28 + temp/CashFlowStatement/constants.ts | 52 ++ temp/CashFlowStatement/schema.ts | 77 ++ 51 files changed, 2823 insertions(+), 287 deletions(-) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheet.controller.ts (80%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheet.module.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheet.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheet.types.ts (99%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetAccounts.ts (88%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetAggregators.ts (83%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetApplication.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetBase.ts (84%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts (92%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetComparsionPreviousYear.ts (93%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetDatePeriods.ts (93%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetExportInjectable.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetFiltering.ts (90%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetInjectable.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetMeta.ts (74%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncome.ts (89%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts (88%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts (92%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts (80%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncomePP.ts (90%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetNetIncomePY.ts (75%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetPdfInjectable.ts (88%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetPercentage.ts (76%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetQuery.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetRepository.ts (94%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetRepositoryNetIncome.ts (97%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetSchema.ts (94%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTable.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTableDatePeriods.ts (86%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTableInjectable.ts (94%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTablePercentage.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTablePreviousPeriod.ts (75%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTablePreviousYear.ts (79%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/BalanceSheetTotal.ts (100%) rename {temp => packages/server-nest/src/modules/FinancialStatements/modules}/BalanceSheet/constants.ts (100%) create mode 100644 temp/CashFlowStatement/CashFlow.ts create mode 100644 temp/CashFlowStatement/CashFlowDatePeriods.ts create mode 100644 temp/CashFlowStatement/CashFlowRepository.ts create mode 100644 temp/CashFlowStatement/CashFlowService.ts create mode 100644 temp/CashFlowStatement/CashFlowTable.ts create mode 100644 temp/CashFlowStatement/Cashflow.controller.ts create mode 100644 temp/CashFlowStatement/Cashflow.module.ts create mode 100644 temp/CashFlowStatement/Cashflow.types.ts create mode 100644 temp/CashFlowStatement/CashflowExportInjectable.ts create mode 100644 temp/CashFlowStatement/CashflowSheetApplication.ts create mode 100644 temp/CashFlowStatement/CashflowSheetMeta.ts create mode 100644 temp/CashFlowStatement/CashflowTableInjectable.ts create mode 100644 temp/CashFlowStatement/CashflowTablePdfInjectable.ts create mode 100644 temp/CashFlowStatement/constants.ts create mode 100644 temp/CashFlowStatement/schema.ts diff --git a/temp/BalanceSheet/BalanceSheet.controller.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.controller.ts similarity index 80% rename from temp/BalanceSheet/BalanceSheet.controller.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.controller.ts index 202c1086a..f337397cf 100644 --- a/temp/BalanceSheet/BalanceSheet.controller.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.controller.ts @@ -1,5 +1,4 @@ import { Response } from 'express'; -import { castArray } from 'lodash'; import { Controller, Headers, Query, Res } from '@nestjs/common'; import { IBalanceSheetQuery } from './BalanceSheet.types'; import { AcceptType } from '@/constants/accept-type'; @@ -20,18 +19,14 @@ export class BalanceSheetStatementController { @Res() res: Response, @Headers('accept') acceptHeader: string, ) { - const filter = { - ...query, - accountsIds: castArray(query.accountsIds), - }; // Retrieves the json table format. if (acceptHeader.includes(AcceptType.ApplicationJsonTable)) { - const table = await this.balanceSheetApp.table(filter); + const table = await this.balanceSheetApp.table(query); return res.status(200).send(table); // Retrieves the csv format. } else if (acceptHeader.includes(AcceptType.ApplicationCsv)) { - const buffer = await this.balanceSheetApp.csv(filter); + const buffer = await this.balanceSheetApp.csv(query); res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); res.setHeader('Content-Type', 'text/csv'); @@ -39,7 +34,7 @@ export class BalanceSheetStatementController { return res.send(buffer); // Retrieves the xlsx format. } else if (acceptHeader.includes(AcceptType.ApplicationXlsx)) { - const buffer = await this.balanceSheetApp.xlsx(filter); + const buffer = await this.balanceSheetApp.xlsx(query); res.setHeader('Content-Disposition', 'attachment; filename=output.xlsx'); res.setHeader( @@ -49,7 +44,7 @@ export class BalanceSheetStatementController { return res.send(buffer); // Retrieves the pdf format. } else if (acceptHeader.includes(AcceptType.ApplicationPdf)) { - const pdfContent = await this.balanceSheetApp.pdf(filter); + const pdfContent = await this.balanceSheetApp.pdf(query); res.set({ 'Content-Type': 'application/pdf', @@ -57,7 +52,7 @@ export class BalanceSheetStatementController { }); res.send(pdfContent); } else { - const sheet = await this.balanceSheetApp.sheet(filter); + const sheet = await this.balanceSheetApp.sheet(query); return res.status(200).send(sheet); } diff --git a/temp/BalanceSheet/BalanceSheet.module.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.module.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheet.module.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.module.ts diff --git a/temp/BalanceSheet/BalanceSheet.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheet.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.ts diff --git a/temp/BalanceSheet/BalanceSheet.types.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.types.ts similarity index 99% rename from temp/BalanceSheet/BalanceSheet.types.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.types.ts index c5f5be024..f0a1f094c 100644 --- a/temp/BalanceSheet/BalanceSheet.types.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheet.types.ts @@ -43,8 +43,10 @@ export enum BALANCE_SHEET_SCHEMA_NODE_ID { export interface IBalanceSheetQuery extends IFinancialSheetBranchesQuery { displayColumnsType: 'total' | 'date_periods'; displayColumnsBy: string; + fromDate: string; toDate: string; + numberFormat: INumberFormatQuery; noneTransactions: boolean; noneZero: boolean; diff --git a/temp/BalanceSheet/BalanceSheetAccounts.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAccounts.ts similarity index 88% rename from temp/BalanceSheet/BalanceSheetAccounts.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAccounts.ts index d28f5be29..2b301bdc3 100644 --- a/temp/BalanceSheet/BalanceSheetAccounts.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAccounts.ts @@ -19,13 +19,16 @@ import { BalanceSheetSchema } from './BalanceSheetSchema'; import { BalanceSheetBase } from './BalanceSheetBase'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetRepository } from './BalanceSheetRepository'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; import { INumberFormatQuery } from '../../types/Report.types'; import { Account } from '@/modules/Accounts/models/Account.model'; import { flatToNestedArray } from '@/utils/flat-to-nested-array'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetAccounts = (Base: T) => - class extends R.compose( +export const BalanceSheetAccounts = >( + Base: T, +) => + class extends R.pipe( BalanceSheetNetIncome, BalanceSheetFiltering, BalanceSheetDatePeriods, @@ -34,7 +37,7 @@ export const BalanceSheetAccounts = (Base: T) => BalanceSheetPercentage, BalanceSheetSchema, BalanceSheetBase, - FinancialSheetStructure + FinancialSheetStructure, )(Base) { /** * Balance sheet query. @@ -70,10 +73,10 @@ export const BalanceSheetAccounts = (Base: T) => * @returns {IAccount[]} */ private getAccountsByAccountTypes = ( - accountsTypes: string[] + accountsTypes: string[], ): Account[] => { const mapAccountsByTypes = R.map((accountType) => - defaultTo(this.repository.accountsByType.get(accountType), []) + defaultTo(this.repository.accountsByType.get(accountType), []), ); return R.compose(R.flatten, mapAccountsByTypes)(accountsTypes); }; @@ -84,10 +87,10 @@ export const BalanceSheetAccounts = (Base: T) => * @returns {IBalanceSheetAccountNode} */ private reportSchemaAccountNodeMapper = ( - account: Account + account: Account, ): IBalanceSheetAccountNode => { const childrenAccountsIds = this.repository.accountsGraph.dependenciesOf( - account.id + account.id, ); const accountIds = R.uniq(R.append(account.id, childrenAccountsIds)); const total = this.repository.totalAccountsLedger @@ -110,22 +113,22 @@ export const BalanceSheetAccounts = (Base: T) => * @returns {IBalanceSheetAccountNode} */ private reportSchemaAccountNodeComposer = ( - account: Account + account: Account, ): IBalanceSheetAccountNode => { return R.compose( R.when( this.query.isPreviousYearActive, - this.previousYearAccountNodeComposer + this.previousYearAccountNodeComposer, ), R.when( this.query.isPreviousPeriodActive, - this.previousPeriodAccountNodeComposer + this.previousPeriodAccountNodeComposer, ), R.when( this.query.isDatePeriodsColumnsType, - this.assocAccountNodeDatePeriods + this.assocAccountNodeDatePeriods, ), - this.reportSchemaAccountNodeMapper + this.reportSchemaAccountNodeMapper, )(account); }; @@ -138,7 +141,7 @@ export const BalanceSheetAccounts = (Base: T) => * @returns {IBalanceSheetAccountNode[]} */ private getAccountsNodesByAccountTypes = ( - accountsTypes: string[] + accountsTypes: string[], ): IBalanceSheetAccountNode[] => { // Retrieves accounts from the given defined node account types. const accounts = this.getAccountsByAccountTypes(accountsTypes); @@ -151,7 +154,7 @@ export const BalanceSheetAccounts = (Base: T) => // Maps over the accounts tree. return this.mapNodesDeep( accountsTree, - this.reportSchemaAccountNodeComposer + this.reportSchemaAccountNodeComposer, ); }; @@ -161,7 +164,7 @@ export const BalanceSheetAccounts = (Base: T) => * @returns {IBalanceSheetAccountNode} */ private reportSchemaAccountsNodeMapper = ( - node: IBalanceSheetSchemaAccountNode + node: IBalanceSheetSchemaAccountNode, ): IBalanceSheetAccountsNode => { const accounts = this.getAccountsNodesByAccountTypes(node.accountsTypes); const children = toArray(node?.children); @@ -182,13 +185,13 @@ export const BalanceSheetAccounts = (Base: T) => * @return {IBalanceSheetSchemaNode | IBalanceSheetDataNode} */ private reportAccountSchemaParser = ( - node: IBalanceSheetSchemaNode | IBalanceSheetDataNode + node: IBalanceSheetSchemaNode | IBalanceSheetDataNode, ): IBalanceSheetSchemaNode | IBalanceSheetDataNode => { return R.compose( R.when( this.isSchemaNodeType(BALANCE_SHEET_SCHEMA_NODE_TYPE.ACCOUNTS), - this.reportSchemaAccountsNodeMapper - ) + this.reportSchemaAccountsNodeMapper, + ), )(node); }; @@ -198,7 +201,7 @@ export const BalanceSheetAccounts = (Base: T) => * @return {IBalanceSheetStructureSection[]} */ public accountsSchemaParser = ( - nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[] + nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[], ): (IBalanceSheetDataNode | IBalanceSheetSchemaNode)[] => { return this.mapNodesDeepReverse(nodes, this.reportAccountSchemaParser); }; diff --git a/temp/BalanceSheet/BalanceSheetAggregators.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAggregators.ts similarity index 83% rename from temp/BalanceSheet/BalanceSheetAggregators.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAggregators.ts index 9e01443fc..5fc0b2f03 100644 --- a/temp/BalanceSheet/BalanceSheetAggregators.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetAggregators.ts @@ -14,18 +14,21 @@ import { BalanceSheetSchema } from './BalanceSheetSchema'; import { BalanceSheetBase } from './BalanceSheetBase'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { FinancialSheetStructure } from '../../common/FinancialSheetStructure'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; import { INumberFormatQuery } from '../../types/Report.types'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetAggregators = (Base: T) => - class extends R.compose( +export const BalanceSheetAggregators = >( + Base: T, +) => + class extends R.pipe( BalanceSheetDatePeriods, BalanceSheetComparsionPreviousPeriod, BalanceSheetComparsionPreviousYear, BalanceSheetPercentage, BalanceSheetSchema, BalanceSheetBase, - FinancialSheetStructure + FinancialSheetStructure, )(Base) { /** * Balance sheet query. @@ -56,21 +59,21 @@ export const BalanceSheetAggregators = (Base: T) => * @returns {IBalanceSheetDataNode} */ public aggregateNodeTotalMapper = ( - node: IBalanceSheetDataNode + node: IBalanceSheetDataNode, ): IBalanceSheetDataNode => { return R.compose( R.when( this.query.isPreviousYearActive, - this.previousYearAggregateNodeComposer + this.previousYearAggregateNodeComposer, ), R.when( this.query.isPreviousPeriodActive, - this.previousPeriodAggregateNodeComposer + this.previousPeriodAggregateNodeComposer, ), R.when( this.query.isDatePeriodsColumnsType, - this.assocAggregateNodeDatePeriods - ) + this.assocAggregateNodeDatePeriods, + ), )(node); }; @@ -80,7 +83,7 @@ export const BalanceSheetAggregators = (Base: T) => * @return {IBalanceSheetAggregateNode} */ public reportSchemaAggregateNodeMapper = ( - node: IBalanceSheetSchemaAggregateNode + node: IBalanceSheetSchemaAggregateNode, ): IBalanceSheetAggregateNode => { const total = this.getTotalOfNodes(node.children); @@ -100,11 +103,11 @@ export const BalanceSheetAggregators = (Base: T) => * @returns {IBalanceSheetSchemaAggregateNode} */ public schemaAggregateNodeCompose = ( - node: IBalanceSheetSchemaAggregateNode + node: IBalanceSheetSchemaAggregateNode, ) => { return R.compose( this.aggregateNodeTotalMapper, - this.reportSchemaAggregateNodeMapper + this.reportSchemaAggregateNodeMapper, )(node); }; @@ -114,17 +117,17 @@ export const BalanceSheetAggregators = (Base: T) => * @return {IBalanceSheetDataNode} */ public reportAggregateSchemaParser = ( - node: IBalanceSheetSchemaNode + node: IBalanceSheetSchemaNode, ): IBalanceSheetDataNode => { return R.compose( R.when( this.isSchemaNodeType(BALANCE_SHEET_SCHEMA_NODE_TYPE.AGGREGATE), - this.schemaAggregateNodeCompose + this.schemaAggregateNodeCompose, ), R.when( this.isSchemaNodeType(BALANCE_SHEET_SCHEMA_NODE_TYPE.ACCOUNTS), - this.schemaAggregateNodeCompose - ) + this.schemaAggregateNodeCompose, + ), )(node); }; @@ -134,7 +137,7 @@ export const BalanceSheetAggregators = (Base: T) => * @return {IBalanceSheetStructureSection[]} */ public aggregatesSchemaParser = ( - nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[] + nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[], ): (IBalanceSheetDataNode | IBalanceSheetSchemaNode)[] => { return this.mapNodesDeepReverse(nodes, this.reportAggregateSchemaParser); }; diff --git a/temp/BalanceSheet/BalanceSheetApplication.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetApplication.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetApplication.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetApplication.ts diff --git a/temp/BalanceSheet/BalanceSheetBase.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetBase.ts similarity index 84% rename from temp/BalanceSheet/BalanceSheetBase.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetBase.ts index 355b459df..41ae8ce6d 100644 --- a/temp/BalanceSheet/BalanceSheetBase.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetBase.ts @@ -3,9 +3,12 @@ import { IBalanceSheetDataNode, IBalanceSheetSchemaNode, } from './BalanceSheet.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetBase = (Base: T) => +export const BalanceSheetBase = >( + Base: T, +) => class BalanceSheetBase extends Base { /** * Detarmines the node type of the given schema node. diff --git a/temp/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts similarity index 92% rename from temp/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts index 196e75a43..7fe6fa31c 100644 --- a/temp/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousPeriod.ts @@ -9,21 +9,24 @@ import { } from './BalanceSheet.types'; import { FinancialPreviousPeriod } from '../../common/FinancialPreviousPeriod'; import { FinancialHorizTotals } from '../../common/FinancialHorizTotals'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetComparsionPreviousPeriod = ( +export const BalanceSheetComparsionPreviousPeriod = < + T extends GConstructor, +>( Base: T, ) => - class BalanceSheetComparsionPreviousPeriod extends R.compose( - FinancialPreviousPeriod, + class BalanceSheetComparsionPreviousPeriod extends R.pipe( FinancialHorizTotals, + FinancialPreviousPeriod, )(Base) { // ------------------------------ // # Account // ------------------------------ /** * Associates the previous period to account node. - * @param {IBalanceSheetDataNode} node + * @param {IBalanceSheetDataNode} node * @returns {IBalanceSheetDataNode} */ public assocPreviousPeriodAccountNode = ( @@ -38,7 +41,7 @@ export const BalanceSheetComparsionPreviousPeriod = ( /** * Previous period account node composer. - * @param {IBalanceSheetAccountNode} node + * @param {IBalanceSheetAccountNode} node * @returns {IBalanceSheetAccountNode} */ public previousPeriodAccountNodeComposer = ( @@ -69,7 +72,7 @@ export const BalanceSheetComparsionPreviousPeriod = ( // ------------------------------ /** * Assoc previous period total to aggregate node. - * @param {IBalanceSheetAggregateNode} node + * @param {IBalanceSheetAggregateNode} node * @returns {IBalanceSheetAggregateNode} */ public assocPreviousPeriodAggregateNode = ( @@ -82,7 +85,7 @@ export const BalanceSheetComparsionPreviousPeriod = ( /** * Previous period aggregate node composer. - * @param {IBalanceSheetAccountNode} node + * @param {IBalanceSheetAccountNode} node * @returns {IBalanceSheetAccountNode} */ public previousPeriodAggregateNodeComposer = ( @@ -113,9 +116,9 @@ export const BalanceSheetComparsionPreviousPeriod = ( // ------------------------------ /** * Retrieve the given account total in the given period. - * @param {number} accountId - Account id. - * @param {Date} fromDate - From date. - * @param {Date} toDate - To date. + * @param {number} accountId - Account id. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. * @returns {number} */ private getAccountPPDatePeriodTotal = R.curry( @@ -152,8 +155,8 @@ export const BalanceSheetComparsionPreviousPeriod = ( /** * Previous year account horizontal node composer. - * @param {IBalanceSheetAccountNode} node - - * @param {IBalanceSheetTotal} + * @param {IBalanceSheetAccountNode} node - + * @param {IBalanceSheetTotal} * @returns {IBalanceSheetTotal} */ private previousPeriodAccountHorizNodeCompose = R.curry( diff --git a/temp/BalanceSheet/BalanceSheetComparsionPreviousYear.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousYear.ts similarity index 93% rename from temp/BalanceSheet/BalanceSheetComparsionPreviousYear.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousYear.ts index ce486bc26..8d7e62797 100644 --- a/temp/BalanceSheet/BalanceSheetComparsionPreviousYear.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetComparsionPreviousYear.ts @@ -7,15 +7,22 @@ import { IBalanceSheetTotal, } from './BalanceSheet.types'; import { FinancialPreviousYear } from '../../common/FinancialPreviousYear'; -import { IBalanceSheetComparsions } from './BalanceSheet.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { BalanceSheetQuery } from './BalanceSheetQuery'; +import { BalanceSheetRepository } from './BalanceSheetRepository'; -export const BalanceSheetComparsionPreviousYear = ( +export const BalanceSheetComparsionPreviousYear = < + T extends GConstructor, +>( Base: T, ) => - class BalanceSheetComparsionPreviousYear extends R.compose( + class BalanceSheetComparsionPreviousYear extends R.pipe( FinancialPreviousYear, )(Base) { + query: BalanceSheetQuery; + repository: BalanceSheetRepository; + // ------------------------------ // # Account // ------------------------------ @@ -37,7 +44,7 @@ export const BalanceSheetComparsionPreviousYear = ( /** * Assoc previous year attributes to account node. - * @param {IBalanceSheetAccountNode} node + * @param {IBalanceSheetAccountNode} node * @returns {IBalanceSheetAccountNode} */ protected previousYearAccountNodeComposer = ( @@ -65,7 +72,7 @@ export const BalanceSheetComparsionPreviousYear = ( // ------------------------------ /** * Assoc previous year on aggregate node. - * @param {IBalanceSheetAccountNode} node + * @param {IBalanceSheetAccountNode} node * @returns {IBalanceSheetAccountNode} */ protected assocPreviousYearAggregateNode = ( @@ -78,7 +85,7 @@ export const BalanceSheetComparsionPreviousYear = ( /** * Assoc previous year attributes to aggregate node. - * @param {IBalanceSheetAccountNode} node + * @param {IBalanceSheetAccountNode} node * @returns {IBalanceSheetAccountNode} */ protected previousYearAggregateNodeComposer = ( diff --git a/temp/BalanceSheet/BalanceSheetDatePeriods.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetDatePeriods.ts similarity index 93% rename from temp/BalanceSheet/BalanceSheetDatePeriods.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetDatePeriods.ts index 19f013aaa..d7104f293 100644 --- a/temp/BalanceSheet/BalanceSheetDatePeriods.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetDatePeriods.ts @@ -8,17 +8,21 @@ import { } from './BalanceSheet.types'; import { FinancialDatePeriods } from '../../common/FinancialDatePeriods'; import { IDateRange, IFormatNumberSettings } from '../../types/Report.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { BalanceSheetQuery } from './BalanceSheetQuery'; /** * Balance sheet date periods. */ -export const BalanceSheetDatePeriods = (Base: T) => - class BalanceSheetDatePeriods extends R.compose(FinancialDatePeriods)(Base) { +export const BalanceSheetDatePeriods = >( + Base: T, +) => + class BalanceSheetDatePeriods extends R.pipe(FinancialDatePeriods)(Base) { /** * @param {IBalanceSheetQuery} */ - readonly query: IBalanceSheetQuery; + public readonly query: BalanceSheetQuery; /** * Retrieves the date periods based on the report query. diff --git a/temp/BalanceSheet/BalanceSheetExportInjectable.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetExportInjectable.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetExportInjectable.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetExportInjectable.ts diff --git a/temp/BalanceSheet/BalanceSheetFiltering.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetFiltering.ts similarity index 90% rename from temp/BalanceSheet/BalanceSheetFiltering.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetFiltering.ts index cbe37076a..2e4e7f4c8 100644 --- a/temp/BalanceSheet/BalanceSheetFiltering.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetFiltering.ts @@ -4,15 +4,25 @@ import { IBalanceSheetDataNode, BALANCE_SHEET_NODE_TYPE, } from './BalanceSheet.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; import { FinancialFilter } from '../../common/FinancialFilter'; import { BalanceSheetBase } from './BalanceSheetBase'; import { BalanceSheetRepository } from './BalanceSheetRepository'; -import { BalanceSheetQuery } from './BalanceSheetQuery'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { FinancialSheetStructure } from '../../common/FinancialSheetStructure'; -export const BalanceSheetFiltering = (Base: T) => - class extends R.pipe(FinancialFilter, BalanceSheetBase)(Base) { - public repository: BalanceSheetRepository; +export const BalanceSheetFiltering = >( + Base: T, +) => + class extends R.pipe( + FinancialFilter, + FinancialSheetStructure, + BalanceSheetBase, + )(Base) { + /** + * @description Repository. + */ + readonly repository: BalanceSheetRepository; // ----------------------- // # Account diff --git a/temp/BalanceSheet/BalanceSheetInjectable.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetInjectable.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetInjectable.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetInjectable.ts diff --git a/temp/BalanceSheet/BalanceSheetMeta.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetMeta.ts similarity index 74% rename from temp/BalanceSheet/BalanceSheetMeta.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetMeta.ts index 76a057361..13cc755d3 100644 --- a/temp/BalanceSheet/BalanceSheetMeta.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetMeta.ts @@ -5,18 +5,13 @@ import { IBalanceSheetMeta, IBalanceSheetQuery } from './BalanceSheet.types'; @Injectable() export class BalanceSheetMetaInjectable { - constructor( - private readonly financialSheetMeta: FinancialSheetMeta, - ) {} + constructor(private readonly financialSheetMeta: FinancialSheetMeta) {} /** - * Retrieve the balance sheet meta. - * @param {number} tenantId - + * Retrieves the balance sheet meta. * @returns {IBalanceSheetMeta} */ - public async meta( - query: IBalanceSheetQuery - ): Promise { + public async meta(query: IBalanceSheetQuery): Promise { const commonMeta = await this.financialSheetMeta.meta(); const formattedAsDate = moment(query.toDate).format('YYYY/MM/DD'); const formattedDateRange = `As ${formattedAsDate}`; diff --git a/temp/BalanceSheet/BalanceSheetNetIncome.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncome.ts similarity index 89% rename from temp/BalanceSheet/BalanceSheetNetIncome.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncome.ts index e0c0a8151..122bbfc34 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncome.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncome.ts @@ -15,15 +15,19 @@ import { BalanceSheetRepository } from './BalanceSheetRepository'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetNetIncomePP } from './BalanceSheetNetIncomePP'; import { BalanceSheetNetIncomePY } from './BalanceSheetNetIncomePY'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { GConstructor } from '@/common/types/Constructor'; -export const BalanceSheetNetIncome = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncome = >( + Base: T, +) => + class extends R.pipe( BalanceSheetNetIncomePP, BalanceSheetNetIncomePY, BalanceSheetComparsionPreviousYear, BalanceSheetComparsionPreviousPeriod, FinancialPreviousPeriod, - FinancialHorizTotals + FinancialHorizTotals, )(Base) { public repository: BalanceSheetRepository; public query: BalanceSheetQuery; @@ -63,7 +67,7 @@ export const BalanceSheetNetIncome = (Base: any) => * @return {IBalanceSheetAggregateNode} */ public schemaNetIncomeNodeMapper = ( - node: IBalanceSheetSchemaNetIncomeNode + node: IBalanceSheetSchemaNetIncomeNode, ): IBalanceSheetNetIncomeNode => { const total = this.getNetIncomeTotal(); @@ -81,22 +85,22 @@ export const BalanceSheetNetIncome = (Base: any) => * @returns {IBalanceSheetNetIncomeNode} */ public schemaNetIncomeNodeCompose = ( - node: IBalanceSheetSchemaNetIncomeNode + node: IBalanceSheetSchemaNetIncomeNode, ): IBalanceSheetNetIncomeNode => { return R.compose( R.when( this.query.isPreviousYearActive, - this.previousYearNetIncomeNodeCompose + this.previousYearNetIncomeNodeCompose, ), R.when( this.query.isPreviousPeriodActive, - this.previousPeriodNetIncomeNodeCompose + this.previousPeriodNetIncomeNodeCompose, ), R.when( this.query.isDatePeriodsColumnsType, - this.assocNetIncomeDatePeriodsNode + this.assocNetIncomeDatePeriodsNode, ), - this.schemaNetIncomeNodeMapper + this.schemaNetIncomeNodeMapper, )(node); }; @@ -160,7 +164,7 @@ export const BalanceSheetNetIncome = (Base: any) => public getNetIncomeDatePeriodNode = ( node: IBalanceSheetNetIncomeNode, fromDate: Date, - toDate: Date + toDate: Date, ): IBalanceSheetTotalPeriod => { const periodTotal = this.getNetIncomeDatePeriodTotal(toDate); @@ -173,11 +177,11 @@ export const BalanceSheetNetIncome = (Base: any) => * @returns {IBalanceSheetNetIncomeNode} */ public getNetIncomeDatePeriodsNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetTotalPeriod[] => { return this.getReportNodeDatePeriods( node, - this.getNetIncomeDatePeriodNode + this.getNetIncomeDatePeriodNode, ); }; @@ -187,7 +191,7 @@ export const BalanceSheetNetIncome = (Base: any) => * @returns {IBalanceSheetNetIncomeNode} */ public assocNetIncomeDatePeriodsNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetNetIncomeNode => { const datePeriods = this.getNetIncomeDatePeriodsNode(node); @@ -203,13 +207,13 @@ export const BalanceSheetNetIncome = (Base: any) => * @return {IBalanceSheetDataNode} */ public reportNetIncomeNodeSchemaParser = ( - schemaNode: IBalanceSheetSchemaNode + schemaNode: IBalanceSheetSchemaNode, ): IBalanceSheetDataNode => { return R.compose( R.when( this.isSchemaNodeType(BALANCE_SHEET_SCHEMA_NODE_TYPE.NET_INCOME), - this.schemaNetIncomeNodeCompose - ) + this.schemaNetIncomeNodeCompose, + ), )(schemaNode); }; @@ -219,7 +223,7 @@ export const BalanceSheetNetIncome = (Base: any) => * @return {IBalanceSheetDataNode[]} */ public netIncomeSchemaParser = ( - nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[] + nodes: (IBalanceSheetSchemaNode | IBalanceSheetDataNode)[], ): IBalanceSheetDataNode[] => { return this.mapNodesDeep(nodes, this.reportNetIncomeNodeSchemaParser); }; diff --git a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts similarity index 88% rename from temp/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts index e81d17c95..4b761c9fa 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriods.ts @@ -8,21 +8,25 @@ import { BalanceSheetComparsionPreviousPeriod } from './BalanceSheetComparsionPr import { FinancialPreviousPeriod } from '../../common/FinancialPreviousPeriod'; import { FinancialHorizTotals } from '../../common/FinancialHorizTotals'; import { BalanceSheetRepository } from './BalanceSheetRepository'; -import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetNetIncomePP } from './BalanceSheetNetIncomePP'; import { BalanceSheetNetIncomePY } from './BalanceSheetNetIncomePY'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { GConstructor } from '@/common/types/Constructor'; -export const BalanceSheetNetIncomeDatePeriods = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncomeDatePeriods = < + T extends GConstructor, +>( + Base: T, +) => + class extends R.pipe( BalanceSheetNetIncomePP, BalanceSheetNetIncomePY, BalanceSheetComparsionPreviousYear, BalanceSheetComparsionPreviousPeriod, FinancialPreviousPeriod, - FinancialHorizTotals + FinancialHorizTotals, )(Base) { - private repository: BalanceSheetRepository; - private query: BalanceSheetQuery; + repository: BalanceSheetRepository; // -------------------------------- // # Date Periods @@ -84,7 +88,7 @@ export const BalanceSheetNetIncomeDatePeriods = (Base: any) => private getNetIncomeDatePeriodNode = ( node: IBalanceSheetNetIncomeNode, fromDate: Date, - toDate: Date + toDate: Date, ): IBalanceSheetTotalPeriod => { const periodTotal = this.getNetIncomeDatePeriodTotal(toDate); @@ -97,11 +101,11 @@ export const BalanceSheetNetIncomeDatePeriods = (Base: any) => * @returns {IBalanceSheetNetIncomeNode} */ private getNetIncomeDatePeriodsNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetTotalPeriod[] => { return this.getReportNodeDatePeriods( node, - this.getNetIncomeDatePeriodNode + this.getNetIncomeDatePeriodNode, ); }; @@ -111,7 +115,7 @@ export const BalanceSheetNetIncomeDatePeriods = (Base: any) => * @returns {IBalanceSheetNetIncomeNode} */ public assocNetIncomeDatePeriodsNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetNetIncomeNode => { const datePeriods = this.getNetIncomeDatePeriodsNode(node); diff --git a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts similarity index 92% rename from temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts index f83849021..5e89b7403 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPP.ts @@ -7,10 +7,16 @@ import { IBalanceSheetTotal, } from './BalanceSheet.types'; import { BalanceSheetQuery } from './BalanceSheetQuery'; -import BalanceSheetRepository from './BalanceSheetRepository'; +import { BalanceSheetRepository } from './BalanceSheetRepository'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetNetIncomeDatePeriodsPP = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncomeDatePeriodsPP = < + T extends GConstructor, +>( + Base: T, +) => + class extends R.pipe( BalanceSheetComparsionPreviousPeriod, FinancialPreviousPeriod, FinancialHorizTotals, diff --git a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts similarity index 80% rename from temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts index ed6d86c4d..62518c6f0 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomeDatePeriodsPY.ts @@ -2,15 +2,24 @@ import * as R from 'ramda'; import { BalanceSheetComparsionPreviousYear } from './BalanceSheetComparsionPreviousYear'; import { FinancialPreviousPeriod } from '../../common/FinancialPreviousPeriod'; import { FinancialHorizTotals } from '../../common/FinancialHorizTotals'; -import { IBalanceSheetNetIncomeNode, IBalanceSheetTotal } from './BalanceSheet.types'; +import { + IBalanceSheetNetIncomeNode, + IBalanceSheetTotal, +} from './BalanceSheet.types'; import { BalanceSheetQuery } from './BalanceSheetQuery'; -import BalanceSheetRepository from './BalanceSheetRepository'; +import { BalanceSheetRepository } from './BalanceSheetRepository'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetNetIncomeDatePeriodsPY = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncomeDatePeriodsPY = < + T extends GConstructor, +>( + Base: T, +) => + class extends R.pipe( BalanceSheetComparsionPreviousYear, FinancialPreviousPeriod, - FinancialHorizTotals + FinancialHorizTotals, )(Base) { query: BalanceSheetQuery; repository: BalanceSheetRepository; @@ -67,10 +76,10 @@ export const BalanceSheetNetIncomeDatePeriodsPY = (Base: any) => public assocPreviousYearNetIncomeHorizTotal = R.curry( (node: IBalanceSheetNetIncomeNode, totalNode) => { const total = this.getPYNetIncomeDatePeriodTotal( - totalNode.previousYearToDate.date + totalNode.previousYearToDate.date, ); return R.assoc('previousYear', this.getAmountMeta(total), totalNode); - } + }, ); /** @@ -81,27 +90,27 @@ export const BalanceSheetNetIncomeDatePeriodsPY = (Base: any) => public previousYearNetIncomeHorizNodeComposer = R.curry( ( node: IBalanceSheetNetIncomeNode, - horiontalTotalNode: IBalanceSheetTotal + horiontalTotalNode: IBalanceSheetTotal, ): IBalanceSheetTotal => { return R.compose( R.when( this.query.isPreviousYearPercentageActive, - this.assocPreviousYearTotalPercentageNode + this.assocPreviousYearTotalPercentageNode, ), R.when( this.query.isPreviousYearChangeActive, - this.assocPreviousYearTotalChangeNode + this.assocPreviousYearTotalChangeNode, ), R.when( this.query.isPreviousYearActive, - this.assocPreviousYearNetIncomeHorizTotal(node) + this.assocPreviousYearNetIncomeHorizTotal(node), ), R.when( this.query.isPreviousYearActive, - this.assocPreviousYearHorizNodeFromToDates - ) + this.assocPreviousYearHorizNodeFromToDates, + ), )(horiontalTotalNode); - } + }, ); /** @@ -110,11 +119,11 @@ export const BalanceSheetNetIncomeDatePeriodsPY = (Base: any) => * @returns {IBalanceSheetCommonNode} */ public assocPreviousYearNetIncomeHorizNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetNetIncomeNode => { const horizontalTotals = R.addIndex(R.map)( this.previousYearNetIncomeHorizNodeComposer(node), - node.horizontalTotals + node.horizontalTotals, ) as IBalanceSheetTotal[]; return R.assoc('horizontalTotals', horizontalTotals, node); diff --git a/temp/BalanceSheet/BalanceSheetNetIncomePP.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePP.ts similarity index 90% rename from temp/BalanceSheet/BalanceSheetNetIncomePP.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePP.ts index c3684cff1..ba0fb7154 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncomePP.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePP.ts @@ -9,9 +9,13 @@ import { FinancialHorizTotals } from '../../common/FinancialHorizTotals'; import { BalanceSheetRepository } from './BalanceSheetRepository'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetNetIncomeDatePeriodsPP } from './BalanceSheetNetIncomeDatePeriodsPP'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { GConstructor } from '@/common/types/Constructor'; -export const BalanceSheetNetIncomePP = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncomePP = >( + Base: T, +) => + class extends R.pipe( BalanceSheetNetIncomeDatePeriodsPP, BalanceSheetComparsionPreviousPeriod, FinancialPreviousPeriod, diff --git a/temp/BalanceSheet/BalanceSheetNetIncomePY.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePY.ts similarity index 75% rename from temp/BalanceSheet/BalanceSheetNetIncomePY.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePY.ts index b99010845..99f96e191 100644 --- a/temp/BalanceSheet/BalanceSheetNetIncomePY.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetNetIncomePY.ts @@ -1,8 +1,5 @@ import * as R from 'ramda'; -import { - IBalanceSheetDataNode, - IBalanceSheetNetIncomeNode, -} from './BalanceSheet.types'; +import { IBalanceSheetNetIncomeNode } from './BalanceSheet.types'; import { BalanceSheetComparsionPreviousYear } from './BalanceSheetComparsionPreviousYear'; import { BalanceSheetComparsionPreviousPeriod } from './BalanceSheetComparsionPreviousPeriod'; import { FinancialPreviousPeriod } from '../../common/FinancialPreviousPeriod'; @@ -10,17 +7,21 @@ import { FinancialHorizTotals } from '../../common/FinancialHorizTotals'; import { BalanceSheetRepository } from './BalanceSheetRepository'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { BalanceSheetNetIncomeDatePeriodsPY } from './BalanceSheetNetIncomeDatePeriodsPY'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { GConstructor } from '@/common/types/Constructor'; -export const BalanceSheetNetIncomePY = (Base: any) => - class extends R.compose( +export const BalanceSheetNetIncomePY = >( + Base: T, +) => + class extends R.pipe( BalanceSheetNetIncomeDatePeriodsPY, BalanceSheetComparsionPreviousYear, BalanceSheetComparsionPreviousPeriod, FinancialPreviousPeriod, - FinancialHorizTotals + FinancialHorizTotals, )(Base) { - public repository: BalanceSheetRepository; - public query: BalanceSheetQuery; + // public repository: BalanceSheetRepository; + // public query: BalanceSheetQuery; // ------------------------------ // # Previous Year (PY) @@ -44,7 +45,7 @@ export const BalanceSheetNetIncomePY = (Base: any) => * @returns {IBalanceSheetAccountNode} */ public assocPreviousYearNetIncomeNode = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetNetIncomeNode => { const total = this.getPreviousYearNetIncome(); @@ -57,23 +58,23 @@ export const BalanceSheetNetIncomePY = (Base: any) => * @returns {IBalanceSheetAccountNode} */ public previousYearNetIncomeNodeCompose = ( - node: IBalanceSheetNetIncomeNode + node: IBalanceSheetNetIncomeNode, ): IBalanceSheetNetIncomeNode => { return R.compose( R.when( this.query.isPreviousYearPercentageActive, - this.assocPreviousYearTotalPercentageNode + this.assocPreviousYearTotalPercentageNode, ), R.when( this.query.isPreviousYearChangeActive, - this.assocPreviousYearTotalChangeNode + this.assocPreviousYearTotalChangeNode, ), // Associate the PY to date periods horizontal nodes. R.when( this.isNodeHasHorizontalTotals, - this.assocPreviousYearNetIncomeHorizNode + this.assocPreviousYearNetIncomeHorizNode, ), - this.assocPreviousYearNetIncomeNode + this.assocPreviousYearNetIncomeNode, )(node); }; }; diff --git a/temp/BalanceSheet/BalanceSheetPdfInjectable.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPdfInjectable.ts similarity index 88% rename from temp/BalanceSheet/BalanceSheetPdfInjectable.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPdfInjectable.ts index 3589d599a..d472ba0d1 100644 --- a/temp/BalanceSheet/BalanceSheetPdfInjectable.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPdfInjectable.ts @@ -13,13 +13,10 @@ export class BalanceSheetPdfInjectable { /** * Converts the given balance sheet table to pdf. - * @param {number} tenantId - Tenant ID. * @param {IBalanceSheetQuery} query - Balance sheet query. * @returns {Promise} */ - public async pdf( - query: IBalanceSheetQuery, - ): Promise { + public async pdf(query: IBalanceSheetQuery): Promise { const table = await this.balanceSheetTable.table(query); return this.tableSheetPdf.convertToPdf( diff --git a/temp/BalanceSheet/BalanceSheetPercentage.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPercentage.ts similarity index 76% rename from temp/BalanceSheet/BalanceSheetPercentage.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPercentage.ts index f946d5693..8647759b1 100644 --- a/temp/BalanceSheet/BalanceSheetPercentage.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetPercentage.ts @@ -2,32 +2,35 @@ import * as R from 'ramda'; import { get } from 'lodash'; import { BalanceSheetQuery } from './BalanceSheetQuery'; import { IBalanceSheetDataNode } from './BalanceSheet.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetPercentage = (Base: T) => +export const BalanceSheetPercentage = >( + Base: T, +) => class extends Base { readonly query: BalanceSheetQuery; /** * Assoc percentage of column to report node. - * @param {IBalanceSheetDataNode} node + * @param {IBalanceSheetDataNode} node * @returns {IBalanceSheetDataNode} */ public assocReportNodeColumnPercentage = R.curry( ( parentTotal: number, - node: IBalanceSheetDataNode + node: IBalanceSheetDataNode, ): IBalanceSheetDataNode => { const percentage = this.getPercentageBasis( parentTotal, - node.total.amount + node.total.amount, ); return R.assoc( 'percentageColumn', this.getPercentageAmountMeta(percentage), - node + node, ); - } + }, ); /** @@ -38,18 +41,18 @@ export const BalanceSheetPercentage = (Base: T) => public assocReportNodeRowPercentage = R.curry( ( parentTotal: number, - node: IBalanceSheetDataNode + node: IBalanceSheetDataNode, ): IBalanceSheetDataNode => { const percenatage = this.getPercentageBasis( parentTotal, - node.total.amount + node.total.amount, ); return R.assoc( 'percentageRow', this.getPercentageAmountMeta(percenatage), - node + node, ); - } + }, ); /** @@ -61,13 +64,13 @@ export const BalanceSheetPercentage = (Base: T) => public assocRowPercentageHorizTotals = R.curry( ( parentTotal: number, - node: IBalanceSheetDataNode + node: IBalanceSheetDataNode, ): IBalanceSheetDataNode => { const assocRowPercen = this.assocReportNodeRowPercentage(parentTotal); const horTotals = R.map(assocRowPercen)(node.horizontalTotals); return R.assoc('horizontalTotals', horTotals, node); - } + }, ); /** @@ -81,10 +84,10 @@ export const BalanceSheetPercentage = (Base: T) => const parentTotal = get( parentNode, `horizontalTotals[${index}].total.amount`, - 0 + 0, ); return this.assocReportNodeColumnPercentage(parentTotal, horTotalNode); - } + }, ); /** @@ -95,15 +98,15 @@ export const BalanceSheetPercentage = (Base: T) => public assocColumnPercentageHorizTotals = R.curry( ( parentNode: IBalanceSheetDataNode, - node: IBalanceSheetDataNode + node: IBalanceSheetDataNode, ): IBalanceSheetDataNode => { // Horizontal totals. const assocColPerc = this.assocColumnPercentageHorizTotal(parentNode); const horTotals = R.addIndex(R.map)(assocColPerc)( - node.horizontalTotals + node.horizontalTotals, ); return R.assoc('horizontalTotals', horTotals, node); - } + }, ); /** @@ -112,19 +115,17 @@ export const BalanceSheetPercentage = (Base: T) => * @param {} node * @returns */ - public reportNodeColumnPercentageComposer = R.curry( - (parentNode, node) => { - const parentTotal = parentNode.total.amount; + public reportNodeColumnPercentageComposer = R.curry((parentNode, node) => { + const parentTotal = parentNode.total.amount; - return R.compose( - R.when( - this.isNodeHasHorizoTotals, - this.assocColumnPercentageHorizTotals(parentNode) - ), - this.assocReportNodeColumnPercentage(parentTotal) - )(node); - } - ); + return R.compose( + R.when( + this.isNodeHasHorizoTotals, + this.assocColumnPercentageHorizTotals(parentNode), + ), + this.assocReportNodeColumnPercentage(parentTotal), + )(node); + }); /** * @@ -137,9 +138,9 @@ export const BalanceSheetPercentage = (Base: T) => return R.compose( R.when( this.isNodeHasHorizoTotals, - this.assocRowPercentageHorizTotals(total) + this.assocRowPercentageHorizTotals(total), ), - this.assocReportNodeRowPercentage(total) + this.assocReportNodeRowPercentage(total), )(node); }; @@ -149,7 +150,7 @@ export const BalanceSheetPercentage = (Base: T) => private assocNodeColumnPercentageChildren = (node) => { const children = this.mapNodesDeep( node.children, - this.reportNodeColumnPercentageComposer(node) + this.reportNodeColumnPercentageComposer(node), ); return R.assoc('children', children, node); }; @@ -166,10 +167,10 @@ export const BalanceSheetPercentage = (Base: T) => return R.compose( R.when( this.isNodeHasHorizoTotals, - this.assocColumnPercentageHorizTotals(parentNode) + this.assocColumnPercentageHorizTotals(parentNode), ), this.assocReportNodeColumnPercentage(parentTotal), - this.assocNodeColumnPercentageChildren + this.assocNodeColumnPercentageChildren, )(node); }; @@ -179,7 +180,7 @@ export const BalanceSheetPercentage = (Base: T) => * @returns {IBalanceSheetDataNode[]} */ private reportColumnsPercentageMapper = ( - nodes: IBalanceSheetDataNode[] + nodes: IBalanceSheetDataNode[], ): IBalanceSheetDataNode[] => { return R.map(this.reportNodeColumnPercentageDeepMap, nodes); }; @@ -202,12 +203,12 @@ export const BalanceSheetPercentage = (Base: T) => return R.compose( R.when( this.query.isColumnsPercentageActive, - this.reportColumnsPercentageMapper + this.reportColumnsPercentageMapper, ), R.when( this.query.isRowsPercentageActive, - this.reportRowsPercentageMapper - ) + this.reportRowsPercentageMapper, + ), )(nodes); }; @@ -216,9 +217,7 @@ export const BalanceSheetPercentage = (Base: T) => * @param {IBalanceSheetDataNode} node * @returns {boolean} */ - public isNodeHasHorizoTotals = ( - node: IBalanceSheetDataNode - ): boolean => { + public isNodeHasHorizoTotals = (node: IBalanceSheetDataNode): boolean => { return ( !R.isEmpty(node.horizontalTotals) && !R.isNil(node.horizontalTotals) ); diff --git a/temp/BalanceSheet/BalanceSheetQuery.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetQuery.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetQuery.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetQuery.ts diff --git a/temp/BalanceSheet/BalanceSheetRepository.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepository.ts similarity index 94% rename from temp/BalanceSheet/BalanceSheetRepository.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepository.ts index 0e2a42729..346e0da9e 100644 --- a/temp/BalanceSheet/BalanceSheetRepository.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepository.ts @@ -15,30 +15,28 @@ 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 + FinancialDatePeriods, )(class {}) { /** - * + * Account model. */ @Inject(Account.name) public readonly accountModel: typeof Account; + /** + * Account transaction model. + */ @Inject(AccountTransaction.name) public readonly accountTransactionModel: typeof AccountTransaction; /** - * @param {number} - */ - public readonly tenantId: number; - - /** + * @description Balance sheet query. * @param {BalanceSheetQuery} */ - public readonly query: BalanceSheetQuery; + public query: BalanceSheetQuery; /** * @param {} @@ -153,14 +151,13 @@ export class BalanceSheetRepository extends R.compose( /** * Constructor method. - * @param {number} tenantId * @param {IBalanceSheetQuery} query */ public setQuery(query: IBalanceSheetQuery) { this.query = new BalanceSheetQuery(query); this.transactionsGroupType = this.getGroupByFromDisplayColumnsBy( - this.query.displayColumnsBy + this.query.displayColumnsBy, ); } @@ -248,16 +245,16 @@ export class BalanceSheetRepository extends R.compose( const periodsByAccount = await this.accountsDatePeriods( this.query.fromDate, this.query.toDate, - this.transactionsGroupType + this.transactionsGroupType, ); // Retrieves opening balance of grouped transactions. const periodsOpeningByAccount = await this.closingAccountsTotal( - this.query.fromDate + this.query.fromDate, ); // Inject to the repository. this.periodsAccountsLedger = Ledger.fromTransactions(periodsByAccount); this.periodsOpeningAccountLedger = Ledger.fromTransactions( - periodsOpeningByAccount + periodsOpeningByAccount, ); }; @@ -270,7 +267,7 @@ export class BalanceSheetRepository extends R.compose( */ public initTotalPreviousYear = async (): Promise => { const PYTotalsByAccounts = await this.closingAccountsTotal( - this.query.PYToDate + this.query.PYToDate, ); // Inject to the repository. this.PYTotalAccountsLedger = Ledger.fromTransactions(PYTotalsByAccounts); @@ -284,16 +281,16 @@ export class BalanceSheetRepository extends R.compose( const PYPeriodsBYAccounts = await this.accountsDatePeriods( this.query.PYFromDate, this.query.PYToDate, - this.transactionsGroupType + this.transactionsGroupType, ); // Retrieves opening balance of grouped transactions. const periodsOpeningByAccount = await this.closingAccountsTotal( - this.query.PYFromDate + this.query.PYFromDate, ); // Inject to the repository. this.PYPeriodsAccountsLedger = Ledger.fromTransactions(PYPeriodsBYAccounts); this.PYPeriodsOpeningAccountLedger = Ledger.fromTransactions( - periodsOpeningByAccount + periodsOpeningByAccount, ); }; @@ -306,7 +303,7 @@ export class BalanceSheetRepository extends R.compose( */ public initTotalPreviousPeriod = async (): Promise => { const PPTotalsByAccounts = await this.closingAccountsTotal( - this.query.PPToDate + this.query.PPToDate, ); // Inject to the repository. this.PPTotalAccountsLedger = Ledger.fromTransactions(PPTotalsByAccounts); @@ -320,16 +317,16 @@ export class BalanceSheetRepository extends R.compose( const PPPeriodsBYAccounts = await this.accountsDatePeriods( this.query.PPFromDate, this.query.PPToDate, - this.transactionsGroupType + this.transactionsGroupType, ); // Retrieves opening balance of grouped transactions. const periodsOpeningByAccount = await this.closingAccountsTotal( - this.query.PPFromDate + this.query.PPFromDate, ); // Inject to the repository. this.PPPeriodsAccountsLedger = Ledger.fromTransactions(PPPeriodsBYAccounts); this.PPPeriodsOpeningAccountLedger = Ledger.fromTransactions( - periodsOpeningByAccount + periodsOpeningByAccount, ); }; @@ -354,7 +351,7 @@ export class BalanceSheetRepository extends R.compose( public accountsDatePeriods = async ( fromDate: Date, toDate: Date, - datePeriodsType: string + datePeriodsType: string, ) => { return this.accountTransactionModel.query().onBuild((query) => { query.sum('credit as credit'); diff --git a/temp/BalanceSheet/BalanceSheetRepositoryNetIncome.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepositoryNetIncome.ts similarity index 97% rename from temp/BalanceSheet/BalanceSheetRepositoryNetIncome.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepositoryNetIncome.ts index 5ef58a60e..4882576a4 100644 --- a/temp/BalanceSheet/BalanceSheetRepositoryNetIncome.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetRepositoryNetIncome.ts @@ -5,11 +5,14 @@ import { Account } from '@/modules/Accounts/models/Account.model'; import { ILedger } from '@/modules/Ledger/types/Ledger.types'; import { ACCOUNT_PARENT_TYPE } from '@/constants/accounts'; import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetRepositoryNetIncome = ( +export const BalanceSheetRepositoryNetIncome = < + T extends GConstructor, +>( Base: T, ) => - class extends R.compose(FinancialDatePeriods)(Base) { + class extends R.pipe(FinancialDatePeriods)(Base) { // ----------------------- // # Net Income // ----------------------- diff --git a/temp/BalanceSheet/BalanceSheetSchema.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetSchema.ts similarity index 94% rename from temp/BalanceSheet/BalanceSheetSchema.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetSchema.ts index 7a5ff22d2..ca9bb4cf6 100644 --- a/temp/BalanceSheet/BalanceSheetSchema.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetSchema.ts @@ -5,11 +5,14 @@ import { BALANCE_SHEET_SCHEMA_NODE_TYPE, } from './BalanceSheet.types'; import { FinancialSchema } from '../../common/FinancialSchema'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; import { ACCOUNT_TYPE } from '@/constants/accounts'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetSchema = (Base: T) => - class extends R.compose(FinancialSchema)(Base) { +export const BalanceSheetSchema = >( + Base: T, +) => + class extends R.pipe(FinancialSchema)(Base) { /** * Retrieves the balance sheet schema. * @returns @@ -17,7 +20,7 @@ export const BalanceSheetSchema = (Base: T) => getSchema = () => { return getBalanceSheetSchema(); }; -}; + }; /** * Retrieve the balance sheet report schema. diff --git a/temp/BalanceSheet/BalanceSheetTable.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTable.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetTable.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTable.ts diff --git a/temp/BalanceSheet/BalanceSheetTableDatePeriods.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableDatePeriods.ts similarity index 86% rename from temp/BalanceSheet/BalanceSheetTableDatePeriods.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableDatePeriods.ts index 1f6b1be34..4dc0c36ff 100644 --- a/temp/BalanceSheet/BalanceSheetTableDatePeriods.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableDatePeriods.ts @@ -1,15 +1,17 @@ import * as R from 'ramda'; import * as moment from 'moment'; -import { - ITableColumn, - ITableColumnAccessor, -} from '../../types/Table.types'; +import { ITableColumn, ITableColumnAccessor } from '../../types/Table.types'; import { FinancialDatePeriods } from '../../common/FinancialDatePeriods'; import { IDateRange } from '../CashFlow/Cashflow.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetTableDatePeriods = (Base: T) => - class extends R.compose(FinancialDatePeriods)(Base) { +export const BalanceSheetTableDatePeriods = < + T extends GConstructor, +>( + Base: T, +) => + class extends R.pipe(FinancialDatePeriods)(Base) { /** * Retrieves the date periods based on the report query. * @returns {IDateRange[]} @@ -18,7 +20,7 @@ export const BalanceSheetTableDatePeriods = (Base: T) => return this.getDateRanges( this.query.fromDate, this.query.toDate, - this.query.displayColumnsBy + this.query.displayColumnsBy, ); } @@ -44,7 +46,7 @@ export const BalanceSheetTableDatePeriods = (Base: T) => R.always(this.query.isDisplayColumnsBy(type)), formatFn, ], - conditions + conditions, ); return R.compose(R.cond(conditionsPairs))(dateRange); }; @@ -68,9 +70,9 @@ export const BalanceSheetTableDatePeriods = (Base: T) => key: `date-range-${index}`, accessor: `horizontalTotals[${index}].total.formattedAmount`, }, - ]) + ]), )([]); - } + }, ); /** @@ -80,7 +82,7 @@ export const BalanceSheetTableDatePeriods = (Base: T) => public datePeriodsColumnsAccessors = (): ITableColumnAccessor[] => { return R.compose( R.flatten, - R.addIndex(R.map)(this.datePeriodColumnsAccessor) + R.addIndex(R.map)(this.datePeriodColumnsAccessor), )(this.datePeriods); }; @@ -95,18 +97,18 @@ export const BalanceSheetTableDatePeriods = (Base: T) => */ public datePeriodChildrenColumns = ( index: number, - dateRange: IDateRange + dateRange: IDateRange, ) => { return R.compose( R.unless( R.isEmpty, R.concat([ { key: `total`, label: this.i18n.__('balance_sheet.total') }, - ]) + ]), ), R.concat(this.percentageColumns()), R.concat(this.getPreviousYearHorizontalColumns(dateRange)), - R.concat(this.previousPeriodHorizontalColumns(dateRange)) + R.concat(this.previousPeriodHorizontalColumns(dateRange)), )([]); }; @@ -118,7 +120,7 @@ export const BalanceSheetTableDatePeriods = (Base: T) => */ public datePeriodColumn = ( dateRange: IDateRange, - index: number + index: number, ): ITableColumn => { return { key: `date-range-${index}`, diff --git a/temp/BalanceSheet/BalanceSheetTableInjectable.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableInjectable.ts similarity index 94% rename from temp/BalanceSheet/BalanceSheetTableInjectable.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableInjectable.ts index 627776a22..03f582223 100644 --- a/temp/BalanceSheet/BalanceSheetTableInjectable.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTableInjectable.ts @@ -13,8 +13,7 @@ export class BalanceSheetTableInjectable { /** * Retrieves the balance sheet in table format. - * @param {number} tenantId - * @param {number} query + * @param {number} query - * @returns {Promise} */ public async table(filter: IBalanceSheetQuery): Promise { diff --git a/temp/BalanceSheet/BalanceSheetTablePercentage.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePercentage.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetTablePercentage.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePercentage.ts diff --git a/temp/BalanceSheet/BalanceSheetTablePreviousPeriod.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousPeriod.ts similarity index 75% rename from temp/BalanceSheet/BalanceSheetTablePreviousPeriod.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousPeriod.ts index baa726d02..5859fe5dc 100644 --- a/temp/BalanceSheet/BalanceSheetTablePreviousPeriod.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousPeriod.ts @@ -4,12 +4,17 @@ import { FinancialTablePreviousPeriod } from '../../common/FinancialTablePreviou import { FinancialDateRanges } from '../../common/FinancialDateRanges'; import { IDateRange } from '../../types/Report.types'; import { ITableColumn } from '../../types/Table.types'; -import { Constructor } from '@/common/types/Constructor'; +import { GConstructor } from '@/common/types/Constructor'; +import { FinancialSheet } from '../../common/FinancialSheet'; -export const BalanceSheetTablePreviousPeriod = (Base: T) => - class BalanceSheetTablePreviousPeriod extends R.compose( +export const BalanceSheetTablePreviousPeriod = < + T extends GConstructor, +>( + Base: T, +) => + class BalanceSheetTablePreviousPeriod extends R.pipe( FinancialTablePreviousPeriod, - FinancialDateRanges + FinancialDateRanges, )(Base) { readonly query: BalanceSheetQuery; @@ -20,23 +25,21 @@ export const BalanceSheetTablePreviousPeriod = (Base: T) * Retrieves the previous period columns. * @returns {ITableColumn[]} */ - public previousPeriodColumns = ( - dateRange?: IDateRange - ): ITableColumn[] => { + public previousPeriodColumns = (dateRange?: IDateRange): ITableColumn[] => { return R.pipe( // Previous period columns. R.when( this.query.isPreviousPeriodActive, - R.append(this.getPreviousPeriodTotalColumn(dateRange)) + R.append(this.getPreviousPeriodTotalColumn(dateRange)), ), R.when( this.query.isPreviousPeriodChangeActive, - R.append(this.getPreviousPeriodChangeColumn()) + R.append(this.getPreviousPeriodChangeColumn()), ), R.when( this.query.isPreviousPeriodPercentageActive, - R.append(this.getPreviousPeriodPercentageColumn()) - ) + R.append(this.getPreviousPeriodPercentageColumn()), + ), )([]); }; @@ -46,12 +49,12 @@ export const BalanceSheetTablePreviousPeriod = (Base: T) * @returns {ITableColumn} */ public previousPeriodHorizontalColumns = ( - dateRange: IDateRange + dateRange: IDateRange, ): ITableColumn[] => { const PPDateRange = this.getPPDatePeriodDateRange( dateRange.fromDate, dateRange.toDate, - this.query.displayColumnsBy + this.query.displayColumnsBy, ); return this.previousPeriodColumns({ fromDate: PPDateRange.fromDate, @@ -71,16 +74,16 @@ export const BalanceSheetTablePreviousPeriod = (Base: T) // Previous period columns. R.when( this.query.isPreviousPeriodActive, - R.append(this.getPreviousPeriodTotalAccessor()) + R.append(this.getPreviousPeriodTotalAccessor()), ), R.when( this.query.isPreviousPeriodChangeActive, - R.append(this.getPreviousPeriodChangeAccessor()) + R.append(this.getPreviousPeriodChangeAccessor()), ), R.when( this.query.isPreviousPeriodPercentageActive, - R.append(this.getPreviousPeriodPercentageAccessor()) - ) + R.append(this.getPreviousPeriodPercentageAccessor()), + ), )([]); }; @@ -90,22 +93,22 @@ export const BalanceSheetTablePreviousPeriod = (Base: T) * @returns */ public previousPeriodHorizColumnAccessors = ( - index: number + index: number, ): ITableColumn[] => { return R.pipe( // Previous period columns. R.when( this.query.isPreviousPeriodActive, - R.append(this.getPreviousPeriodTotalHorizAccessor(index)) + R.append(this.getPreviousPeriodTotalHorizAccessor(index)), ), R.when( this.query.isPreviousPeriodChangeActive, - R.append(this.getPreviousPeriodChangeHorizAccessor(index)) + R.append(this.getPreviousPeriodChangeHorizAccessor(index)), ), R.when( this.query.isPreviousPeriodPercentageActive, - R.append(this.getPreviousPeriodPercentageHorizAccessor(index)) - ) + R.append(this.getPreviousPeriodPercentageHorizAccessor(index)), + ), )([]); }; }; diff --git a/temp/BalanceSheet/BalanceSheetTablePreviousYear.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousYear.ts similarity index 79% rename from temp/BalanceSheet/BalanceSheetTablePreviousYear.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousYear.ts index f5f9e329b..c4c0c718c 100644 --- a/temp/BalanceSheet/BalanceSheetTablePreviousYear.ts +++ b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTablePreviousYear.ts @@ -1,12 +1,12 @@ import * as R from 'ramda'; -import { IDateRange, } from '../../types/Report.types'; +import { IDateRange } from '../../types/Report.types'; import { ITableColumn } from '../../types/Table.types'; import { FinancialTablePreviousYear } from '../../common/FinancialTablePreviousYear'; import { FinancialDateRanges } from '../../common/FinancialDateRanges'; import { Constructor } from '@/common/types/Constructor'; export const BalanceSheetTablePreviousYear = (Base: T) => - class extends R.compose(FinancialTablePreviousYear, FinancialDateRanges)(Base) { + class extends R.pipe(FinancialTablePreviousYear, FinancialDateRanges)(Base) { // -------------------- // # Columns. // -------------------- @@ -15,34 +15,34 @@ export const BalanceSheetTablePreviousYear = (Base: T) => * @returns {ITableColumn[]} */ public getPreviousYearColumns = ( - dateRange?: IDateRange + dateRange?: IDateRange, ): ITableColumn[] => { return R.pipe( // Previous year columns. R.when( this.query.isPreviousYearActive, - R.append(this.getPreviousYearTotalColumn(dateRange)) + R.append(this.getPreviousYearTotalColumn(dateRange)), ), R.when( this.query.isPreviousYearChangeActive, - R.append(this.getPreviousYearChangeColumn()) + R.append(this.getPreviousYearChangeColumn()), ), R.when( this.query.isPreviousYearPercentageActive, - R.append(this.getPreviousYearPercentageColumn()) - ) + R.append(this.getPreviousYearPercentageColumn()), + ), )([]); }; /** - * + * * @param {IDateRange} dateRange * @returns */ public getPreviousYearHorizontalColumns = (dateRange: IDateRange) => { const PYDateRange = this.getPreviousYearDateRange( dateRange.fromDate, - dateRange.toDate + dateRange.toDate, ); return this.getPreviousYearColumns(PYDateRange); }; @@ -59,16 +59,16 @@ export const BalanceSheetTablePreviousYear = (Base: T) => // Previous year columns. R.when( this.query.isPreviousYearActive, - R.append(this.getPreviousYearTotalAccessor()) + R.append(this.getPreviousYearTotalAccessor()), ), R.when( this.query.isPreviousYearChangeActive, - R.append(this.getPreviousYearChangeAccessor()) + R.append(this.getPreviousYearChangeAccessor()), ), R.when( this.query.isPreviousYearPercentageActive, - R.append(this.getPreviousYearPercentageAccessor()) - ) + R.append(this.getPreviousYearPercentageAccessor()), + ), )([]); }; @@ -78,22 +78,22 @@ export const BalanceSheetTablePreviousYear = (Base: T) => * @returns {ITableColumn[]} */ public previousYearHorizontalColumnAccessors = ( - index: number + index: number, ): ITableColumn[] => { return R.pipe( // Previous year columns. R.when( this.query.isPreviousYearActive, - R.append(this.getPreviousYearTotalHorizAccessor(index)) + R.append(this.getPreviousYearTotalHorizAccessor(index)), ), R.when( this.query.isPreviousYearChangeActive, - R.append(this.getPreviousYearChangeHorizAccessor(index)) + R.append(this.getPreviousYearChangeHorizAccessor(index)), ), R.when( this.query.isPreviousYearPercentageActive, - R.append(this.getPreviousYearPercentageHorizAccessor(index)) - ) + R.append(this.getPreviousYearPercentageHorizAccessor(index)), + ), )([]); }; }; diff --git a/temp/BalanceSheet/BalanceSheetTotal.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTotal.ts similarity index 100% rename from temp/BalanceSheet/BalanceSheetTotal.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/BalanceSheetTotal.ts diff --git a/temp/BalanceSheet/constants.ts b/packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/constants.ts similarity index 100% rename from temp/BalanceSheet/constants.ts rename to packages/server-nest/src/modules/FinancialStatements/modules/BalanceSheet/constants.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4f992085..ecaa78f4f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -667,6 +667,9 @@ importers: strategy: specifier: ^1.1.1 version: 1.1.1 + stripe: + specifier: ^16.10.0 + version: 16.10.0 uniqid: specifier: ^5.2.0 version: 5.4.0 @@ -10572,7 +10575,7 @@ packages: '@storybook/client-logger': 7.6.17 '@storybook/core-events': 7.6.17 '@storybook/global': 5.0.0 - qs: 6.12.1 + qs: 6.13.0 telejson: 7.2.0 tiny-invariant: 1.3.3 dev: true @@ -10583,7 +10586,7 @@ packages: '@storybook/client-logger': 7.6.20 '@storybook/core-events': 7.6.20 '@storybook/global': 5.0.0 - qs: 6.12.1 + qs: 6.13.0 telejson: 7.2.0 tiny-invariant: 1.3.3 dev: true @@ -11169,7 +11172,7 @@ packages: dependencies: '@storybook/client-logger': 7.6.17 memoizerific: 1.11.3 - qs: 6.12.1 + qs: 6.13.0 dev: true /@storybook/router@7.6.20: @@ -11177,7 +11180,7 @@ packages: dependencies: '@storybook/client-logger': 7.6.20 memoizerific: 1.11.3 - qs: 6.12.1 + qs: 6.13.0 dev: true /@storybook/telemetry@7.2.2: @@ -32929,7 +32932,7 @@ packages: http-basic: 8.1.3 http-response-object: 3.0.2 promise: 8.3.0 - qs: 6.12.1 + qs: 6.13.0 dev: false /thenify-all@1.6.0: diff --git a/temp/CashFlowStatement/CashFlow.ts b/temp/CashFlowStatement/CashFlow.ts new file mode 100644 index 000000000..47df3e94f --- /dev/null +++ b/temp/CashFlowStatement/CashFlow.ts @@ -0,0 +1,705 @@ +import * as R from 'ramda'; +import { defaultTo, map, set, sumBy, isEmpty, mapValues, get } from 'lodash'; +import * as mathjs from 'mathjs'; +import * as moment from 'moment'; +import { compose } from 'lodash/fp'; +import { I18nService } from 'nestjs-i18n'; +import { + ICashFlowSchemaSection, + ICashFlowStatementQuery, + ICashFlowStatementNetIncomeSection, + ICashFlowStatementAccountSection, + ICashFlowSchemaSectionAccounts, + ICashFlowStatementAccountMeta, + ICashFlowSchemaAccountRelation, + ICashFlowStatementSectionType, + ICashFlowStatementData, + ICashFlowSchemaTotalSection, + ICashFlowStatementTotalSection, + ICashFlowStatementSection, + ICashFlowCashBeginningNode, + ICashFlowStatementAggregateSection, +} from './Cashflow.types'; +import { CASH_FLOW_SCHEMA } from './schema'; +import { FinancialSheet } from '../../common/FinancialSheet'; +import { ACCOUNT_ROOT_TYPE } from '@/constants/accounts'; +import { CashFlowStatementDatePeriods } from './CashFlowDatePeriods'; +import { DISPLAY_COLUMNS_BY } from './constants'; +import { FinancialSheetStructure } from '../../common/FinancialSheetStructure'; +import { Account } from '@/modules/Accounts/models/Account.model'; +import { ILedger } from '@/modules/Ledger/types/Ledger.types'; +import { INumberFormatQuery } from '../../types/Report.types'; +import { transformToMapBy } from '@/utils/transform-to-map-by'; +import { accumSum } from '@/utils/accum-sum'; +import { ModelObject } from 'objection'; + +export default class CashFlowStatement extends compose( + CashFlowStatementDatePeriods, + FinancialSheetStructure +)(FinancialSheet) { + readonly baseCurrency: string; + readonly i18n: I18nService; + readonly sectionsByIds = {}; + readonly cashFlowSchemaMap: Map; + readonly cashFlowSchemaSeq: Array; + readonly accountByTypeMap: Map; + readonly accountsByRootType: Map; + readonly ledger: ILedger; + readonly cashLedger: ILedger; + readonly netIncomeLedger: ILedger; + readonly query: ICashFlowStatementQuery; + readonly numberFormat: INumberFormatQuery; + readonly comparatorDateType: string; + readonly dateRangeSet: { fromDate: Date; toDate: Date }[]; + + /** + * Constructor method. + * @constructor + */ + constructor( + accounts: Account[], + ledger: ILedger, + cashLedger: ILedger, + netIncomeLedger: ILedger, + query: ICashFlowStatementQuery, + baseCurrency: string, + i18n + ) { + super(); + + this.baseCurrency = baseCurrency; + this.i18n = i18n; + this.ledger = ledger; + this.cashLedger = cashLedger; + this.netIncomeLedger = netIncomeLedger; + this.accountByTypeMap = transformToMapBy(accounts, 'accountType'); + this.accountsByRootType = transformToMapBy(accounts, 'accountRootType'); + this.query = query; + this.numberFormat = this.query.numberFormat; + this.dateRangeSet = []; + this.comparatorDateType = + query.displayColumnsType === 'total' ? 'day' : query.displayColumnsBy; + + this.initDateRangeCollection(); + } + + // -------------------------------------------- + // # GENERAL UTILITIES + // -------------------------------------------- + /** + * Retrieve the expense accounts ids. + * @return {number[]} + */ + private getAccountsIdsByType = (accountType: string): number[] => { + const expenseAccounts = this.accountsByRootType.get(accountType); + const expenseAccountsIds = map(expenseAccounts, 'id'); + + return expenseAccountsIds; + }; + + /** + * Detarmines the given display columns by type. + * @param {string} displayColumnsBy + * @returns {boolean} + */ + private isDisplayColumnsBy = (displayColumnsBy: string): boolean => { + return this.query.displayColumnsType === displayColumnsBy; + }; + + /** + * Adjustments the given amount. + * @param {string} direction + * @param {number} amount - + * @return {number} + */ + private amountAdjustment = (direction: 'mines' | 'plus', amount): number => { + return R.when( + R.always(R.equals(direction, 'mines')), + R.multiply(-1) + )(amount); + }; + + // -------------------------------------------- + // # NET INCOME NODE + // -------------------------------------------- + /** + * Retrieve the accounts net income. + * @returns {number} - Amount of net income. + */ + private getAccountsNetIncome(): number { + // Mapping income/expense accounts ids. + const incomeAccountsIds = this.getAccountsIdsByType( + ACCOUNT_ROOT_TYPE.INCOME + ); + const expenseAccountsIds = this.getAccountsIdsByType( + ACCOUNT_ROOT_TYPE.EXPENSE + ); + // Income closing balance. + const incomeClosingBalance = accumSum(incomeAccountsIds, (id) => + this.netIncomeLedger.whereAccountId(id).getClosingBalance() + ); + // Expense closing balance. + const expenseClosingBalance = accumSum(expenseAccountsIds, (id) => + this.netIncomeLedger.whereAccountId(id).getClosingBalance() + ); + // Net income = income - expenses. + const netIncome = incomeClosingBalance - expenseClosingBalance; + + return netIncome; + } + + /** + * Parses the net income section from the given section schema. + * @param {ICashFlowSchemaSection} nodeSchema - Report section schema. + * @returns {ICashFlowStatementNetIncomeSection} + */ + private netIncomeSectionMapper = ( + nodeSchema: ICashFlowSchemaSection + ): ICashFlowStatementNetIncomeSection => { + const netIncome = this.getAccountsNetIncome(); + + const node = { + id: nodeSchema.id, + label: this.i18n.__(nodeSchema.label), + total: this.getAmountMeta(netIncome), + sectionType: ICashFlowStatementSectionType.NET_INCOME, + }; + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocPeriodsToNetIncomeNode + ) + )(node); + }; + + // -------------------------------------------- + // # ACCOUNT NODE + // -------------------------------------------- + /** + * Retrieve account meta. + * @param {ICashFlowSchemaAccountRelation} relation - Account relation. + * @param {IAccount} account - + * @returns {ICashFlowStatementAccountMeta} + */ + private accountMetaMapper = ( + relation: ICashFlowSchemaAccountRelation, + account: ModelObject + ): ICashFlowStatementAccountMeta => { + // Retrieve the closing balance of the given account. + const getClosingBalance = (id) => + this.ledger.whereAccountId(id).getClosingBalance(); + + const closingBalance = R.compose( + // Multiplies the amount by -1 in case the relation in mines. + R.curry(this.amountAdjustment)(relation.direction) + )(getClosingBalance(account.id)); + + const node = { + id: account.id, + code: account.code, + label: account.name, + accountType: account.accountType, + adjustmentType: relation.direction, + total: this.getAmountMeta(closingBalance), + sectionType: ICashFlowStatementSectionType.ACCOUNT, + }; + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocPeriodsToAccountNode + ) + )(node); + }; + + /** + * Retrieve accounts sections by the given schema relation. + * @param {ICashFlowSchemaAccountRelation} relation + * @returns {ICashFlowStatementAccountMeta[]} + */ + private getAccountsBySchemaRelation = ( + relation: ICashFlowSchemaAccountRelation + ): ICashFlowStatementAccountMeta[] => { + const accounts = defaultTo(this.accountByTypeMap.get(relation.type), []); + const accountMetaMapper = R.curry(this.accountMetaMapper)(relation); + return R.map(accountMetaMapper)(accounts); + }; + + /** + * Retrieve the accounts meta. + * @param {string[]} types + * @returns {ICashFlowStatementAccountMeta[]} + */ + private getAccountsBySchemaRelations = ( + relations: ICashFlowSchemaAccountRelation[] + ): ICashFlowStatementAccountMeta[] => { + return R.pipe( + R.append(R.map(this.getAccountsBySchemaRelation)(relations)), + R.flatten + )([]); + }; + + /** + * Calculates the accounts total + * @param {ICashFlowStatementAccountMeta[]} accounts + * @returns {number} + */ + private getAccountsMetaTotal = ( + accounts: ICashFlowStatementAccountMeta[] + ): number => { + return sumBy(accounts, 'total.amount'); + }; + + /** + * Retrieve the accounts section from the section schema. + * @param {ICashFlowSchemaSectionAccounts} sectionSchema + * @returns {ICashFlowStatementAccountSection} + */ + private accountsSectionParser = ( + sectionSchema: ICashFlowSchemaSectionAccounts + ): ICashFlowStatementAccountSection => { + const { accountsRelations } = sectionSchema; + + const accounts = this.getAccountsBySchemaRelations(accountsRelations); + const accountsTotal = this.getAccountsMetaTotal(accounts); + const total = this.getTotalAmountMeta(accountsTotal); + + const node = { + sectionType: ICashFlowStatementSectionType.ACCOUNTS, + id: sectionSchema.id, + label: this.i18n.__(sectionSchema.label), + footerLabel: this.i18n.__(sectionSchema.footerLabel), + children: accounts, + total, + }; + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocPeriodsToAggregateNode + ) + )(node); + }; + + /** + * Detarmines the schema section type. + * @param {string} type + * @param {ICashFlowSchemaSection} section + * @returns {boolean} + */ + private isSchemaSectionType = R.curry( + (type: string, section: ICashFlowSchemaSection): boolean => { + return type === section.sectionType; + } + ); + + // -------------------------------------------- + // # AGGREGATE NODE + // -------------------------------------------- + /** + * Aggregate schema node parser to aggregate report node. + * @param {ICashFlowSchemaSection} schemaSection + * @returns {ICashFlowStatementAggregateSection} + */ + private regularSectionParser = R.curry( + ( + children, + schemaSection: ICashFlowSchemaSection + ): ICashFlowStatementAggregateSection => { + const node = { + id: schemaSection.id, + label: this.i18n.__(schemaSection.label), + footerLabel: this.i18n.__(schemaSection.footerLabel), + sectionType: ICashFlowStatementSectionType.AGGREGATE, + children, + }; + return R.compose( + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.AGGREGATE), + this.assocRegularSectionTotal + ), + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.AGGREGATE), + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocPeriodsToAggregateNode + ) + ) + )(node); + } + ); + + private transformSectionsToMap = (sections: ICashFlowSchemaSection[]) => { + return this.reduceNodesDeep( + sections, + (acc, section) => { + if (section.id) { + acc[`${section.id}`] = section; + } + return acc; + }, + {} + ); + }; + + // -------------------------------------------- + // # TOTAL EQUATION NODE + // -------------------------------------------- + + private sectionsMapToTotal = (mappedSections: { [key: number]: any }) => { + return mapValues(mappedSections, (node) => get(node, 'total.amount') || 0); + }; + + /** + * Evauluate equaation string with the given scope table. + * @param {string} equation - + * @param {{ [key: string]: number }} scope - + * @return {number} + */ + private evaluateEquation = ( + equation: string, + scope: { [key: string | number]: number } + ): number => { + return mathjs.evaluate(equation, scope); + }; + + /** + * Retrieve the total section from the eqauation parser. + * @param {ICashFlowSchemaTotalSection} sectionSchema + * @param {ICashFlowSchemaSection[]} accumulatedSections + * @returns {ICashFlowStatementTotalSection} + */ + private totalEquationSectionParser = ( + accumulatedSections: ICashFlowSchemaSection[], + sectionSchema: ICashFlowSchemaTotalSection + ): ICashFlowStatementTotalSection => { + const mappedSectionsById = this.transformSectionsToMap(accumulatedSections); + const nodesTotalById = this.sectionsMapToTotal(mappedSectionsById); + + const total = this.evaluateEquation(sectionSchema.equation, nodesTotalById); + + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + R.curry(this.assocTotalEquationDatePeriods)( + mappedSectionsById, + sectionSchema.equation + ) + ) + )({ + sectionType: ICashFlowStatementSectionType.TOTAL, + id: sectionSchema.id, + label: this.i18n.__(sectionSchema.label), + total: this.getTotalAmountMeta(total), + }); + }; + + /** + * Retrieve the beginning cash from date. + * @param {Date|string} fromDate - + * @return {Date} + */ + private beginningCashFrom = (fromDate: string | Date): Date => { + return moment(fromDate).subtract(1, 'days').toDate(); + }; + + /** + * Retrieve account meta. + * @param {ICashFlowSchemaAccountRelation} relation + * @param {IAccount} account + * @returns {ICashFlowStatementAccountMeta} + */ + private cashAccountMetaMapper = ( + relation: ICashFlowSchemaAccountRelation, + account: ModelObject + ): ICashFlowStatementAccountMeta => { + const cashToDate = this.beginningCashFrom(this.query.fromDate); + + const closingBalance = this.cashLedger + .whereToDate(cashToDate) + .whereAccountId(account.id) + .getClosingBalance(); + + const node = { + id: account.id, + code: account.code, + label: account.name, + accountType: account.accountType, + adjustmentType: relation.direction, + total: this.getAmountMeta(closingBalance), + sectionType: ICashFlowStatementSectionType.ACCOUNT, + }; + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocCashAtBeginningAccountDatePeriods + ) + )(node); + }; + + /** + * Retrieve accounts sections by the given schema relation. + * @param {ICashFlowSchemaAccountRelation} relation + * @returns {ICashFlowStatementAccountMeta[]} + */ + private getCashAccountsBySchemaRelation = ( + relation: ICashFlowSchemaAccountRelation + ): ICashFlowStatementAccountMeta[] => { + const accounts = this.accountByTypeMap.get(relation.type) || []; + const accountMetaMapper = R.curry(this.cashAccountMetaMapper)(relation); + return accounts.map(accountMetaMapper); + }; + + /** + * Retrieve the accounts meta. + * @param {string[]} types + * @returns {ICashFlowStatementAccountMeta[]} + */ + private getCashAccountsBySchemaRelations = ( + relations: ICashFlowSchemaAccountRelation[] + ): ICashFlowStatementAccountMeta[] => { + return R.concat(...R.map(this.getCashAccountsBySchemaRelation)(relations)); + }; + + /** + * Parses the cash at beginning section. + * @param {ICashFlowSchemaTotalSection} sectionSchema - + * @return {ICashFlowCashBeginningNode} + */ + private cashAtBeginningSectionParser = ( + nodeSchema: ICashFlowSchemaSection + ): ICashFlowCashBeginningNode => { + const { accountsRelations } = nodeSchema; + const children = this.getCashAccountsBySchemaRelations(accountsRelations); + const total = this.getAccountsMetaTotal(children); + + const node = { + sectionType: ICashFlowStatementSectionType.CASH_AT_BEGINNING, + id: nodeSchema.id, + label: this.i18n.__(nodeSchema.label), + children, + total: this.getTotalAmountMeta(total), + }; + return R.compose( + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + this.assocCashAtBeginningDatePeriods + ) + )(node); + }; + + /** + * Parses the schema section. + * @param {ICashFlowSchemaSection} schemaNode + * @returns {ICashFlowSchemaSection} + */ + private schemaSectionParser = ( + schemaNode: ICashFlowSchemaSection, + children + ): ICashFlowSchemaSection | ICashFlowStatementSection => { + return R.compose( + // Accounts node. + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.ACCOUNTS), + this.accountsSectionParser + ), + // Net income node. + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.NET_INCOME), + this.netIncomeSectionMapper + ), + // Cash at beginning node. + R.when( + this.isSchemaSectionType( + ICashFlowStatementSectionType.CASH_AT_BEGINNING + ), + this.cashAtBeginningSectionParser + ), + // Aggregate node. (that has no section type). + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.AGGREGATE), + this.regularSectionParser(children) + ) + )(schemaNode); + }; + + /** + * Parses the schema section. + * @param {ICashFlowSchemaSection | ICashFlowStatementSection} section + * @param {number} key + * @param {ICashFlowSchemaSection[]} parentValue + * @param {(ICashFlowSchemaSection | ICashFlowStatementSection)[]} accumulatedSections + * @returns {ICashFlowSchemaSection} + */ + private schemaSectionTotalParser = ( + section: ICashFlowSchemaSection | ICashFlowStatementSection, + key: number, + parentValue: ICashFlowSchemaSection[], + context, + accumulatedSections: (ICashFlowSchemaSection | ICashFlowStatementSection)[] + ): ICashFlowSchemaSection | ICashFlowStatementSection => { + return R.compose( + // Total equation section. + R.when( + this.isSchemaSectionType(ICashFlowStatementSectionType.TOTAL), + R.curry(this.totalEquationSectionParser)(accumulatedSections) + ) + )(section); + }; + + /** + * Schema sections parser. + * @param {ICashFlowSchemaSection[]}schema + * @returns {ICashFlowStatementSection[]} + */ + private schemaSectionsParser = ( + schema: ICashFlowSchemaSection[] + ): ICashFlowStatementSection[] => { + return this.mapNodesDeepReverse(schema, this.schemaSectionParser); + }; + + /** + * Writes the `total` property to the aggregate node. + * @param {ICashFlowStatementSection} section + * @return {ICashFlowStatementSection} + */ + private assocRegularSectionTotal = (section: ICashFlowStatementSection) => { + const total = this.getAccountsMetaTotal(section.children); + return R.assoc('total', this.getTotalAmountMeta(total), section); + }; + + /** + * Parses total schema nodes. + * @param {(ICashFlowSchemaSection | ICashFlowStatementSection)[]} sections + * @returns {(ICashFlowSchemaSection | ICashFlowStatementSection)[]} + */ + private totalSectionsParser = ( + sections: (ICashFlowSchemaSection | ICashFlowStatementSection)[] + ): (ICashFlowSchemaSection | ICashFlowStatementSection)[] => { + return this.reduceNodesDeep( + sections, + (acc, value, key, parentValue, context) => { + set( + acc, + context.path, + this.schemaSectionTotalParser(value, key, parentValue, context, acc) + ); + return acc; + }, + [] + ); + }; + + // -------------------------------------------- + // REPORT FILTERING + // -------------------------------------------- + /** + * Detarmines the given section has children and not empty. + * @param {ICashFlowStatementSection} section + * @returns {boolean} + */ + private isSectionHasChildren = ( + section: ICashFlowStatementSection + ): boolean => { + return !isEmpty(section.children); + }; + + /** + * Detarmines whether the section has no zero amount. + * @param {ICashFlowStatementSection} section + * @returns {boolean} + */ + private isSectionNoneZero = (section: ICashFlowStatementSection): boolean => { + return section.total.amount !== 0; + }; + + /** + * Detarmines whether the parent accounts sections has children. + * @param {ICashFlowStatementSection} section + * @returns {boolean} + */ + private isAccountsSectionHasChildren = ( + section: ICashFlowStatementSection[] + ): boolean => { + return R.ifElse( + this.isSchemaSectionType(ICashFlowStatementSectionType.ACCOUNTS), + this.isSectionHasChildren, + R.always(true) + )(section); + }; + + /** + * Detarmines the account section has no zero otherwise returns true. + * @param {ICashFlowStatementSection} section + * @returns {boolean} + */ + private isAccountLeafNoneZero = ( + section: ICashFlowStatementSection[] + ): boolean => { + return R.ifElse( + this.isSchemaSectionType(ICashFlowStatementSectionType.ACCOUNT), + this.isSectionNoneZero, + R.always(true) + )(section); + }; + + /** + * Deep filters the non-zero accounts leafs of the report sections. + * @param {ICashFlowStatementSection[]} sections + * @returns {ICashFlowStatementSection[]} + */ + private filterNoneZeroAccountsLeafs = ( + sections: ICashFlowStatementSection[] + ): ICashFlowStatementSection[] => { + return this.filterNodesDeep(sections, this.isAccountLeafNoneZero); + }; + + /** + * Deep filter the non-children sections of the report sections. + * @param {ICashFlowStatementSection[]} sections + * @returns {ICashFlowStatementSection[]} + */ + private filterNoneChildrenSections = ( + sections: ICashFlowStatementSection[] + ): ICashFlowStatementSection[] => { + return this.filterNodesDeep(sections, this.isAccountsSectionHasChildren); + }; + + /** + * Filters the report data. + * @param {ICashFlowStatementSection[]} sections + * @returns {ICashFlowStatementSection[]} + */ + private filterReportData = ( + sections: ICashFlowStatementSection[] + ): ICashFlowStatementSection[] => { + return R.compose( + this.filterNoneChildrenSections, + this.filterNoneZeroAccountsLeafs + )(sections); + }; + + /** + * Schema parser. + * @param {ICashFlowSchemaSection[]} schema + * @returns {ICashFlowSchemaSection[]} + */ + private schemaParser = ( + schema: ICashFlowSchemaSection[] + ): ICashFlowSchemaSection[] => { + return R.compose( + R.when( + R.always(this.query.noneTransactions || this.query.noneZero), + this.filterReportData + ), + this.totalSectionsParser, + this.schemaSectionsParser + )(schema); + }; + + /** + * Retrieve the cashflow statement data. + * @return {ICashFlowStatementData} + */ + public reportData = (): ICashFlowStatementData => { + return this.schemaParser(R.clone(CASH_FLOW_SCHEMA)); + }; +} diff --git a/temp/CashFlowStatement/CashFlowDatePeriods.ts b/temp/CashFlowStatement/CashFlowDatePeriods.ts new file mode 100644 index 000000000..a6986ab4c --- /dev/null +++ b/temp/CashFlowStatement/CashFlowDatePeriods.ts @@ -0,0 +1,412 @@ +import * as R from 'ramda'; +import { sumBy, mapValues, get } from 'lodash'; +import { ACCOUNT_ROOT_TYPE } from '@/constants/accounts'; +import { + ICashFlowDatePeriod, + ICashFlowStatementNetIncomeSection, + ICashFlowStatementAccountSection, + ICashFlowStatementSection, + ICashFlowSchemaTotalSection, + ICashFlowStatementTotalSection, + ICashFlowStatementQuery, + IDateRange, +} from './Cashflow.types'; +import { IFormatNumberSettings } from '../../types/Report.types'; +import { dateRangeFromToCollection } from '@/utils/date-range-collection'; +import { accumSum } from '@/utils/accum-sum'; + +export const CashFlowStatementDatePeriods = (Base) => + class extends Base { + dateRangeSet: IDateRange[]; + query: ICashFlowStatementQuery; + + /** + * Initialize date range set. + */ + public initDateRangeCollection() { + this.dateRangeSet = dateRangeFromToCollection( + this.query.fromDate, + this.query.toDate, + this.comparatorDateType + ); + } + + /** + * Retrieve the date period meta. + * @param {number} total - Total amount. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {ICashFlowDatePeriod} + */ + public getDatePeriodTotalMeta = ( + total: number, + fromDate: Date, + toDate: Date, + overrideSettings: IFormatNumberSettings = {} + ): ICashFlowDatePeriod => { + return this.getDatePeriodMeta(total, fromDate, toDate, { + money: true, + ...overrideSettings, + }); + }; + + /** + * Retrieve the date period meta. + * @param {number} total - Total amount. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {ICashFlowDatePeriod} + */ + public getDatePeriodMeta = ( + total: number, + fromDate: Date, + toDate: Date, + overrideSettings?: IFormatNumberSettings + ): ICashFlowDatePeriod => { + return { + fromDate: this.getDateMeta(fromDate), + toDate: this.getDateMeta(toDate), + total: this.getAmountMeta(total, overrideSettings), + }; + }; + + // Net income -------------------- + /** + * Retrieve the net income between the given date range. + * @param {Date} fromDate + * @param {Date} toDate + * @returns {number} + */ + public getNetIncomeDateRange = (fromDate: Date, toDate: Date) => { + // Mapping income/expense accounts ids. + const incomeAccountsIds = this.getAccountsIdsByType( + ACCOUNT_ROOT_TYPE.INCOME + ); + const expenseAccountsIds = this.getAccountsIdsByType( + ACCOUNT_ROOT_TYPE.EXPENSE + ); + // Income closing balance. + const incomeClosingBalance = accumSum(incomeAccountsIds, (id) => + this.netIncomeLedger + .whereFromDate(fromDate) + .whereToDate(toDate) + .whereAccountId(id) + .getClosingBalance() + ); + // Expense closing balance. + const expenseClosingBalance = accumSum(expenseAccountsIds, (id) => + this.netIncomeLedger + .whereToDate(toDate) + .whereFromDate(fromDate) + .whereAccountId(id) + .getClosingBalance() + ); + // Net income = income - expenses. + const netIncome = incomeClosingBalance - expenseClosingBalance; + + return netIncome; + }; + + /** + * Retrieve the net income of date period. + * @param {IDateRange} dateRange - + * @retrun {ICashFlowDatePeriod} + */ + public getNetIncomeDatePeriod = (dateRange): ICashFlowDatePeriod => { + const total = this.getNetIncomeDateRange( + dateRange.fromDate, + dateRange.toDate + ); + return this.getDatePeriodMeta( + total, + dateRange.fromDate, + dateRange.toDate + ); + }; + + /** + * Retrieve the net income node between the given date ranges. + * @param {Date} fromDate + * @param {Date} toDate + * @returns {ICashFlowDatePeriod[]} + */ + public getNetIncomeDatePeriods = ( + section: ICashFlowStatementNetIncomeSection + ): ICashFlowDatePeriod[] => { + return this.dateRangeSet.map(this.getNetIncomeDatePeriod.bind(this)); + }; + + /** + * Writes periods property to net income section. + * @param {ICashFlowStatementNetIncomeSection} section + * @returns {ICashFlowStatementNetIncomeSection} + */ + public assocPeriodsToNetIncomeNode = ( + section: ICashFlowStatementNetIncomeSection + ): ICashFlowStatementNetIncomeSection => { + const incomeDatePeriods = this.getNetIncomeDatePeriods(section); + return R.assoc('periods', incomeDatePeriods, section); + }; + + // Account nodes -------------------- + /** + * Retrieve the account total between date range. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {number} + */ + public getAccountTotalDateRange = ( + node: ICashFlowStatementAccountSection, + fromDate: Date, + toDate: Date + ): number => { + const closingBalance = this.ledger + .whereFromDate(fromDate) + .whereToDate(toDate) + .whereAccountId(node.id) + .getClosingBalance(); + + return this.amountAdjustment(node.adjustmentType, closingBalance); + }; + + /** + * Retrieve the given account node total date period. + * @param {ICashFlowStatementAccountSection} node - + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {ICashFlowDatePeriod} + */ + public getAccountTotalDatePeriod = ( + node: ICashFlowStatementAccountSection, + fromDate: Date, + toDate: Date + ): ICashFlowDatePeriod => { + const total = this.getAccountTotalDateRange(node, fromDate, toDate); + return this.getDatePeriodMeta(total, fromDate, toDate); + }; + + /** + * Retrieve the accounts date periods nodes of the give account node. + * @param {ICashFlowStatementAccountSection} node - + * @return {ICashFlowDatePeriod[]} + */ + public getAccountDatePeriods = ( + node: ICashFlowStatementAccountSection + ): ICashFlowDatePeriod[] => { + return this.getNodeDatePeriods( + node, + this.getAccountTotalDatePeriod.bind(this) + ); + } + + /** + * Writes `periods` property to account node. + * @param {ICashFlowStatementAccountSection} node - + * @return {ICashFlowStatementAccountSection} + */ + public assocPeriodsToAccountNode = ( + node: ICashFlowStatementAccountSection + ): ICashFlowStatementAccountSection => { + const datePeriods = this.getAccountDatePeriods(node); + return R.assoc('periods', datePeriods, node); + } + + // Aggregate node ------------------------- + /** + * Retrieve total of the given period index for node that has children nodes. + * @return {number} + */ + public getChildrenTotalPeriodByIndex = ( + node: ICashFlowStatementSection, + index: number + ): number => { + return sumBy(node.children, `periods[${index}].total.amount`); + } + + /** + * Retrieve date period meta of the given node index. + * @param {ICashFlowStatementSection} node - + * @param {number} index - Loop index. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + */ + public getChildrenTotalPeriodMetaByIndex( + node: ICashFlowStatementSection, + index: number, + fromDate: Date, + toDate: Date + ) { + const total = this.getChildrenTotalPeriodByIndex(node, index); + return this.getDatePeriodTotalMeta(total, fromDate, toDate); + } + + /** + * Retrieve the date periods of aggregate node. + * @param {ICashFlowStatementSection} node + */ + public getAggregateNodeDatePeriods(node: ICashFlowStatementSection) { + const getChildrenTotalPeriodMetaByIndex = R.curry( + this.getChildrenTotalPeriodMetaByIndex.bind(this) + )(node); + + return this.dateRangeSet.map((dateRange, index) => + getChildrenTotalPeriodMetaByIndex( + index, + dateRange.fromDate, + dateRange.toDate + ) + ); + } + + /** + * Writes `periods` property to aggregate section node. + * @param {ICashFlowStatementSection} node - + * @return {ICashFlowStatementSection} + */ + public assocPeriodsToAggregateNode = ( + node: ICashFlowStatementSection + ): ICashFlowStatementSection => { + const datePeriods = this.getAggregateNodeDatePeriods(node); + return R.assoc('periods', datePeriods, node); + }; + + // Total equation node -------------------- + + public sectionsMapToTotalPeriod = ( + mappedSections: { [key: number]: any }, + index + ) => { + return mapValues( + mappedSections, + (node) => get(node, `periods[${index}].total.amount`) || 0 + ); + }; + + /** + * Retrieve the date periods of the given total equation. + * @param {ICashFlowSchemaTotalSection} + * @param {string} equation - + * @return {ICashFlowDatePeriod[]} + */ + public getTotalEquationDatePeriods = ( + node: ICashFlowSchemaTotalSection, + equation: string, + nodesTable + ): ICashFlowDatePeriod[] => { + return this.getNodeDatePeriods(node, (node, fromDate, toDate, index) => { + const periodScope = this.sectionsMapToTotalPeriod(nodesTable, index); + const total = this.evaluateEquation(equation, periodScope); + + return this.getDatePeriodTotalMeta(total, fromDate, toDate); + }); + }; + + /** + * Associates the total periods of total equation to the ginve total node.. + * @param {ICashFlowSchemaTotalSection} totalSection - + * @return {ICashFlowStatementTotalSection} + */ + public assocTotalEquationDatePeriods = ( + nodesTable: any, + equation: string, + node: ICashFlowSchemaTotalSection + ): ICashFlowStatementTotalSection => { + const datePeriods = this.getTotalEquationDatePeriods( + node, + equation, + nodesTable + ); + + return R.assoc('periods', datePeriods, node); + }; + + // Cash at beginning ---------------------- + + /** + * Retrieve the date preioods of the given node and accumulated function. + * @param {} node + * @param {} + * @return {} + */ + public getNodeDatePeriods = (node, callback) => { + const curriedCallback = R.curry(callback)(node); + + return this.dateRangeSet.map((dateRange, index) => { + return curriedCallback(dateRange.fromDate, dateRange.toDate, index); + }); + }; + + /** + * Retrieve the account total between date range. + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {number} + */ + public getBeginningCashAccountDateRange = ( + node: ICashFlowStatementSection, + fromDate: Date, + toDate: Date + ) => { + const cashToDate = this.beginningCashFrom(fromDate); + + return this.cashLedger + .whereToDate(cashToDate) + .whereAccountId(node.id) + .getClosingBalance(); + }; + + /** + * Retrieve the beginning cash date period. + * @param {ICashFlowStatementSection} node - + * @param {Date} fromDate - From date. + * @param {Date} toDate - To date. + * @return {ICashFlowDatePeriod} + */ + public getBeginningCashDatePeriod = ( + node: ICashFlowStatementSection, + fromDate: Date, + toDate: Date + ) => { + const total = this.getBeginningCashAccountDateRange( + node, + fromDate, + toDate + ); + return this.getDatePeriodTotalMeta(total, fromDate, toDate); + }; + + /** + * Retrieve the beginning cash account periods. + * @param {ICashFlowStatementSection} node + * @return {ICashFlowDatePeriod} + */ + public getBeginningCashAccountPeriods = ( + node: ICashFlowStatementSection + ): ICashFlowDatePeriod => { + return this.getNodeDatePeriods(node, this.getBeginningCashDatePeriod); + }; + + /** + * Writes `periods` property to cash at beginning date periods. + * @param {ICashFlowStatementSection} section - + * @return {ICashFlowStatementSection} + */ + public assocCashAtBeginningDatePeriods = ( + node: ICashFlowStatementSection + ): ICashFlowStatementSection => { + const datePeriods = this.getAggregateNodeDatePeriods(node); + return R.assoc('periods', datePeriods, node); + }; + + /** + * Associates `periods` propery to cash at beginning account node. + * @param {ICashFlowStatementSection} node - + * @return {ICashFlowStatementSection} + */ + public assocCashAtBeginningAccountDatePeriods = ( + node: ICashFlowStatementSection + ): ICashFlowStatementSection => { + const datePeriods = this.getBeginningCashAccountPeriods(node); + return R.assoc('periods', datePeriods, node); + }; + }; diff --git a/temp/CashFlowStatement/CashFlowRepository.ts b/temp/CashFlowStatement/CashFlowRepository.ts new file mode 100644 index 000000000..87661dfe6 --- /dev/null +++ b/temp/CashFlowStatement/CashFlowRepository.ts @@ -0,0 +1,163 @@ +import { Inject, Injectable } from '@nestjs/common'; +import moment from 'moment'; +import { Knex } from 'knex'; +import { isEmpty } from 'lodash'; +import { ICashFlowStatementQuery } from './Cashflow.types'; +import { Account } from '@/modules/Accounts/models/Account.model'; +import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction.model'; +import { ModelObject } from 'objection'; + +@Injectable() +export class CashFlowRepository { + constructor( + @Inject(Account.name) + private readonly accountModel: typeof Account, + + @Inject(AccountTransaction.name) + private readonly accountTransactionModel: typeof AccountTransaction, + ) {} + + /** + * Retrieve the group type from periods type. + * @param {string} displayType + * @returns {string} + */ + protected getGroupTypeFromPeriodsType(displayType: string) { + const displayTypes = { + year: 'year', + day: 'day', + month: 'month', + quarter: 'month', + week: 'day', + }; + return displayTypes[displayType] || 'month'; + } + + /** + * Retrieve the cashflow accounts. + * @returns {Promise} + */ + public async cashFlowAccounts(): Promise { + const accounts = await this.accountModel.query(); + return accounts; + } + + /** + * Retrieve total of csah at beginning transactions. + * @param {ICashFlowStatementQuery} filter - + * @return {Promise} + */ + public async cashAtBeginningTotalTransactions( + filter: ICashFlowStatementQuery, + ): Promise[]> { + const cashBeginningPeriod = moment(filter.fromDate) + .subtract(1, 'day') + .toDate(); + + const transactions = await this.accountTransactionModel + .query() + .onBuild((query) => { + query.modify('creditDebitSummation'); + + query.select('accountId'); + query.groupBy('accountId'); + + query.withGraphFetched('account'); + query.modify('filterDateRange', null, cashBeginningPeriod); + + this.commonFilterBranchesQuery(filter, query); + }); + return transactions; + } + + /** + * Retrieve accounts transactions. + * @param {ICashFlowStatementQuery} filter + * @return {Promise} + */ + public async getAccountsTransactions( + filter: ICashFlowStatementQuery, + ): Promise[]> { + const groupByDateType = this.getGroupTypeFromPeriodsType( + filter.displayColumnsBy, + ); + return await this.accountTransactionModel.query().onBuild((query) => { + query.modify('creditDebitSummation'); + query.modify('groupByDateFormat', groupByDateType); + + query.select('accountId'); + + query.groupBy('accountId'); + query.withGraphFetched('account'); + + query.modify('filterDateRange', filter.fromDate, filter.toDate); + + this.commonFilterBranchesQuery(filter, query); + }); + } + + /** + * Retrieve the net income tranasctions. + * @param {number} tenantId - + * @param {ICashFlowStatementQuery} query - + * @return {Promise} + */ + public async getNetIncomeTransactions( + filter: ICashFlowStatementQuery, + ): Promise { + const groupByDateType = this.getGroupTypeFromPeriodsType( + filter.displayColumnsBy, + ); + return await this.accountTransactionModel.query().onBuild((query) => { + query.modify('creditDebitSummation'); + query.modify('groupByDateFormat', groupByDateType); + + query.select('accountId'); + query.groupBy('accountId'); + + query.withGraphFetched('account'); + query.modify('filterDateRange', filter.fromDate, filter.toDate); + + this.commonFilterBranchesQuery(filter, query); + }); + } + + /** + * Retrieve peridos of cash at beginning transactions. + * @param {ICashFlowStatementQuery} filter - + * @return {Promise[]>} + */ + public async cashAtBeginningPeriodTransactions( + filter: ICashFlowStatementQuery, + ): Promise[]> { + const groupByDateType = this.getGroupTypeFromPeriodsType( + filter.displayColumnsBy, + ); + + return await this.accountTransactionModel.query().onBuild((query) => { + query.modify('creditDebitSummation'); + query.modify('groupByDateFormat', groupByDateType); + + query.select('accountId'); + query.groupBy('accountId'); + + query.withGraphFetched('account'); + query.modify('filterDateRange', filter.fromDate, filter.toDate); + + this.commonFilterBranchesQuery(filter, query); + }); + } + + /** + * Common branches filter query. + * @param {Knex.QueryBuilder} query + */ + private commonFilterBranchesQuery = ( + query: ICashFlowStatementQuery, + knexQuery: Knex.QueryBuilder, + ) => { + if (!isEmpty(query.branchesIds)) { + knexQuery.modify('filterByBranches', query.branchesIds); + } + }; +} diff --git a/temp/CashFlowStatement/CashFlowService.ts b/temp/CashFlowStatement/CashFlowService.ts new file mode 100644 index 000000000..4dc334330 --- /dev/null +++ b/temp/CashFlowStatement/CashFlowService.ts @@ -0,0 +1,109 @@ +import { ModelObject } from 'objection'; +import moment from 'moment'; +import * as R from 'ramda'; +import { + ICashFlowStatementQuery, + ICashFlowStatementDOO, +} from './Cashflow.types'; +import CashFlowStatement from './CashFlow'; +import { CashflowSheetMeta } from './CashflowSheetMeta'; +import { Injectable } from '@nestjs/common'; +import { CashFlowRepository } from './CashFlowRepository'; +import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; +import { Ledger } from '@/modules/Ledger/Ledger'; +import { AccountTransaction } from '@/modules/Accounts/models/AccountTransaction.model'; +import { I18nService } from 'nestjs-i18n'; +import { getDefaultCashflowQuery } from './constants'; + +@Injectable() +export class CashFlowStatementService { + /** + * @param {CashFlowRepository} cashFlowRepo - Cash flow repository. + * @param {CashflowSheetMeta} cashflowSheetMeta - Cashflow sheet meta. + * @param {TenancyContext} tenancyContext - Tenancy context. + */ + constructor( + private readonly cashFlowRepo: CashFlowRepository, + private readonly cashflowSheetMeta: CashflowSheetMeta, + private readonly tenancyContext: TenancyContext, + private readonly i18n: I18nService, + ) {} + + /** + * Retrieves cash at beginning transactions. + * @param {ICashFlowStatementQuery} filter - Cash flow statement query. + * @returns {Promise[]>} + */ + private async cashAtBeginningTransactions( + filter: ICashFlowStatementQuery, + ): Promise[]> { + const appendPeriodsOperToChain = (trans) => + R.append( + this.cashFlowRepo.cashAtBeginningPeriodTransactions(filter), + trans, + ); + + const promisesChain = R.pipe( + R.append(this.cashFlowRepo.cashAtBeginningTotalTransactions(filter)), + R.when( + R.always(R.equals(filter.displayColumnsType, 'date_periods')), + appendPeriodsOperToChain, + ), + )([]); + const promisesResults = await Promise.all(promisesChain); + const transactions = R.flatten(promisesResults); + + return transactions; + } + + /** + * Retrieve the cash flow sheet statement. + * @param {number} tenantId + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async cashFlow( + query: ICashFlowStatementQuery, + ): Promise { + // Retrieve all accounts on the storage. + const accounts = await this.cashFlowRepo.cashFlowAccounts(); + const tenant = await this.tenancyContext.getTenant(); + + const filter = { + ...getDefaultCashflowQuery(), + ...query, + }; + // Retrieve the accounts transactions. + const transactions = + await this.cashFlowRepo.getAccountsTransactions(filter); + // Retrieve the net income transactions. + const netIncome = await this.cashFlowRepo.getNetIncomeTransactions(filter); + // Retrieve the cash at beginning transactions. + const cashAtBeginningTransactions = + await this.cashAtBeginningTransactions(filter); + + // Transformes the transactions to ledgers. + const ledger = Ledger.fromTransactions(transactions); + const cashLedger = Ledger.fromTransactions(cashAtBeginningTransactions); + const netIncomeLedger = Ledger.fromTransactions(netIncome); + + // Cash flow statement. + const cashFlowInstance = new CashFlowStatement( + accounts, + ledger, + cashLedger, + netIncomeLedger, + filter, + tenant.metadata.baseCurrency, + this.i18n, + ); + // Retrieve the cashflow sheet meta. + const meta = await this.cashflowSheetMeta.meta(filter); + + return { + data: cashFlowInstance.reportData(), + query: filter, + meta, + }; + } +} diff --git a/temp/CashFlowStatement/CashFlowTable.ts b/temp/CashFlowStatement/CashFlowTable.ts new file mode 100644 index 000000000..d54504254 --- /dev/null +++ b/temp/CashFlowStatement/CashFlowTable.ts @@ -0,0 +1,374 @@ +import * as R from 'ramda'; +import { isEmpty, } from 'lodash'; +import moment from 'moment'; +import { + ICashFlowStatementSection, + ICashFlowStatementSectionType, + IDateRange, + ICashFlowStatementDOO, +} from './Cashflow.types'; +import { ITableRow, ITableColumn } from '../../types/Table.types'; +import { dateRangeFromToCollection } from '@/utils/date-range-collection'; +import { tableRowMapper } from '../../utils/Table.utils'; +import { mapValuesDeep } from '@/utils/deepdash'; + +enum IROW_TYPE { + AGGREGATE = 'AGGREGATE', + NET_INCOME = 'NET_INCOME', + ACCOUNTS = 'ACCOUNTS', + ACCOUNT = 'ACCOUNT', + TOTAL = 'TOTAL', +} +const DEEP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; +const DISPLAY_COLUMNS_BY = { + DATE_PERIODS: 'date_periods', + TOTAL: 'total', +}; + +export class CashFlowTable { + private report: ICashFlowStatementDOO; + private i18n; + private dateRangeSet: IDateRange[]; + + /** + * Constructor method. + * @param {ICashFlowStatement} reportStatement + */ + constructor(reportStatement: ICashFlowStatementDOO, i18n) { + this.report = reportStatement; + this.i18n = i18n; + this.dateRangeSet = []; + this.initDateRangeCollection(); + } + + /** + * Initialize date range set. + */ + private initDateRangeCollection() { + this.dateRangeSet = dateRangeFromToCollection( + this.report.query.fromDate, + this.report.query.toDate, + this.report.query.displayColumnsBy, + ); + } + + /** + * Retrieve the date periods columns accessors. + */ + private datePeriodsColumnsAccessors = () => { + return this.dateRangeSet.map((dateRange: IDateRange, index) => ({ + key: `date-range-${index}`, + accessor: `periods[${index}].total.formattedAmount`, + })); + }; + + /** + * Retrieve the total column accessor. + */ + private totalColumnAccessor = () => { + return [{ key: 'total', accessor: 'total.formattedAmount' }]; + }; + + /** + * Retrieve the common columns for all report nodes. + */ + private commonColumns = () => { + return R.compose( + R.concat([{ key: 'name', accessor: 'label' }]), + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + R.concat(this.datePeriodsColumnsAccessors()), + ), + R.concat(this.totalColumnAccessor()), + )([]); + }; + + /** + * Retrieve the table rows of regular section. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow[]} + */ + private regularSectionMapper = ( + section: ICashFlowStatementSection, + ): ITableRow => { + const columns = this.commonColumns(); + + return tableRowMapper(section, columns, { + rowTypes: [IROW_TYPE.AGGREGATE], + id: section.id, + }); + }; + + /** + * Retrieve the net income table rows of the section. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow} + */ + private netIncomeSectionMapper = ( + section: ICashFlowStatementSection, + ): ITableRow => { + const columns = this.commonColumns(); + + return tableRowMapper(section, columns, { + rowTypes: [IROW_TYPE.NET_INCOME, IROW_TYPE.TOTAL], + id: section.id, + }); + }; + + /** + * Retrieve the accounts table rows of the section. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow} + */ + private accountsSectionMapper = ( + section: ICashFlowStatementSection, + ): ITableRow => { + const columns = this.commonColumns(); + + return tableRowMapper(section, columns, { + rowTypes: [IROW_TYPE.ACCOUNTS], + id: section.id, + }); + }; + + /** + * Retrieve the account table row of account section. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow} + */ + private accountSectionMapper = ( + section: ICashFlowStatementSection, + ): ITableRow => { + const columns = this.commonColumns(); + + return tableRowMapper(section, columns, { + rowTypes: [IROW_TYPE.ACCOUNT], + id: `account-${section.id}`, + }); + }; + + /** + * Retrieve the total table rows from the given total section. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow} + */ + private totalSectionMapper = ( + section: ICashFlowStatementSection, + ): ITableRow => { + const columns = this.commonColumns(); + + return tableRowMapper(section, columns, { + rowTypes: [IROW_TYPE.TOTAL], + id: section.id, + }); + }; + + /** + * Detarmines the schema section type. + * @param {string} type + * @param {ICashFlowSchemaSection} section + * @returns {boolean} + */ + private isSectionHasType = ( + type: string, + section: ICashFlowStatementSection, + ): boolean => { + return type === section.sectionType; + }; + + /** + * The report section mapper. + * @param {ICashFlowStatementSection} section + * @returns {ITableRow} + */ + private sectionMapper = ( + section: ICashFlowStatementSection, + key: string, + parentSection: ICashFlowStatementSection, + ): ITableRow => { + const isSectionHasType = R.curry(this.isSectionHasType); + + return R.pipe( + R.when( + isSectionHasType(ICashFlowStatementSectionType.AGGREGATE), + this.regularSectionMapper, + ), + R.when( + isSectionHasType(ICashFlowStatementSectionType.CASH_AT_BEGINNING), + this.regularSectionMapper, + ), + R.when( + isSectionHasType(ICashFlowStatementSectionType.NET_INCOME), + this.netIncomeSectionMapper, + ), + R.when( + isSectionHasType(ICashFlowStatementSectionType.ACCOUNTS), + this.accountsSectionMapper, + ), + R.when( + isSectionHasType(ICashFlowStatementSectionType.ACCOUNT), + this.accountSectionMapper, + ), + R.when( + isSectionHasType(ICashFlowStatementSectionType.TOTAL), + this.totalSectionMapper, + ), + )(section); + }; + + /** + * Mappes the sections to the table rows. + * @param {ICashFlowStatementSection[]} sections + * @returns {ITableRow[]} + */ + private mapSectionsToTableRows = ( + sections: ICashFlowStatementSection[], + ): ITableRow[] => { + return mapValuesDeep(sections, this.sectionMapper.bind(this), DEEP_CONFIG); + }; + + /** + * Appends the total to section's children. + * @param {ICashFlowStatementSection} section + * @returns {ICashFlowStatementSection} + */ + private appendTotalToSectionChildren = ( + section: ICashFlowStatementSection, + ): ICashFlowStatementSection => { + const label = section.footerLabel + ? section.footerLabel + : this.i18n.__('Total {{accountName}}', { accountName: section.label }); + + section.children.push({ + sectionType: ICashFlowStatementSectionType.TOTAL, + label, + periods: section.periods, + total: section.total, + }); + return section; + }; + + /** + * + * @param {ICashFlowStatementSection} section + * @returns {ICashFlowStatementSection} + */ + private mapSectionsToAppendTotalChildren = ( + section: ICashFlowStatementSection, + ): ICashFlowStatementSection => { + const isSectionHasChildren = (section) => !isEmpty(section.children); + + return R.compose( + R.when( + isSectionHasChildren, + this.appendTotalToSectionChildren.bind(this), + ), + )(section); + }; + + /** + * Appends total node to children section. + * @param {ICashFlowStatementSection[]} sections + * @returns {ICashFlowStatementSection[]} + */ + private appendTotalToChildren = (sections: ICashFlowStatementSection[]) => { + return mapValuesDeep( + sections, + this.mapSectionsToAppendTotalChildren.bind(this), + DEEP_CONFIG, + ); + }; + + /** + * Retrieve the table rows of cash flow statement. + * @param {ICashFlowStatementSection[]} sections + * @returns {ITableRow[]} + */ + public tableRows = (): ITableRow[] => { + const sections = this.report.data; + + return R.pipe( + this.appendTotalToChildren, + this.mapSectionsToTableRows, + )(sections); + }; + + /** + * Retrieve the total columns. + * @returns {ITableColumn} + */ + private totalColumns = (): ITableColumn[] => { + return [{ key: 'total', label: this.i18n.__('Total') }]; + }; + + /** + * Retrieve the formatted column label from the given date range. + * @param {ICashFlowDateRange} dateRange - + * @return {string} + */ + private formatColumnLabel = (dateRange: ICashFlowDateRange) => { + const monthFormat = (range) => moment(range.toDate).format('YYYY-MM'); + const yearFormat = (range) => moment(range.toDate).format('YYYY'); + const dayFormat = (range) => moment(range.toDate).format('YYYY-MM-DD'); + + const conditions = [ + ['month', monthFormat], + ['year', yearFormat], + ['day', dayFormat], + ['quarter', monthFormat], + ['week', dayFormat], + ]; + const conditionsPairs = R.map( + ([type, formatFn]) => [ + R.always(this.isDisplayColumnsType(type)), + formatFn, + ], + conditions, + ); + + return R.compose(R.cond(conditionsPairs))(dateRange); + }; + + /** + * Date periods columns. + * @returns {ITableColumn[]} + */ + private datePeriodsColumns = (): ITableColumn[] => { + return this.dateRangeSet.map((dateRange, index) => ({ + key: `date-range-${index}`, + label: this.formatColumnLabel(dateRange), + })); + }; + + /** + * Detarmines the given column type is the current. + * @reutrns {boolean} + */ + private isDisplayColumnsBy = (displayColumnsType: string): Boolean => { + return this.report.query.displayColumnsType === displayColumnsType; + }; + + /** + * Detarmines whether the given display columns type is the current. + * @param {string} displayColumnsBy + * @returns {boolean} + */ + private isDisplayColumnsType = (displayColumnsBy: string): Boolean => { + return this.report.query.displayColumnsBy === displayColumnsBy; + }; + + /** + * Retrieve the table columns. + * @return {ITableColumn[]} + */ + public tableColumns = (): ITableColumn[] => { + return R.compose( + R.concat([{ key: 'name', label: this.i18n.__('Account name') }]), + R.when( + R.always(this.isDisplayColumnsBy(DISPLAY_COLUMNS_BY.DATE_PERIODS)), + R.concat(this.datePeriodsColumns()), + ), + R.concat(this.totalColumns()), + )([]); + }; +} diff --git a/temp/CashFlowStatement/Cashflow.controller.ts b/temp/CashFlowStatement/Cashflow.controller.ts new file mode 100644 index 000000000..be0df3fc7 --- /dev/null +++ b/temp/CashFlowStatement/Cashflow.controller.ts @@ -0,0 +1,56 @@ +import { Response } from 'express'; +import { Controller, Get, Headers, Query, Res } from '@nestjs/common'; +import { ICashFlowStatementQuery } from './Cashflow.types'; +import { AcceptType } from '@/constants/accept-type'; +import { CashflowSheetApplication } from './CashflowSheetApplication'; + +@Controller('reports/cashflow') +export class CashflowController { + constructor(private readonly cashflowSheetApp: CashflowSheetApplication) {} + + @Get() + async getCashflow( + @Query() query: ICashFlowStatementQuery, + @Res() res: Response, + @Headers('accept') acceptHeader: string, + ) { + // Retrieves the json table format. + if (acceptHeader.includes(AcceptType.ApplicationJsonTable)) { + const table = await this.cashflowSheetApp.table(query); + + return res.status(200).send(table); + // Retrieves the csv format. + } else if (acceptHeader.includes(AcceptType.ApplicationCsv)) { + const buffer = await this.cashflowSheetApp.csv(query); + + res.setHeader('Content-Disposition', 'attachment; filename=output.csv'); + res.setHeader('Content-Type', 'text/csv'); + + return res.status(200).send(buffer); + // Retrieves the pdf format. + } else if (acceptHeader.includes(AcceptType.ApplicationXlsx)) { + const buffer = await this.cashflowSheetApp.xlsx(query); + + res.setHeader('Content-Disposition', 'attachment; filename=output.xlsx'); + res.setHeader( + 'Content-Type', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + ); + return res.send(buffer); + // Retrieves the pdf format. + } else if (acceptHeader.includes(AcceptType.ApplicationPdf)) { + const pdfContent = await this.cashflowSheetApp.pdf(query); + + res.set({ + 'Content-Type': 'application/pdf', + 'Content-Length': pdfContent.length, + }); + return res.send(pdfContent); + // Retrieves the json format. + } else { + const cashflow = await this.cashflowSheetApp.sheet(query); + + return res.status(200).send(cashflow); + } + } +} diff --git a/temp/CashFlowStatement/Cashflow.module.ts b/temp/CashFlowStatement/Cashflow.module.ts new file mode 100644 index 000000000..1646def94 --- /dev/null +++ b/temp/CashFlowStatement/Cashflow.module.ts @@ -0,0 +1,27 @@ +import { Module } from '@nestjs/common'; +import { CashflowSheetMeta } from './CashflowSheetMeta'; +import { CashFlowRepository } from './CashFlowRepository'; +import { CashflowTablePdfInjectable } from './CashflowTablePdfInjectable'; +import { CashflowExportInjectable } from './CashflowExportInjectable'; +import { CashflowController } from './Cashflow.controller'; +import { FinancialSheetCommonModule } from '../../common/FinancialSheetCommon.module'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { CashFlowStatementService } from './CashFlowService'; +import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; +import { CashflowSheetApplication } from './CashflowSheetApplication'; + +@Module({ + imports: [FinancialSheetCommonModule], + providers: [ + CashFlowRepository, + CashflowSheetMeta, + CashFlowStatementService, + CashflowTablePdfInjectable, + CashflowExportInjectable, + CashflowTableInjectable, + CashflowSheetApplication, + TenancyContext + ], + controllers: [CashflowController], +}) +export class CashflowReportModule {} diff --git a/temp/CashFlowStatement/Cashflow.types.ts b/temp/CashFlowStatement/Cashflow.types.ts new file mode 100644 index 000000000..6d21ca118 --- /dev/null +++ b/temp/CashFlowStatement/Cashflow.types.ts @@ -0,0 +1,299 @@ +import { Knex } from 'knex'; +import { IFinancialSheetCommonMeta, INumberFormatQuery } from '../../types/Report.types'; +import { Account } from '@/modules/Accounts/models/Account.model'; +import { Ledger } from '@/modules/Ledger/Ledger'; +import { IFinancialTable, ITableRow } from '../../types/Table.types'; + + +export interface ICashFlowStatementQuery { + fromDate: Date | string; + toDate: Date | string; + displayColumnsBy: string; + displayColumnsType: string; + noneZero: boolean; + noneTransactions: boolean; + numberFormat: INumberFormatQuery; + basis: string; + + branchesIds?: number[]; +} + +export interface ICashFlowStatementTotal { + amount: number; + formattedAmount: string; + currencyCode: string; +} + +export interface ICashFlowStatementTotalPeriod { + fromDate: Date; + toDate: Date; + total: ICashFlowStatementTotal; +} + +export interface ICashFlowStatementCommonSection { + id: string; + label: string; + total: ICashFlowStatementTotal; + footerLabel?: string; +} + +export interface ICashFlowStatementAccountMeta { + id: number; + label: string; + code: string; + total: ICashFlowStatementTotal; + accountType: string; + adjustmentType: string; + sectionType: ICashFlowStatementSectionType.ACCOUNT; +} + +export enum ICashFlowStatementSectionType { + REGULAR = 'REGULAR', + AGGREGATE = 'AGGREGATE', + NET_INCOME = 'NET_INCOME', + ACCOUNT = 'ACCOUNT', + ACCOUNTS = 'ACCOUNTS', + TOTAL = 'TOTAL', + CASH_AT_BEGINNING = 'CASH_AT_BEGINNING', +} + +export interface ICashFlowStatementAccountSection + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.ACCOUNTS; + children: ICashFlowStatementAccountMeta[]; + total: ICashFlowStatementTotal; +} + +export interface ICashFlowStatementNetIncomeSection + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.NET_INCOME; +} + +export interface ICashFlowStatementTotalSection + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.TOTAL; +} + +export interface ICashFlowStatementAggregateSection + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.AGGREGATE; +} + +export interface ICashFlowCashBeginningNode + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.CASH_AT_BEGINNING; +} + +export type ICashFlowStatementSection = + | ICashFlowStatementAccountSection + | ICashFlowStatementNetIncomeSection + | ICashFlowStatementTotalSection + | ICashFlowStatementCommonSection; + +export interface ICashFlowStatementColumn {} +export interface ICashFlowStatementMeta extends IFinancialSheetCommonMeta { + formattedToDate: string; + formattedFromDate: string; + formattedDateRange: string; +} + +export interface ICashFlowStatementDOO { + data: ICashFlowStatementData; + meta: ICashFlowStatementMeta; + query: ICashFlowStatementQuery; +} + +export interface ICashFlowStatementTable extends IFinancialTable { + meta: ICashFlowStatementMeta; + query: ICashFlowStatementQuery; +} + +export interface ICashFlowStatementService { + cashFlow( + tenantId: number, + query: ICashFlowStatementQuery + ): Promise; +} + +// CASH FLOW SCHEMA TYPES. +// ----------------------------- +export interface ICashFlowSchemaCommonSection { + id: string; + label: string; + children: ICashFlowSchemaSection[]; + footerLabel?: string; +} + +export enum CASH_FLOW_ACCOUNT_RELATION { + MINES = 'mines', + PLUS = 'plus', +} + +export enum CASH_FLOW_SECTION_ID { + NET_INCOME = 'NET_INCOME', + OPERATING = 'OPERATING', + OPERATING_ACCOUNTS = 'OPERATING_ACCOUNTS', + INVESTMENT = 'INVESTMENT', + FINANCIAL = 'FINANCIAL', + + NET_OPERATING = 'NET_OPERATING', + NET_INVESTMENT = 'NET_INVESTMENT', + NET_FINANCIAL = 'NET_FINANCIAL', + + CASH_BEGINNING_PERIOD = 'CASH_BEGINNING_PERIOD', + CASH_END_PERIOD = 'CASH_END_PERIOD', + NET_CASH_INCREASE = 'NET_CASH_INCREASE', +} + +export interface ICashFlowSchemaAccountsSection + extends ICashFlowSchemaCommonSection { + sectionType: ICashFlowStatementSectionType.ACCOUNT; + accountsRelations: ICashFlowSchemaAccountRelation[]; +} + +export interface ICashFlowSchemaTotalSection + extends ICashFlowStatementCommonSection { + sectionType: ICashFlowStatementSectionType.TOTAL; + equation: string; +} + +export type ICashFlowSchemaSection = + | ICashFlowSchemaAccountsSection + | ICashFlowSchemaTotalSection + | ICashFlowSchemaCommonSection; + +export type ICashFlowStatementData = ICashFlowSchemaSection[]; + +export interface ICashFlowSchemaAccountRelation { + type: string; + direction: CASH_FLOW_ACCOUNT_RELATION.PLUS; +} + +export interface ICashFlowSchemaSectionAccounts + extends ICashFlowStatementCommonSection { + type: ICashFlowStatementSectionType.ACCOUNT; + accountsRelations: ICashFlowSchemaAccountRelation[]; +} + +export interface ICashFlowSchemaSectionTotal { + type: ICashFlowStatementSectionType.TOTAL; + totalEquation: string; +} + +export interface ICashFlowDatePeriod { + fromDate: ICashFlowDate; + toDate: ICashFlowDate; + total: ICashFlowStatementTotal; +} + +export interface ICashFlowDate { + formattedDate: string; + date: Date; +} + +export interface ICashFlowStatement { + /** + * Constructor method. + * @constructor + */ + constructor( + accounts: Account[], + ledger: Ledger, + cashLedger: Ledger, + netIncomeLedger: Ledger, + query: ICashFlowStatementQuery, + baseCurrency: string + ): void; + + reportData(): ICashFlowStatementData; +} + +export interface ICashFlowTable { + constructor(reportStatement: ICashFlowStatement): void; + tableRows(): ITableRow[]; +} + +export interface IDateRange { + fromDate: Date; + toDate: Date; +} + +export interface ICashflowTransactionSchema { + amount: number; + date: Date; + referenceNo?: string | null; + transactionNumber: string; + transactionType: string; + creditAccountId: number; + cashflowAccountId: number; + userId: number; + publishedAt?: Date | null; + branchId?: number; +} + +export interface ICashflowTransactionInput extends ICashflowTransactionSchema {} + +export interface ICategorizeCashflowTransactioDTO { + date: Date; + creditAccountId: number; + referenceNo: string; + transactionNumber: string; + transactionType: string; + exchangeRate: number; + description: string; + branchId: number; +} + +export interface IUncategorizedCashflowTransaction { + id?: number; + amount: number; + date: Date; + currencyCode: string; + accountId: number; + description: string; + referenceNo: string; + categorizeRefType: string; + categorizeRefId: number; + categorized: boolean; +} + +export interface CreateUncategorizedTransactionDTO { + date: Date | string; + accountId: number; + amount: number; + currencyCode: string; + payee?: string; + description?: string; + referenceNo?: string | null; + plaidTransactionId?: string | null; + pending?: boolean; + pendingPlaidTransactionId?: string | null; + batch?: string; +} + +export interface IUncategorizedTransactionCreatingEventPayload { + tenantId: number; + createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO; + trx: Knex.Transaction; +} + +export interface IUncategorizedTransactionCreatedEventPayload { + tenantId: number; + uncategorizedTransaction: any; + createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO; + trx: Knex.Transaction; +} + +export interface IPendingTransactionRemovingEventPayload { + tenantId: number; + uncategorizedTransactionId: number; + pendingTransaction: IUncategorizedCashflowTransaction; + trx?: Knex.Transaction; +} + +export interface IPendingTransactionRemovedEventPayload { + tenantId: number; + uncategorizedTransactionId: number; + pendingTransaction: IUncategorizedCashflowTransaction; + trx?: Knex.Transaction; +} diff --git a/temp/CashFlowStatement/CashflowExportInjectable.ts b/temp/CashFlowStatement/CashflowExportInjectable.ts new file mode 100644 index 000000000..75f4bcae2 --- /dev/null +++ b/temp/CashFlowStatement/CashflowExportInjectable.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@nestjs/common'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { ICashFlowStatementQuery } from './Cashflow.types'; +import { TableSheet } from '../../common/TableSheet'; + +@Injectable() +export class CashflowExportInjectable { + constructor(private readonly cashflowSheetTable: CashflowTableInjectable) {} + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + * @returns {Promise} + */ + public async xlsx(query: ICashFlowStatementQuery): Promise { + const table = await this.cashflowSheetTable.table(query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToXLSX(); + + return tableSheet.convertToBuffer(tableCsv, 'xlsx'); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + * @returns {Promise} + */ + public async csv(query: ICashFlowStatementQuery): Promise { + const table = await this.cashflowSheetTable.table(query); + + const tableSheet = new TableSheet(table.table); + const tableCsv = tableSheet.convertToCSV(); + + return tableCsv; + } +} diff --git a/temp/CashFlowStatement/CashflowSheetApplication.ts b/temp/CashFlowStatement/CashflowSheetApplication.ts new file mode 100644 index 000000000..2afdcf65f --- /dev/null +++ b/temp/CashFlowStatement/CashflowSheetApplication.ts @@ -0,0 +1,66 @@ +import { CashflowExportInjectable } from './CashflowExportInjectable'; +import { ICashFlowStatementQuery } from './Cashflow.types'; +import { CashFlowStatementService } from './CashFlowService'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { CashflowTablePdfInjectable } from './CashflowTablePdfInjectable'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class CashflowSheetApplication { + /** + * Constructor method. + * @param {CashflowExportInjectable} cashflowExport + * @param {} cashflowSheet + * @param cashflowTable + * @param cashflowPdf + */ + constructor( + private readonly cashflowExport: CashflowExportInjectable, + private readonly cashflowSheet: CashFlowStatementService, + private readonly cashflowTable: CashflowTableInjectable, + private readonly cashflowPdf: CashflowTablePdfInjectable, + ) {} + + /** + * Retrieves the cashflow sheet + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + */ + public async sheet(query: ICashFlowStatementQuery) { + return this.cashflowSheet.cashFlow(query); + } + + /** + * Retrieves the cashflow sheet in table format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + */ + public async table(query: ICashFlowStatementQuery) { + return this.cashflowTable.table(query); + } + + /** + * Retrieves the cashflow sheet in XLSX format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + * @returns {Promise} + */ + public async xlsx(query: ICashFlowStatementQuery) { + return this.cashflowExport.xlsx(query); + } + + /** + * Retrieves the cashflow sheet in CSV format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + * @returns {Promise} + */ + public async csv(query: ICashFlowStatementQuery): Promise { + return this.cashflowExport.csv(query); + } + + /** + * Retrieves the cashflow sheet in pdf format. + * @param {ICashFlowStatementQuery} query - Cashflow statement query. + * @returns {Promise} + */ + public async pdf(query: ICashFlowStatementQuery): Promise { + return this.cashflowPdf.pdf(query); + } +} diff --git a/temp/CashFlowStatement/CashflowSheetMeta.ts b/temp/CashFlowStatement/CashflowSheetMeta.ts new file mode 100644 index 000000000..3d19612eb --- /dev/null +++ b/temp/CashFlowStatement/CashflowSheetMeta.ts @@ -0,0 +1,36 @@ +import moment from 'moment'; +import { Injectable } from '@nestjs/common'; +import { FinancialSheetMeta } from '../../common/FinancialSheetMeta'; +import { + ICashFlowStatementMeta, + ICashFlowStatementQuery, +} from './Cashflow.types'; + +@Injectable() +export class CashflowSheetMeta { + constructor(private readonly financialSheetMeta: FinancialSheetMeta) {} + + /** + * Cashflow sheet meta. + * @param {ICashFlowStatementQuery} query + * @returns {Promise} + */ + public async meta( + query: ICashFlowStatementQuery, + ): Promise { + const meta = await this.financialSheetMeta.meta(); + const formattedToDate = moment(query.toDate).format('YYYY/MM/DD'); + const formattedFromDate = moment(query.fromDate).format('YYYY/MM/DD'); + const formattedDateRange = `From ${formattedFromDate} | To ${formattedToDate}`; + + const sheetName = 'Statement of Cash Flow'; + + return { + ...meta, + sheetName, + formattedToDate, + formattedFromDate, + formattedDateRange, + }; + } +} diff --git a/temp/CashFlowStatement/CashflowTableInjectable.ts b/temp/CashFlowStatement/CashflowTableInjectable.ts new file mode 100644 index 000000000..3440b5c3c --- /dev/null +++ b/temp/CashFlowStatement/CashflowTableInjectable.ts @@ -0,0 +1,36 @@ +import { Injectable } from '@nestjs/common'; +import { CashFlowTable } from './CashFlowTable'; +import { CashFlowStatementService } from './CashFlowService'; +import { I18nService } from 'nestjs-i18n'; +import { + ICashFlowStatementQuery, + ICashFlowStatementTable, +} from './Cashflow.types'; + +@Injectable() +export class CashflowTableInjectable { + constructor( + private readonly cashflowSheet: CashFlowStatementService, + private readonly i18n: I18nService, + ) {} + + /** + * Retrieves the cash flow table. + * @returns {Promise} + */ + public async table( + query: ICashFlowStatementQuery, + ): Promise { + const cashflowDOO = await this.cashflowSheet.cashFlow(query); + const cashflowTable = new CashFlowTable(cashflowDOO, this.i18n); + + return { + table: { + columns: cashflowTable.tableColumns(), + rows: cashflowTable.tableRows(), + }, + query: cashflowDOO.query, + meta: cashflowDOO.meta, + }; + } +} diff --git a/temp/CashFlowStatement/CashflowTablePdfInjectable.ts b/temp/CashFlowStatement/CashflowTablePdfInjectable.ts new file mode 100644 index 000000000..6033a9df2 --- /dev/null +++ b/temp/CashFlowStatement/CashflowTablePdfInjectable.ts @@ -0,0 +1,28 @@ +import { TableSheetPdf } from '../../common/TableSheetPdf'; +import { ICashFlowStatementQuery } from './Cashflow.types'; +import { CashflowTableInjectable } from './CashflowTableInjectable'; +import { HtmlTableCustomCss } from './constants'; + +export class CashflowTablePdfInjectable { + constructor( + private readonly cashflowTable: CashflowTableInjectable, + private readonly tableSheetPdf: TableSheetPdf, + ) {} + + /** + * Converts the given cashflow sheet table to pdf. + * @param {number} tenantId - Tenant ID. + * @param {IBalanceSheetQuery} query - Balance sheet query. + * @returns {Promise} + */ + public async pdf(query: ICashFlowStatementQuery): Promise { + const table = await this.cashflowTable.table(query); + + return this.tableSheetPdf.convertToPdf( + table.table, + table.meta.sheetName, + table.meta.formattedDateRange, + HtmlTableCustomCss, + ); + } +} diff --git a/temp/CashFlowStatement/constants.ts b/temp/CashFlowStatement/constants.ts new file mode 100644 index 000000000..6aaa74486 --- /dev/null +++ b/temp/CashFlowStatement/constants.ts @@ -0,0 +1,52 @@ +import { ICashFlowStatementQuery } from "./Cashflow.types"; + +export const DISPLAY_COLUMNS_BY = { + DATE_PERIODS: 'date_periods', + TOTAL: 'total', +}; + +export const MAP_CONFIG = { childrenPath: 'children', pathFormat: 'array' }; +export const HtmlTableCustomCss = ` +table tr.row-type--accounts td { + border-top: 1px solid #bbb; +} +table tr.row-id--cash-end-period td { + border-bottom: 3px double #333; +} +table tr.row-type--total { + font-weight: 600; +} +table tr.row-type--total td { + color: #000; +} +table tr.row-type--total:not(:first-child) td { + border-top: 1px solid #bbb; +} +table .column--name, +table .cell--name { + width: 400px; +} +table .column--total, +table .cell--total, +table [class*="column--date-range"], +table [class*="cell--date-range"] { + text-align: right; +} +`; + +export const getDefaultCashflowQuery = (): ICashFlowStatementQuery => ({ + displayColumnsType: 'total', + displayColumnsBy: 'day', + fromDate: moment().startOf('year').format('YYYY-MM-DD'), + toDate: moment().format('YYYY-MM-DD'), + numberFormat: { + precision: 2, + divideOn1000: false, + showZero: false, + formatMoney: 'total', + negativeFormat: 'mines', + }, + noneZero: false, + noneTransactions: false, + basis: 'cash', +}); diff --git a/temp/CashFlowStatement/schema.ts b/temp/CashFlowStatement/schema.ts new file mode 100644 index 000000000..67be33743 --- /dev/null +++ b/temp/CashFlowStatement/schema.ts @@ -0,0 +1,77 @@ +import { ACCOUNT_TYPE } from '@/constants/accounts'; +import { + ICashFlowSchemaSection, + CASH_FLOW_SECTION_ID, + ICashFlowStatementSectionType, +} from './Cashflow.types'; + +export const CASH_FLOW_SCHEMA = [ + { + id: CASH_FLOW_SECTION_ID.OPERATING, + label: 'OPERATING ACTIVITIES', + sectionType: ICashFlowStatementSectionType.AGGREGATE, + children: [ + { + id: CASH_FLOW_SECTION_ID.NET_INCOME, + label: 'Net income', + sectionType: ICashFlowStatementSectionType.NET_INCOME, + }, + { + id: CASH_FLOW_SECTION_ID.OPERATING_ACCOUNTS, + label: 'Adjustments net income by operating activities.', + sectionType: ICashFlowStatementSectionType.ACCOUNTS, + accountsRelations: [ + { type: ACCOUNT_TYPE.ACCOUNTS_RECEIVABLE, direction: 'mines' }, + { type: ACCOUNT_TYPE.INVENTORY, direction: 'mines' }, + { type: ACCOUNT_TYPE.NON_CURRENT_ASSET, direction: 'mines' }, + { type: ACCOUNT_TYPE.ACCOUNTS_PAYABLE, direction: 'plus' }, + { type: ACCOUNT_TYPE.CREDIT_CARD, direction: 'plus' }, + { type: ACCOUNT_TYPE.TAX_PAYABLE, direction: 'plus' }, + { type: ACCOUNT_TYPE.OTHER_CURRENT_ASSET, direction: 'mines' }, + { type: ACCOUNT_TYPE.OTHER_CURRENT_LIABILITY, direction: 'plus' }, + { type: ACCOUNT_TYPE.NON_CURRENT_LIABILITY, direction: 'plus' }, + ], + showAlways: true, + }, + ], + footerLabel: 'Net cash provided by operating activities', + }, + { + id: CASH_FLOW_SECTION_ID.INVESTMENT, + sectionType: ICashFlowStatementSectionType.ACCOUNTS, + label: 'INVESTMENT ACTIVITIES', + accountsRelations: [{ type: ACCOUNT_TYPE.FIXED_ASSET, direction: 'mines' }], + footerLabel: 'Net cash provided by investing activities', + }, + { + id: CASH_FLOW_SECTION_ID.FINANCIAL, + label: 'FINANCIAL ACTIVITIES', + sectionType: ICashFlowStatementSectionType.ACCOUNTS, + accountsRelations: [ + { type: ACCOUNT_TYPE.LOGN_TERM_LIABILITY, direction: 'plus' }, + { type: ACCOUNT_TYPE.EQUITY, direction: 'plus' }, + ], + footerLabel: 'Net cash provided by financing activities', + }, + { + id: CASH_FLOW_SECTION_ID.CASH_BEGINNING_PERIOD, + sectionType: ICashFlowStatementSectionType.CASH_AT_BEGINNING, + label: 'Cash at beginning of period', + accountsRelations: [ + { type: ACCOUNT_TYPE.CASH, direction: 'plus' }, + { type: ACCOUNT_TYPE.BANK, direction: 'plus' }, + ], + }, + { + id: CASH_FLOW_SECTION_ID.NET_CASH_INCREASE, + sectionType: ICashFlowStatementSectionType.TOTAL, + equation: 'OPERATING + INVESTMENT + FINANCIAL', + label: 'NET CASH INCREASE FOR PERIOD', + }, + { + id: CASH_FLOW_SECTION_ID.CASH_END_PERIOD, + label: 'CASH AT END OF PERIOD', + sectionType: ICashFlowStatementSectionType.TOTAL, + equation: 'NET_CASH_INCREASE + CASH_BEGINNING_PERIOD', + }, +] as ICashFlowSchemaSection[];