feat: AR/AP aging summary report.

This commit is contained in:
a.bouhuolia
2021-01-07 16:05:32 +02:00
parent 22b2fd5918
commit 09b2aa57a0
4 changed files with 63 additions and 71 deletions

View File

@@ -20,6 +20,13 @@ export default class APAgingSummarySheet extends AgingSummaryReport {
readonly unpaidInvoicesByContactId: Dictionary<IBill[]>; readonly unpaidInvoicesByContactId: Dictionary<IBill[]>;
readonly agingPeriods: IAgingPeriod[]; readonly agingPeriods: IAgingPeriod[];
/**
* Constructor method.
* @param {number} tenantId - Tenant id.
* @param {IAPAgingSummaryQuery} query - Report query.
* @param {IVendor[]} vendors - Unpaid bills.
* @param {string} baseCurrency - Base currency of the organization.
*/
constructor( constructor(
tenantId: number, tenantId: number,
query: IAPAgingSummaryQuery, query: IAPAgingSummaryQuery,
@@ -44,16 +51,14 @@ export default class APAgingSummarySheet extends AgingSummaryReport {
this.query.agingDaysBefore, this.query.agingDaysBefore,
this.query.agingPeriods this.query.agingPeriods
); );
this.initContactsAgingPeriods();
this.calcUnpaidInvoicesAgingPeriods();
} }
/** /**
* Retrieve the vendor section data. * Retrieve the vendor section data.
* @param {IVendor} vendor * @param {IVendor} vendor
* @return {IAPAgingSummaryData} * @return {IAPAgingSummaryVendor}
*/ */
protected vendorData(vendor: IVendor): IAPAgingSummaryVendor { private vendorData(vendor: IVendor): IAPAgingSummaryVendor {
const agingPeriods = this.getContactAgingPeriods(vendor.id); const agingPeriods = this.getContactAgingPeriods(vendor.id);
const amount = sumBy(agingPeriods, 'total'); const amount = sumBy(agingPeriods, 'total');
@@ -68,8 +73,8 @@ export default class APAgingSummarySheet extends AgingSummaryReport {
* Retrieve vendors aging periods. * Retrieve vendors aging periods.
* @return {IAPAgingSummaryVendor[]} * @return {IAPAgingSummaryVendor[]}
*/ */
private vendorsWalker(): IAPAgingSummaryVendor[] { private vendorsWalker(vendors: IVendor[]): IAPAgingSummaryVendor[] {
return this.contacts return vendors
.map((vendor) => this.vendorData(vendor)) .map((vendor) => this.vendorData(vendor))
.filter( .filter(
(vendor: IAPAgingSummaryVendor) => (vendor: IAPAgingSummaryVendor) =>
@@ -82,9 +87,12 @@ export default class APAgingSummarySheet extends AgingSummaryReport {
* @return {IAPAgingSummaryData} * @return {IAPAgingSummaryData}
*/ */
public reportData(): IAPAgingSummaryData { public reportData(): IAPAgingSummaryData {
const vendorsAgingPeriods = this.vendorsWalker(this.contacts);
const totalAgingPeriods = this.getTotalAgingPeriods(vendorsAgingPeriods);
return { return {
vendors: this.vendorsWalker(), vendors: vendorsAgingPeriods,
total: this.getTotalAgingPeriods(), total: totalAgingPeriods,
} }
} }

View File

@@ -52,8 +52,6 @@ export default class ARAgingSummarySheet extends AgingSummaryReport {
this.query.agingDaysBefore, this.query.agingDaysBefore,
this.query.agingPeriods this.query.agingPeriods
); );
this.initContactsAgingPeriods();
this.calcUnpaidInvoicesAgingPeriods();
} }
/** /**
@@ -77,8 +75,8 @@ export default class ARAgingSummarySheet extends AgingSummaryReport {
* @param {ICustomer[]} customers * @param {ICustomer[]} customers
* @return {IARAgingSummaryCustomer[]} * @return {IARAgingSummaryCustomer[]}
*/ */
private customersWalker(): IARAgingSummaryCustomer[] { private customersWalker(customers: ICustomer[]): IARAgingSummaryCustomer[] {
return this.contacts return customers
.map((customer) => this.customerData(customer)) .map((customer) => this.customerData(customer))
.filter( .filter(
(customer: IARAgingSummaryCustomer) => (customer: IARAgingSummaryCustomer) =>
@@ -91,9 +89,12 @@ export default class ARAgingSummarySheet extends AgingSummaryReport {
* @return {IARAgingSummaryData} * @return {IARAgingSummaryData}
*/ */
public reportData(): IARAgingSummaryData { public reportData(): IARAgingSummaryData {
const customersAgingPeriods = this.customersWalker(this.contacts);
const totalAgingPeriods = this.getTotalAgingPeriods(customersAgingPeriods);
return { return {
customers: this.customersWalker(), customers: customersAgingPeriods,
total: this.getTotalAgingPeriods(), total: totalAgingPeriods,
}; };
} }

View File

@@ -13,7 +13,7 @@ export default abstract class AgingReport extends FinancialSheet{
* @param {number} agingPeriodsFreq * @param {number} agingPeriodsFreq
*/ */
agingRangePeriods( agingRangePeriods(
asDay: string, asDay: Date|string,
agingDaysBefore: number, agingDaysBefore: number,
agingPeriodsFreq: number agingPeriodsFreq: number
): IAgingPeriod[] { ): IAgingPeriod[] {

View File

@@ -1,10 +1,10 @@
import moment from 'moment'; import { defaultTo, sumBy } from 'lodash';
import { defaultTo } from 'lodash';
import { import {
IAgingPeriod, IAgingPeriod,
ISaleInvoice, ISaleInvoice,
IBill, IBill,
IAgingPeriodTotal, IAgingPeriodTotal,
IARAgingSummaryCustomer,
IContact, IContact,
} from 'interfaces'; } from 'interfaces';
import AgingReport from './AgingReport'; import AgingReport from './AgingReport';
@@ -15,7 +15,7 @@ export default abstract class AgingSummaryReport extends AgingReport {
protected readonly agingPeriods: IAgingPeriod[] = []; protected readonly agingPeriods: IAgingPeriod[] = [];
protected readonly baseCurrency: string; protected readonly baseCurrency: string;
protected readonly unpaidInvoices: (ISaleInvoice | IBill)[]; protected readonly unpaidInvoices: (ISaleInvoice | IBill)[];
readonly unpaidInvoicesByContactId: Dictionary< protected readonly unpaidInvoicesByContactId: Dictionary<
(ISaleInvoice | IBill)[] (ISaleInvoice | IBill)[]
>; >;
protected periodsByContactId: { protected periodsByContactId: {
@@ -26,13 +26,11 @@ export default abstract class AgingSummaryReport extends AgingReport {
* Setes initial aging periods to the given customer id. * Setes initial aging periods to the given customer id.
* @param {number} customerId - Customer id. * @param {number} customerId - Customer id.
*/ */
protected setInitialAgingPeriods(contactId: number): void { protected getInitialAgingPeriodsTotal() {
this.periodsByContactId[contactId] = this.agingPeriods.map( return this.agingPeriods.map((agingPeriod) => ({
(agingPeriod) => ({
...agingPeriod, ...agingPeriod,
...this.formatTotalAmount(0), ...this.formatTotalAmount(0),
}) }));
);
} }
/** /**
@@ -43,29 +41,34 @@ export default abstract class AgingSummaryReport extends AgingReport {
protected getContactAgingPeriods( protected getContactAgingPeriods(
contactId: number contactId: number
): (IAgingPeriod & IAgingPeriodTotal)[] { ): (IAgingPeriod & IAgingPeriodTotal)[] {
return defaultTo(this.periodsByContactId[contactId], []); const unpaidInvoices = this.getUnpaidInvoicesByContactId(contactId);
const initialAgingPeriods = this.getInitialAgingPeriodsTotal();
return unpaidInvoices.reduce((agingPeriods, unpaidInvoice) => {
const newAgingPeriods = this.getContactAgingDueAmount(
agingPeriods,
unpaidInvoice.dueAmount,
unpaidInvoice.overdueDays
);
return newAgingPeriods;
}, initialAgingPeriods);
} }
/** /**
* Sets the customer aging due amount to the table. * Sets the customer aging due amount to the table. (Xx)
* @param {number} customerId - Customer id. * @param {number} customerId - Customer id.
* @param {number} dueAmount - Due amount. * @param {number} dueAmount - Due amount.
* @param {number} overdueDays - Overdue days. * @param {number} overdueDays - Overdue days.
*/ */
protected setContactAgingDueAmount( protected getContactAgingDueAmount(
customerId: number, agingPeriods: any,
dueAmount: number, dueAmount: number,
overdueDays: number overdueDays: number
): void { ): (IAgingPeriod & IAgingPeriodTotal)[] {
if (!this.periodsByContactId[customerId]) {
this.setInitialAgingPeriods(customerId);
}
const agingPeriods = this.periodsByContactId[customerId];
const newAgingPeriods = agingPeriods.map((agingPeriod) => { const newAgingPeriods = agingPeriods.map((agingPeriod) => {
const isInAgingPeriod = const isInAgingPeriod =
agingPeriod.beforeDays < overdueDays && agingPeriod.beforeDays <= overdueDays &&
agingPeriod.toDays > overdueDays; (agingPeriod.toDays > overdueDays || !agingPeriod.toDays);
return { return {
...agingPeriod, ...agingPeriod,
@@ -74,11 +77,11 @@ export default abstract class AgingSummaryReport extends AgingReport {
: agingPeriod.total, : agingPeriod.total,
}; };
}); });
this.periodsByContactId[customerId] = newAgingPeriods; return newAgingPeriods;
} }
/** /**
* Retrieve the aging period total object. * Retrieve the aging period total object. (xx)
* @param {number} amount * @param {number} amount
* @return {IAgingPeriodTotal} * @return {IAgingPeriodTotal}
*/ */
@@ -95,26 +98,21 @@ export default abstract class AgingSummaryReport extends AgingReport {
* @param {number} index * @param {number} index
* @return {number} * @return {number}
*/ */
protected getTotalAgingPeriodByIndex(index: number): number { protected getTotalAgingPeriodByIndex(
contactsAgingPeriods: any,
index: number
): number {
return this.contacts.reduce((acc, customer) => { return this.contacts.reduce((acc, customer) => {
const periods = this.getContactAgingPeriods(customer.id); const totalPeriod = contactsAgingPeriods[index]
const totalPeriod = periods[index] ? periods[index].total : 0; ? contactsAgingPeriods[index].total
: 0;
return acc + totalPeriod; return acc + totalPeriod;
}, 0); }, 0);
} }
/** /**
* Sets the initial aging periods to the all customers. * Retrieve the due invoices by the given customer id. (XX)
*/
protected initContactsAgingPeriods(): void {
this.contacts.forEach((contact) => {
this.setInitialAgingPeriods(contact.id);
});
}
/**
* Retrieve the due invoices by the given customer id.
* @param {number} customerId - * @param {number} customerId -
* @return {ISaleInvoice[]} * @return {ISaleInvoice[]}
*/ */
@@ -128,9 +126,11 @@ export default abstract class AgingSummaryReport extends AgingReport {
* Retrieve total aging periods of the report. * Retrieve total aging periods of the report.
* @return {(IAgingPeriodTotal & IAgingPeriod)[]} * @return {(IAgingPeriodTotal & IAgingPeriod)[]}
*/ */
protected getTotalAgingPeriods(): (IAgingPeriodTotal & IAgingPeriod)[] { protected getTotalAgingPeriods(
contactsAgingPeriods: IARAgingSummaryCustomer[]
): (IAgingPeriodTotal & IAgingPeriod)[] {
return this.agingPeriods.map((agingPeriod, index) => { return this.agingPeriods.map((agingPeriod, index) => {
const total = this.getTotalAgingPeriodByIndex(index); const total = sumBy(contactsAgingPeriods, `aging[${index}].total`);
return { return {
...agingPeriod, ...agingPeriod,
@@ -138,21 +138,4 @@ export default abstract class AgingSummaryReport extends AgingReport {
}; };
}); });
} }
/**
* Sets customers invoices to aging periods.
*/
protected calcUnpaidInvoicesAgingPeriods(): void {
this.contacts.forEach((contact) => {
const unpaidInvoices = this.getUnpaidInvoicesByContactId(contact.id);
unpaidInvoices.forEach((unpaidInvoice) => {
this.setContactAgingDueAmount(
contact.id,
unpaidInvoice.dueAmount,
unpaidInvoice.overdueDays
);
});
});
}
} }