From a747750d88ace071540f6dd38bbc67e0f4cd3f1e Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Thu, 14 Jan 2021 13:16:32 +0200 Subject: [PATCH] fix: AR/AP aging summary report. --- .../financialStatements.mappers.js | 13 +- server/src/interfaces/APAgingSummaryReport.ts | 14 ++- server/src/interfaces/ARAgingSummaryReport.ts | 31 ++--- server/src/interfaces/AgingReport.ts | 22 +++- server/src/repositories/CustomerRepository.ts | 2 +- server/src/repositories/VendorRepository.ts | 6 +- .../AgingSummary/APAgingSummarySheet.ts | 35 ++++-- .../AgingSummary/ARAgingSummarySheet.ts | 43 +++++-- .../AgingSummary/AgingSummary.ts | 117 +++++++++++------- .../FinancialStatements/FinancialSheet.ts | 56 +++++++-- .../GeneralLedger/GeneralLedger.ts | 96 ++++++++------ .../GeneralLedger/GeneralLedgerService.ts | 5 +- .../JournalSheet/JournalSheetService.ts | 1 - 13 files changed, 287 insertions(+), 154 deletions(-) diff --git a/client/src/store/financialStatement/financialStatements.mappers.js b/client/src/store/financialStatement/financialStatements.mappers.js index a73b30a21..a5f78c9e6 100644 --- a/client/src/store/financialStatement/financialStatements.mappers.js +++ b/client/src/store/financialStatement/financialStatements.mappers.js @@ -83,7 +83,7 @@ export const ARAgingSummaryTableRowsMapper = (sheet, total) => { const mapAging = (agingPeriods) => { return agingPeriods.reduce((acc, aging, index) => { - acc[`aging-${index}`] = aging.formatted_total; + acc[`aging-${index}`] = aging.total.formatted_amount; return acc; }, {}); }; @@ -94,18 +94,21 @@ export const ARAgingSummaryTableRowsMapper = (sheet, total) => { rowType: 'customer', name: customer.customer_name, ...agingRow, - current: customer.current.formatted_total, - total: customer.total.formatted_total, + current: customer.current.formatted_amount, + total: customer.total.formatted_amount, }); }); + if (rows.length <= 0) { + return []; + } return [ ...rows, { name: 'TOTAL', rowType: 'total', - current: sheet.total.current.formatted_total, + current: sheet.total.current.formatted_amount, ...mapAging(sheet.total.aging), - total: sheet.total.total.formatted_total, + total: sheet.total.total.formatted_amount, } ]; }; diff --git a/server/src/interfaces/APAgingSummaryReport.ts b/server/src/interfaces/APAgingSummaryReport.ts index 2c352fd46..dd62b4b1f 100644 --- a/server/src/interfaces/APAgingSummaryReport.ts +++ b/server/src/interfaces/APAgingSummaryReport.ts @@ -1,6 +1,7 @@ import { IAgingPeriod, - IAgingPeriodTotal + IAgingPeriodTotal, + IAgingAmount } from './AgingReport'; import { INumberFormatQuery @@ -17,14 +18,15 @@ export interface IAPAgingSummaryQuery { export interface IAPAgingSummaryVendor { vendorName: string, - current: IAgingPeriodTotal, - aging: (IAgingPeriod & IAgingPeriodTotal)[], - total: IAgingPeriodTotal, + current: IAgingAmount, + aging: IAgingPeriodTotal[], + total: IAgingAmount, }; export interface IAPAgingSummaryTotal { - current: IAgingPeriodTotal, - aging: (IAgingPeriodTotal & IAgingPeriod)[], + current: IAgingAmount, + aging: IAgingPeriodTotal[], + total: IAgingAmount, }; export interface IAPAgingSummaryData { diff --git a/server/src/interfaces/ARAgingSummaryReport.ts b/server/src/interfaces/ARAgingSummaryReport.ts index 581f3d5d5..20e3df42d 100644 --- a/server/src/interfaces/ARAgingSummaryReport.ts +++ b/server/src/interfaces/ARAgingSummaryReport.ts @@ -1,10 +1,5 @@ -import { - IAgingPeriod, - IAgingPeriodTotal -} from './AgingReport'; -import { - INumberFormatQuery -} from './FinancialStatements'; +import { IAgingPeriod, IAgingPeriodTotal, IAgingAmount } from './AgingReport'; +import { INumberFormatQuery } from './FinancialStatements'; export interface IARAgingSummaryQuery { asDate: Date | string; @@ -17,20 +12,20 @@ export interface IARAgingSummaryQuery { export interface IARAgingSummaryCustomer { customerName: string; - current: IAgingPeriodTotal, - aging: (IAgingPeriodTotal & IAgingPeriod)[]; - total: IAgingPeriodTotal; + current: IAgingAmount; + aging: IAgingPeriodTotal[]; + total: IAgingAmount; } export interface IARAgingSummaryTotal { - current: IAgingPeriodTotal, - aging: (IAgingPeriodTotal & IAgingPeriod)[], - total: IAgingPeriodTotal, -}; + current: IAgingAmount; + aging: IAgingPeriodTotal[]; + total: IAgingAmount; +} export interface IARAgingSummaryData { - customers: IARAgingSummaryCustomer[], - total: IARAgingSummaryTotal, -}; + customers: IARAgingSummaryCustomer[]; + total: IARAgingSummaryTotal; +} -export type IARAgingSummaryColumns = IAgingPeriod[]; \ No newline at end of file +export type IARAgingSummaryColumns = IAgingPeriod[]; diff --git a/server/src/interfaces/AgingReport.ts b/server/src/interfaces/AgingReport.ts index ca8d4bc01..65983d44f 100644 --- a/server/src/interfaces/AgingReport.ts +++ b/server/src/interfaces/AgingReport.ts @@ -1,12 +1,22 @@ -export interface IAgingPeriodTotal { - total: number; - formattedTotal: string; +export interface IAgingPeriodTotal extends IAgingPeriod { + total: IAgingAmount; +}; + +export interface IAgingAmount { + amount: number; + formattedAmount: string; currencyCode: string; } export interface IAgingPeriod { - fromPeriod: Date|string; - toPeriod: Date|string; + fromPeriod: Date | string; + toPeriod: Date | string; beforeDays: number; toDays: number; -} \ No newline at end of file +} + +export interface IAgingSummaryContact { + current: IAgingAmount; + aging: IAgingPeriodTotal[]; + total: IAgingAmount; +} diff --git a/server/src/repositories/CustomerRepository.ts b/server/src/repositories/CustomerRepository.ts index 8bfaa3633..59408909e 100644 --- a/server/src/repositories/CustomerRepository.ts +++ b/server/src/repositories/CustomerRepository.ts @@ -7,7 +7,7 @@ export default class CustomerRepository extends TenantRepository { */ constructor(knex, cache) { super(knex, cache); - this.repositoryName = 'ContactRepository'; + this.repositoryName = 'CustomerRepository'; } /** diff --git a/server/src/repositories/VendorRepository.ts b/server/src/repositories/VendorRepository.ts index b833840b3..085973e87 100644 --- a/server/src/repositories/VendorRepository.ts +++ b/server/src/repositories/VendorRepository.ts @@ -7,7 +7,7 @@ export default class VendorRepository extends TenantRepository { */ constructor(knex, cache) { super(knex, cache); - this.repositoryName = 'ContactRepository'; + this.repositoryName = 'VendorRepository'; } /** @@ -17,6 +17,10 @@ export default class VendorRepository extends TenantRepository { return Vendor.bindKnex(this.knex); } + unpaid() { + + } + changeBalance(vendorId: number, amount: number) { return super.changeNumber({ id: vendorId }, 'balance', amount); } diff --git a/server/src/services/FinancialStatements/AgingSummary/APAgingSummarySheet.ts b/server/src/services/FinancialStatements/AgingSummary/APAgingSummarySheet.ts index 769be797c..da56ac415 100644 --- a/server/src/services/FinancialStatements/AgingSummary/APAgingSummarySheet.ts +++ b/server/src/services/FinancialStatements/AgingSummary/APAgingSummarySheet.ts @@ -7,9 +7,11 @@ import { IVendor, IAPAgingSummaryData, IAPAgingSummaryVendor, - IAPAgingSummaryColumns + IAPAgingSummaryColumns, + IAPAgingSummaryTotal } from 'interfaces'; import { Dictionary } from 'tsyringe/dist/typings/types'; + export default class APAgingSummarySheet extends AgingSummaryReport { readonly tenantId: number; readonly query: IAPAgingSummaryQuery; @@ -56,6 +58,23 @@ export default class APAgingSummarySheet extends AgingSummaryReport { ); } + /** + * Retrieve the vendors aging and current total. + * @param {IAPAgingSummaryTotal} vendorsAgingPeriods + * @return {IAPAgingSummaryTotal} + */ + getVendorsTotal(vendorsAgingPeriods): IAPAgingSummaryTotal { + const totalAgingPeriods = this.getTotalAgingPeriods(vendorsAgingPeriods); + const totalCurrent = this.getTotalCurrent(vendorsAgingPeriods); + const totalVendorsTotal = this.getTotalContactsTotals(vendorsAgingPeriods); + + return { + current: this.formatTotalAmount(totalCurrent), + aging: totalAgingPeriods, + total: this.formatTotalAmount(totalVendorsTotal), + }; + } + /** * Retrieve the vendor section data. * @param {IVendor} vendor @@ -85,7 +104,7 @@ export default class APAgingSummarySheet extends AgingSummaryReport { .map((vendor) => this.vendorData(vendor)) .filter( (vendor: IAPAgingSummaryVendor) => - !(vendor.total.total === 0 && this.query.noneZero) + !(vendor.total.amount === 0 && this.query.noneZero) ); } @@ -95,16 +114,12 @@ export default class APAgingSummarySheet extends AgingSummaryReport { */ public reportData(): IAPAgingSummaryData { const vendorsAgingPeriods = this.vendorsWalker(this.contacts); - const totalAgingPeriods = this.getTotalAgingPeriods(vendorsAgingPeriods); - const totalCurrent = this.getTotalCurrent(vendorsAgingPeriods); + const vendorsTotal = this.getVendorsTotal(vendorsAgingPeriods); return { vendors: vendorsAgingPeriods, - total: { - current: this.formatTotalAmount(totalCurrent), - aging: totalAgingPeriods, - }, - } + total: vendorsTotal, + }; } /** @@ -113,4 +128,4 @@ export default class APAgingSummarySheet extends AgingSummaryReport { public reportColumns(): IAPAgingSummaryColumns { return this.agingPeriods; } -} \ No newline at end of file +} diff --git a/server/src/services/FinancialStatements/AgingSummary/ARAgingSummarySheet.ts b/server/src/services/FinancialStatements/AgingSummary/ARAgingSummarySheet.ts index 171f529b4..3385c76bb 100644 --- a/server/src/services/FinancialStatements/AgingSummary/ARAgingSummarySheet.ts +++ b/server/src/services/FinancialStatements/AgingSummary/ARAgingSummarySheet.ts @@ -7,6 +7,7 @@ import { ISaleInvoice, IARAgingSummaryData, IARAgingSummaryColumns, + IARAgingSummaryTotal, } from 'interfaces'; import AgingSummaryReport from './AgingSummary'; import { Dictionary } from 'tsyringe/dist/typings/types'; @@ -44,8 +45,14 @@ export default class ARAgingSummarySheet extends AgingSummaryReport { this.baseCurrency = baseCurrency; this.numberFormat = this.query.numberFormat; - this.overdueInvoicesByContactId = groupBy(overdueSaleInvoices, 'customerId'); - this.currentInvoicesByContactId = groupBy(currentSaleInvoices, 'customerId'); + this.overdueInvoicesByContactId = groupBy( + overdueSaleInvoices, + 'customerId' + ); + this.currentInvoicesByContactId = groupBy( + currentSaleInvoices, + 'customerId' + ); // Initializes the aging periods. this.agingPeriods = this.agingRangePeriods( @@ -84,27 +91,41 @@ export default class ARAgingSummarySheet extends AgingSummaryReport { .map((customer) => this.customerData(customer)) .filter( (customer: IARAgingSummaryCustomer) => - !(customer.total.total === 0 && this.query.noneZero) + !(customer.total.amount === 0 && this.query.noneZero) ); } + /** + * Retrieve the customers aging and current total. + * @param {IARAgingSummaryCustomer} customersAgingPeriods + */ + private getCustomersTotal( + customersAgingPeriods: IARAgingSummaryCustomer[] + ): IARAgingSummaryTotal { + const totalAgingPeriods = this.getTotalAgingPeriods(customersAgingPeriods); + const totalCurrent = this.getTotalCurrent(customersAgingPeriods); + const totalCustomersTotal = this.getTotalContactsTotals( + customersAgingPeriods + ); + + return { + current: this.formatTotalAmount(totalCurrent), + aging: totalAgingPeriods, + total: this.formatTotalAmount(totalCustomersTotal), + }; + } + /** * Retrieve A/R aging summary report data. * @return {IARAgingSummaryData} */ public reportData(): IARAgingSummaryData { const customersAgingPeriods = this.customersWalker(this.contacts); - const totalAgingPeriods = this.getTotalAgingPeriods(customersAgingPeriods); - const totalCurrent = this.getTotalCurrent(customersAgingPeriods); - const totalCustomersTotal = this.getTotalContactsTotals(customersAgingPeriods); + const customersTotal = this.getCustomersTotal(customersAgingPeriods); return { customers: customersAgingPeriods, - total: { - current: this.formatTotalAmount(totalCurrent), - aging: totalAgingPeriods, - total: this.formatTotalAmount(totalCustomersTotal), - } + total: customersTotal, }; } diff --git a/server/src/services/FinancialStatements/AgingSummary/AgingSummary.ts b/server/src/services/FinancialStatements/AgingSummary/AgingSummary.ts index d9e6ee048..cdb6e2b4f 100644 --- a/server/src/services/FinancialStatements/AgingSummary/AgingSummary.ts +++ b/server/src/services/FinancialStatements/AgingSummary/AgingSummary.ts @@ -8,6 +8,8 @@ import { IContact, IARAgingSummaryQuery, IFormatNumberSettings, + IAgingAmount, + IAgingSummaryContact } from 'interfaces'; import AgingReport from './AgingReport'; import { Dictionary } from 'tsyringe/dist/typings/types'; @@ -25,60 +27,61 @@ export default abstract class AgingSummaryReport extends AgingReport { >; /** - * Setes initial aging periods to the given customer id. - * @param {number} customerId - Customer id. + * Setes initial aging periods to the contact. */ - protected getInitialAgingPeriodsTotal() { + protected getInitialAgingPeriodsTotal(): IAgingPeriodTotal[] { return this.agingPeriods.map((agingPeriod) => ({ ...agingPeriod, - ...this.formatAmount(0), + total: this.formatAmount(0), })); } /** * Calculates the given contact aging periods. - * @param {ICustomer} customer - * @return {(IAgingPeriod & IAgingPeriodTotal)[]} + * @param {number} contactId - Contact id. + * @return {IAgingPeriodTotal[]} */ - protected getContactAgingPeriods( - contactId: number - ): (IAgingPeriod & IAgingPeriodTotal)[] { + protected getContactAgingPeriods(contactId: number): IAgingPeriodTotal[] { const unpaidInvoices = this.getUnpaidInvoicesByContactId(contactId); const initialAgingPeriods = this.getInitialAgingPeriodsTotal(); - return unpaidInvoices.reduce((agingPeriods, unpaidInvoice) => { - const newAgingPeriods = this.getContactAgingDueAmount( - agingPeriods, - unpaidInvoice.dueAmount, - unpaidInvoice.getOverdueDays(this.query.asDate) - ); - return newAgingPeriods; - }, initialAgingPeriods); + return unpaidInvoices.reduce( + (agingPeriods: IAgingPeriodTotal[], unpaidInvoice) => { + const newAgingPeriods = this.getContactAgingDueAmount( + agingPeriods, + unpaidInvoice.dueAmount, + unpaidInvoice.getOverdueDays(this.query.asDate) + ); + return newAgingPeriods; + }, + initialAgingPeriods + ); } /** - * Sets the customer aging due amount to the table. (Xx) - * @param {number} customerId - Customer id. + * Sets the contact aging due amount to the table. + * @param {IAgingPeriodTotal} agingPeriods - Aging periods. * @param {number} dueAmount - Due amount. * @param {number} overdueDays - Overdue days. + * @return {IAgingPeriodTotal[]} */ protected getContactAgingDueAmount( - agingPeriods: any, + agingPeriods: IAgingPeriodTotal[], dueAmount: number, overdueDays: number - ): (IAgingPeriod & IAgingPeriodTotal)[] { + ): IAgingPeriodTotal[] { const newAgingPeriods = agingPeriods.map((agingPeriod) => { const isInAgingPeriod = agingPeriod.beforeDays <= overdueDays && (agingPeriod.toDays > overdueDays || !agingPeriod.toDays); - - const total = isInAgingPeriod - ? agingPeriod.total + dueAmount - : agingPeriod.total; + + const total: number = isInAgingPeriod + ? agingPeriod.total.amount + dueAmount + : agingPeriod.total.amount; return { ...agingPeriod, - total, + total: this.formatAmount(total), }; }); return newAgingPeriods; @@ -87,27 +90,34 @@ export default abstract class AgingSummaryReport extends AgingReport { /** * Retrieve the aging period total object. * @param {number} amount - * @return {IAgingPeriodTotal} + * @param {IFormatNumberSettings} settings - Override the format number settings. + * @return {IAgingAmount} */ protected formatAmount( amount: number, settings: IFormatNumberSettings = {} - ): IAgingPeriodTotal { + ): IAgingAmount { return { - total: amount, - formattedTotal: this.formatNumber(amount, settings), + amount, + formattedAmount: this.formatNumber(amount, settings), currencyCode: this.baseCurrency, }; } + /** + * Retrieve the aging period total object. + * @param {number} amount + * @param {IFormatNumberSettings} settings - Override the format number settings. + * @return {IAgingPeriodTotal} + */ protected formatTotalAmount( amount: number, settings: IFormatNumberSettings = {} - ): IAgingPeriodTotal { + ): IAgingAmount { return this.formatAmount(amount, { money: true, excerptZero: false, - ...settings + ...settings, }); } @@ -118,9 +128,9 @@ export default abstract class AgingSummaryReport extends AgingReport { */ protected getTotalAgingPeriodByIndex( contactsAgingPeriods: any, - index: number + index: number, ): number { - return this.contacts.reduce((acc, customer) => { + return this.contacts.reduce((acc, contact) => { const totalPeriod = contactsAgingPeriods[index] ? contactsAgingPeriods[index].total : 0; @@ -130,9 +140,9 @@ export default abstract class AgingSummaryReport extends AgingReport { } /** - * Retrieve the due invoices by the given customer id. - * @param {number} customerId - - * @return {ISaleInvoice[]} + * Retrieve the due invoices by the given contact id. + * @param {number} contactId - + * @return {(ISaleInvoice | IBill)[]} */ protected getUnpaidInvoicesByContactId( contactId: number @@ -146,13 +156,23 @@ export default abstract class AgingSummaryReport extends AgingReport { */ protected getTotalAgingPeriods( contactsAgingPeriods: IARAgingSummaryCustomer[] - ): (IAgingPeriodTotal & IAgingPeriod)[] { + ): IAgingPeriodTotal[] { return this.agingPeriods.map((agingPeriod, index) => { - const total = sumBy(contactsAgingPeriods, `aging[${index}].total`); + const total = sumBy( + contactsAgingPeriods, + (summary: IARAgingSummaryCustomer) => { + const aging = summary.aging[index]; + + if (!aging) { + return 0; + } + return aging.total.amount; + } + ); return { ...agingPeriod, - ...this.formatTotalAmount(total), + total: this.formatTotalAmount(total), }; }); } @@ -179,14 +199,14 @@ export default abstract class AgingSummaryReport extends AgingReport { } /** - * Retrieve to total sumation of the given customers sections. + * Retrieve to total sumation of the given contacts summeries sections. * @param {IARAgingSummaryCustomer[]} contactsSections - * @return {number} */ protected getTotalCurrent( - customersSummary: IARAgingSummaryCustomer[] + contactsSummaries: IAgingSummaryContact[] ): number { - return sumBy(customersSummary, (summary) => summary.current.total); + return sumBy(contactsSummaries, (summary) => summary.current.amount); } /** @@ -195,13 +215,16 @@ export default abstract class AgingSummaryReport extends AgingReport { * @return {number} */ protected getAgingPeriodsTotal(agingPeriods: IAgingPeriodTotal[]): number { - return sumBy(agingPeriods, 'total'); + return sumBy(agingPeriods, (period) => period.total.amount); } - + /** + * Retrieve total of contacts totals. + * @param {IAgingSummaryContact[]} contactsSummaries + */ protected getTotalContactsTotals( - customersSummary: IARAgingSummaryCustomer[] + contactsSummaries: IAgingSummaryContact[] ): number { - return sumBy(customersSummary, (summary) => summary.total.total); + return sumBy(contactsSummaries, (summary) => summary.total.amount); } } diff --git a/server/src/services/FinancialStatements/FinancialSheet.ts b/server/src/services/FinancialStatements/FinancialSheet.ts index bab23900b..df78de504 100644 --- a/server/src/services/FinancialStatements/FinancialSheet.ts +++ b/server/src/services/FinancialStatements/FinancialSheet.ts @@ -1,16 +1,56 @@ -import { - formatNumber -} from 'utils'; +import { IFormatNumberSettings, INumberFormatQuery } from 'interfaces'; +import { formatNumber } from 'utils'; export default class FinancialSheet { - numberFormat: { noCents: boolean, divideOn1000: boolean }; + numberFormat: INumberFormatQuery; + + /** + * Transformes the number format query to settings + */ + protected transfromFormatQueryToSettings(): IFormatNumberSettings { + const { numberFormat } = this; + + return { + precision: numberFormat.precision, + divideOn1000: numberFormat.divideOn1000, + excerptZero: !numberFormat.showZero, + negativeFormat: numberFormat.negativeFormat, + money: numberFormat.formatMoney === 'always', + }; + } /** * Formating amount based on the given report query. - * @param {number} number + * @param {number} number - + * @param {IFormatNumberSettings} overrideSettings - * @return {string} */ - protected formatNumber(number): string { - return formatNumber(number, this.numberFormat); + protected formatNumber( + number, + overrideSettings: IFormatNumberSettings = {} + ): string { + const settings = { + ...this.transfromFormatQueryToSettings(), + ...overrideSettings, + }; + return formatNumber(number, settings); } -} \ No newline at end of file + + /** + * Formatting full amount with different format settings. + * @param {number} amount - + * @param {IFormatNumberSettings} settings - + */ + protected formatTotalNumber( + amount: number, + settings: IFormatNumberSettings = {} + ): string { + const { numberFormat } = this; + + return this.formatNumber(amount, { + money: numberFormat.formatMoney === 'none' ? false : true, + excerptZero: false, + ...settings + }); + } +} diff --git a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedger.ts b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedger.ts index 751a87e20..98b6a3c2d 100644 --- a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedger.ts +++ b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedger.ts @@ -7,9 +7,9 @@ import { IAccount, IJournalPoster, IAccountType, - IJournalEntry + IJournalEntry, } from 'interfaces'; -import FinancialSheet from "../FinancialSheet"; +import FinancialSheet from '../FinancialSheet'; export default class GeneralLedgerSheet extends FinancialSheet { tenantId: number; @@ -35,7 +35,7 @@ export default class GeneralLedgerSheet extends FinancialSheet { transactions: IJournalPoster, openingBalancesJournal: IJournalPoster, closingBalancesJournal: IJournalPoster, - baseCurrency: string, + baseCurrency: string ) { super(); @@ -51,7 +51,7 @@ export default class GeneralLedgerSheet extends FinancialSheet { /** * Mapping the account transactions to general ledger transactions of the given account. - * @param {IAccount} account + * @param {IAccount} account * @return {IGeneralLedgerSheetAccountTransaction[]} */ private accountTransactionsMapper( @@ -59,34 +59,45 @@ export default class GeneralLedgerSheet extends FinancialSheet { ): IGeneralLedgerSheetAccountTransaction[] { const entries = this.transactions.getAccountEntries(account.id); - return entries.map((transaction: IJournalEntry): IGeneralLedgerSheetAccountTransaction => { - let amount = 0; + return entries.map( + (transaction: IJournalEntry): IGeneralLedgerSheetAccountTransaction => { + let amount = 0; - if (account.type.normal === 'credit') { - amount += transaction.credit - transaction.debit; - } else if (account.type.normal === 'debit') { - amount += transaction.debit - transaction.credit; + if (account.type.normal === 'credit') { + amount += transaction.credit - transaction.debit; + } else if (account.type.normal === 'debit') { + amount += transaction.debit - transaction.credit; + } + const formattedAmount = this.formatNumber(amount); + + return { + ...pick(transaction, [ + 'id', + 'note', + 'transactionType', + 'referenceType', + 'referenceId', + 'referenceTypeFormatted', + 'date', + ]), + amount, + formattedAmount, + currencyCode: this.baseCurrency, + }; } - const formattedAmount = this.formatNumber(amount); - - return { - ...pick(transaction, ['id', 'note', 'transactionType', 'referenceType', - 'referenceId', 'date']), - amount, - formattedAmount, - currencyCode: this.baseCurrency, - }; - }); + ); } /** * Retrieve account opening balance. - * @param {IAccount} account + * @param {IAccount} account * @return {IGeneralLedgerSheetAccountBalance} */ - private accountOpeningBalance(account: IAccount): IGeneralLedgerSheetAccountBalance { + private accountOpeningBalance( + account: IAccount + ): IGeneralLedgerSheetAccountBalance { const amount = this.openingBalancesJournal.getAccountBalance(account.id); - const formattedAmount = this.formatNumber(amount); + const formattedAmount = this.formatTotalNumber(amount); const currencyCode = this.baseCurrency; const date = this.query.fromDate; @@ -95,12 +106,14 @@ export default class GeneralLedgerSheet extends FinancialSheet { /** * Retrieve account closing balance. - * @param {IAccount} account + * @param {IAccount} account * @return {IGeneralLedgerSheetAccountBalance} */ - private accountClosingBalance(account: IAccount): IGeneralLedgerSheetAccountBalance { + private accountClosingBalance( + account: IAccount + ): IGeneralLedgerSheetAccountBalance { const amount = this.closingBalancesJournal.getAccountBalance(account.id); - const formattedAmount = this.formatNumber(amount); + const formattedAmount = this.formatTotalNumber(amount); const currencyCode = this.baseCurrency; const date = this.query.toDate; @@ -109,35 +122,42 @@ export default class GeneralLedgerSheet extends FinancialSheet { /** * Retreive general ledger accounts sections. - * @param {IAccount} account + * @param {IAccount} account * @return {IGeneralLedgerSheetAccount} */ private accountMapper( - account: IAccount & { type: IAccountType }, + account: IAccount & { type: IAccountType } ): IGeneralLedgerSheetAccount { return { ...pick(account, ['id', 'name', 'code', 'index', 'parentAccountId']), opening: this.accountOpeningBalance(account), transactions: this.accountTransactionsMapper(account), closing: this.accountClosingBalance(account), - } + }; } /** * Retrieve mapped accounts with general ledger transactions and opeing/closing balance. - * @param {IAccount[]} accounts - + * @param {IAccount[]} accounts - * @return {IGeneralLedgerSheetAccount[]} */ private accountsWalker( accounts: IAccount & { type: IAccountType }[] ): IGeneralLedgerSheetAccount[] { - return accounts - .map((account: IAccount & { type: IAccountType }) => this.accountMapper(account)) - - // Filter general ledger accounts that have no transactions when `noneTransactions` is on. - .filter((generalLedgerAccount: IGeneralLedgerSheetAccount) => ( - !(generalLedgerAccount.transactions.length === 0 && this.query.noneTransactions) - )); + return ( + accounts + .map((account: IAccount & { type: IAccountType }) => + this.accountMapper(account) + ) + // Filter general ledger accounts that have no transactions when `noneTransactions` is on. + .filter( + (generalLedgerAccount: IGeneralLedgerSheetAccount) => + !( + generalLedgerAccount.transactions.length === 0 && + this.query.noneTransactions + ) + ) + ); } /** @@ -147,4 +167,4 @@ export default class GeneralLedgerSheet extends FinancialSheet { public reportData(): IGeneralLedgerSheetAccount[] { return this.accountsWalker(this.accounts); } -} \ No newline at end of file +} diff --git a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts index 57a28f2e7..071951cf4 100644 --- a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts +++ b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts @@ -85,8 +85,7 @@ export default class GeneralLedgerService { group: 'organization', key: 'base_currency', }); - - // Retrieve all accounts from the storage. + // Retrieve all accounts with associated type from the storage. const accounts = await accountRepository.all('type'); const accountsGraph = await accountRepository.getDependencyGraph(); @@ -111,11 +110,13 @@ export default class GeneralLedgerService { tenantId, accountsGraph ); + // Accounts opening transactions. const openingTransJournal = Journal.fromTransactions( openingBalanceTrans, tenantId, accountsGraph ); + // Accounts closing transactions. const closingTransJournal = Journal.fromTransactions( closingBalanceTrans, tenantId, diff --git a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts index 27a7e2e0c..866bd1db2 100644 --- a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts +++ b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts @@ -57,7 +57,6 @@ export default class JournalSheetService { group: 'organization', key: 'base_currency', }); - // Retrieve all accounts on the storage. const accountsGraph = await accountRepository.getDependencyGraph();