Files
bigcapital/server/src/services/FinancialStatements/AgingSummary/AgingSummary.ts
2021-01-13 20:58:58 +02:00

208 lines
5.7 KiB
TypeScript

import { defaultTo, sumBy, get } from 'lodash';
import {
IAgingPeriod,
ISaleInvoice,
IBill,
IAgingPeriodTotal,
IARAgingSummaryCustomer,
IContact,
IARAgingSummaryQuery,
IFormatNumberSettings,
} from 'interfaces';
import AgingReport from './AgingReport';
import { Dictionary } from 'tsyringe/dist/typings/types';
export default abstract class AgingSummaryReport extends AgingReport {
protected readonly contacts: IContact[];
protected readonly agingPeriods: IAgingPeriod[] = [];
protected readonly baseCurrency: string;
protected readonly query: IARAgingSummaryQuery;
protected readonly overdueInvoicesByContactId: Dictionary<
(ISaleInvoice | IBill)[]
>;
protected readonly currentInvoicesByContactId: Dictionary<
(ISaleInvoice | IBill)[]
>;
/**
* Setes initial aging periods to the given customer id.
* @param {number} customerId - Customer id.
*/
protected getInitialAgingPeriodsTotal() {
return this.agingPeriods.map((agingPeriod) => ({
...agingPeriod,
...this.formatAmount(0),
}));
}
/**
* Calculates the given contact aging periods.
* @param {ICustomer} customer
* @return {(IAgingPeriod & IAgingPeriodTotal)[]}
*/
protected getContactAgingPeriods(
contactId: number
): (IAgingPeriod & 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);
}
/**
* Sets the customer aging due amount to the table. (Xx)
* @param {number} customerId - Customer id.
* @param {number} dueAmount - Due amount.
* @param {number} overdueDays - Overdue days.
*/
protected getContactAgingDueAmount(
agingPeriods: any,
dueAmount: number,
overdueDays: number
): (IAgingPeriod & IAgingPeriodTotal)[] {
const newAgingPeriods = agingPeriods.map((agingPeriod) => {
const isInAgingPeriod =
agingPeriod.beforeDays <= overdueDays &&
(agingPeriod.toDays > overdueDays || !agingPeriod.toDays);
const total = isInAgingPeriod
? agingPeriod.total + dueAmount
: agingPeriod.total;
return {
...agingPeriod,
total,
};
});
return newAgingPeriods;
}
/**
* Retrieve the aging period total object.
* @param {number} amount
* @return {IAgingPeriodTotal}
*/
protected formatAmount(
amount: number,
settings: IFormatNumberSettings = {}
): IAgingPeriodTotal {
return {
total: amount,
formattedTotal: this.formatNumber(amount, settings),
currencyCode: this.baseCurrency,
};
}
protected formatTotalAmount(
amount: number,
settings: IFormatNumberSettings = {}
): IAgingPeriodTotal {
return this.formatAmount(amount, {
money: true,
excerptZero: false,
...settings
});
}
/**
* Calculates the total of the aging period by the given index.
* @param {number} index
* @return {number}
*/
protected getTotalAgingPeriodByIndex(
contactsAgingPeriods: any,
index: number
): number {
return this.contacts.reduce((acc, customer) => {
const totalPeriod = contactsAgingPeriods[index]
? contactsAgingPeriods[index].total
: 0;
return acc + totalPeriod;
}, 0);
}
/**
* Retrieve the due invoices by the given customer id.
* @param {number} customerId -
* @return {ISaleInvoice[]}
*/
protected getUnpaidInvoicesByContactId(
contactId: number
): (ISaleInvoice | IBill)[] {
return defaultTo(this.overdueInvoicesByContactId[contactId], []);
}
/**
* Retrieve total aging periods of the report.
* @return {(IAgingPeriodTotal & IAgingPeriod)[]}
*/
protected getTotalAgingPeriods(
contactsAgingPeriods: IARAgingSummaryCustomer[]
): (IAgingPeriodTotal & IAgingPeriod)[] {
return this.agingPeriods.map((agingPeriod, index) => {
const total = sumBy(contactsAgingPeriods, `aging[${index}].total`);
return {
...agingPeriod,
...this.formatTotalAmount(total),
};
});
}
/**
* Retrieve the current invoices by the given contact id.
* @param {number} contactId - Specific contact id.
* @return {(ISaleInvoice | IBill)[]}
*/
protected getCurrentInvoicesByContactId(
contactId: number
): (ISaleInvoice | IBill)[] {
return get(this.currentInvoicesByContactId, contactId, []);
}
/**
* Retrieve the contact total due amount.
* @param {number} contactId - Specific contact id.
* @return {number}
*/
protected getContactCurrentTotal(contactId: number): number {
const currentInvoices = this.getCurrentInvoicesByContactId(contactId);
return sumBy(currentInvoices, (invoice) => invoice.dueAmount);
}
/**
* Retrieve to total sumation of the given customers sections.
* @param {IARAgingSummaryCustomer[]} contactsSections -
* @return {number}
*/
protected getTotalCurrent(
customersSummary: IARAgingSummaryCustomer[]
): number {
return sumBy(customersSummary, (summary) => summary.current.total);
}
/**
* Retrieve the total of the given aging periods.
* @param {IAgingPeriodTotal[]} agingPeriods
* @return {number}
*/
protected getAgingPeriodsTotal(agingPeriods: IAgingPeriodTotal[]): number {
return sumBy(agingPeriods, 'total');
}
protected getTotalContactsTotals(
customersSummary: IARAgingSummaryCustomer[]
): number {
return sumBy(customersSummary, (summary) => summary.total.total);
}
}