import { groupBy, sum, isEmpty } from 'lodash'; import * as R from 'ramda'; import AgingSummaryReport from './AgingSummary'; import { IAPAgingSummaryQuery, IAgingPeriod, IBill, IVendor, IAPAgingSummaryData, IAPAgingSummaryVendor, IAPAgingSummaryColumns, IAPAgingSummaryTotal, } from '@/interfaces'; import { Dictionary } from 'tsyringe/dist/typings/types'; import { allPassedConditionsPass } from 'utils'; export default class APAgingSummarySheet extends AgingSummaryReport { readonly tenantId: number; readonly query: IAPAgingSummaryQuery; readonly contacts: IVendor[]; readonly unpaidBills: IBill[]; readonly baseCurrency: string; readonly overdueInvoicesByContactId: Dictionary; readonly currentInvoicesByContactId: Dictionary; 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( tenantId: number, query: IAPAgingSummaryQuery, vendors: IVendor[], overdueBills: IBill[], unpaidBills: IBill[], baseCurrency: string ) { super(); this.tenantId = tenantId; this.query = query; this.numberFormat = this.query.numberFormat; this.contacts = vendors; this.baseCurrency = baseCurrency; this.overdueInvoicesByContactId = groupBy(overdueBills, 'vendorId'); this.currentInvoicesByContactId = groupBy(unpaidBills, 'vendorId'); // Initializes the aging periods. this.agingPeriods = this.agingRangePeriods( this.query.asDate, this.query.agingDaysBefore, this.query.agingPeriods ); } /** * Retrieve the vendors aging and current total. * @param {IAPAgingSummaryTotal} vendorsAgingPeriods * @return {IAPAgingSummaryTotal} */ private 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 * @return {IAPAgingSummaryVendor} */ private vendorTransformer = (vendor: IVendor): IAPAgingSummaryVendor => { const agingPeriods = this.getContactAgingPeriods(vendor.id); const currentTotal = this.getContactCurrentTotal(vendor.id); const agingPeriodsTotal = this.getAgingPeriodsTotal(agingPeriods); const amount = sum([agingPeriodsTotal, currentTotal]); return { vendorName: vendor.displayName, current: this.formatAmount(currentTotal), aging: agingPeriods, total: this.formatTotalAmount(amount), }; }; /** * Mappes the given vendor objects to vendor report node. * @param {IVendor[]} vendors * @returns {IAPAgingSummaryVendor[]} */ private vendorsMapper = (vendors: IVendor[]): IAPAgingSummaryVendor[] => { return vendors.map(this.vendorTransformer); }; /** * Detarmines whether the given vendor node is none zero. * @param {IAPAgingSummaryVendor} vendorNode * @returns {boolean} */ private filterNoneZeroVendorNode = ( vendorNode: IAPAgingSummaryVendor ): boolean => { return vendorNode.total.amount !== 0; }; /** * Filters vendors report nodes based on the given report query. * @param {IAPAgingSummaryVendor} vendorNode * @returns {boolean} */ private vendorNodeFilter = (vendorNode: IAPAgingSummaryVendor): boolean => { const { noneZero } = this.query; const conditions = [[noneZero, this.filterNoneZeroVendorNode]]; return allPassedConditionsPass(conditions)(vendorNode); }; /** * Filtesr the given report vendors nodes. * @param {IAPAgingSummaryVendor[]} vendorNodes * @returns {IAPAgingSummaryVendor[]} */ private vendorsFilter = ( vendorNodes: IAPAgingSummaryVendor[] ): IAPAgingSummaryVendor[] => { return vendorNodes.filter(this.vendorNodeFilter); }; /** * Detarmines whether vendors nodes filter enabled. * @returns {boolean} */ private isVendorNodesFilter = (): boolean => { return isEmpty(this.query.vendorsIds); }; /** * Retrieve vendors aging periods. * @return {IAPAgingSummaryVendor[]} */ private vendorsSection = (vendors: IVendor[]): IAPAgingSummaryVendor[] => { return R.compose( R.when(this.isVendorNodesFilter, this.vendorsFilter), this.vendorsMapper )(vendors); }; /** * Retrieve the A/P aging summary report data. * @return {IAPAgingSummaryData} */ public reportData = (): IAPAgingSummaryData => { const vendorsAgingPeriods = this.vendorsSection(this.contacts); const vendorsTotal = this.getVendorsTotal(vendorsAgingPeriods); return { vendors: vendorsAgingPeriods, total: vendorsTotal, }; }; /** * Retrieve the A/P aging summary report columns. */ public reportColumns = (): IAPAgingSummaryColumns => { return this.agingPeriods; }; }