mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
fix: AR/AP aging summary report.
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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[];
|
||||
export type IARAgingSummaryColumns = IAgingPeriod[];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IAgingSummaryContact {
|
||||
current: IAgingAmount;
|
||||
aging: IAgingPeriodTotal[];
|
||||
total: IAgingAmount;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export default class CustomerRepository extends TenantRepository {
|
||||
*/
|
||||
constructor(knex, cache) {
|
||||
super(knex, cache);
|
||||
this.repositoryName = 'ContactRepository';
|
||||
this.repositoryName = 'CustomerRepository';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -57,7 +57,6 @@ export default class JournalSheetService {
|
||||
group: 'organization',
|
||||
key: 'base_currency',
|
||||
});
|
||||
|
||||
// Retrieve all accounts on the storage.
|
||||
const accountsGraph = await accountRepository.getDependencyGraph();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user