Files
bigcapital/packages/server/src/modules/FinancialStatements/modules/ARAgingSummary/ARAgingSummarySheet.ts
Ahmed Bouhuolia c83132b867 fix(financial-statements): use stored date format settings in all reports
- Replace hardcoded date formats ('YYYY/MM/DD') in all Meta classes with meta.dateFormat
- Add IFinancialReportMeta interface with baseCurrency and dateFormat fields
- Add DEFAULT_REPORT_META constant with default date format 'YYYY MMM DD'
- Update all sheet classes to accept IFinancialReportMeta parameter
- Update all services to pass dateFormat from meta to sheet constructors
- Fix customer/vendor transactions date formatting in table rows
- Add TenancyModule to SalesTaxLiabilityModule for dependency injection
- Make dateFormat optional in JournalSheet and GeneralLedger query types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-25 07:05:31 +02:00

198 lines
5.8 KiB
TypeScript

import * as R from 'ramda';
import { isEmpty, sum } from 'lodash';
import { IAgingPeriod } from '../AgingSummary/AgingSummary.types';
import {
IARAgingSummaryCustomer,
IARAgingSummaryData,
IARAgingSummaryColumns,
IARAgingSummaryTotal,
} from './ARAgingSummary.types';
import { AgingSummaryReport } from '../AgingSummary/AgingSummary';
import { allPassedConditionsPass } from '@/utils/all-conditions-passed';
import { ModelObject } from 'objection';
import { ARAgingSummaryRepository } from './ARAgingSummaryRepository';
import { Customer } from '@/modules/Customers/models/Customer';
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
import { IFinancialReportMeta, DEFAULT_REPORT_META } from '../../types/Report.types';
export class ARAgingSummarySheet extends AgingSummaryReport {
readonly query: ARAgingSummaryQueryDto;
readonly agingPeriods: IAgingPeriod[];
readonly repository: ARAgingSummaryRepository;
readonly overdueInvoicesByContactId: Record<
string,
ModelObject<SaleInvoice>[]
>;
readonly currentInvoicesByContactId: Record<
number,
Array<ModelObject<SaleInvoice>>
>;
/**
* Constructor method.
* @param {ARAgingSummaryQueryDto} query - Query
* @param {ARAgingSummaryRepository} repository - Repository.
* @param {IFinancialReportMeta} meta - Report meta.
*/
constructor(
query: ARAgingSummaryQueryDto,
repository: ARAgingSummaryRepository,
meta: IFinancialReportMeta,
) {
super();
this.query = query;
this.repository = repository;
this.numberFormat = this.query.numberFormat;
this.dateFormat = meta.dateFormat || DEFAULT_REPORT_META.dateFormat;
this.overdueInvoicesByContactId =
this.repository.overdueInvoicesByContactId;
this.currentInvoicesByContactId =
this.repository.currentInvoicesByContactId;
// Initializes the aging periods.
this.agingPeriods = this.agingRangePeriods(
this.query.asDate,
this.query.agingDaysBefore,
this.query.agingPeriods,
);
}
/**
* Mapping aging customer.
* @param {ICustomer} customer -
* @return {IARAgingSummaryCustomer[]}
*/
private customerTransformer = (
customer: ModelObject<Customer>,
): IARAgingSummaryCustomer => {
const agingPeriods = this.getContactAgingPeriods(customer.id);
const currentTotal = this.getContactCurrentTotal(customer.id);
const agingPeriodsTotal = this.getAgingPeriodsTotal(agingPeriods);
const amount = sum([agingPeriodsTotal, currentTotal]);
return {
customerName: customer.displayName,
current: this.formatAmount(currentTotal),
aging: agingPeriods,
total: this.formatTotalAmount(amount),
};
};
/**
* Mappes the customers objects to report accounts nodes.
* @param {ICustomer[]} customers
* @returns {IARAgingSummaryCustomer[]}
*/
private customersMapper = (
customers: ModelObject<Customer>[],
): IARAgingSummaryCustomer[] => {
return customers.map(this.customerTransformer);
};
/**
* Filters the none-zero account report node.
* @param {IARAgingSummaryCustomer} node
* @returns {boolean}
*/
private filterNoneZeroAccountNode = (
node: IARAgingSummaryCustomer,
): boolean => {
return node.total.amount !== 0;
};
/**
* Filters customer report node based on the given report query.
* @param {IARAgingSummaryCustomer} customerNode
* @returns {boolean}
*/
private customerNodeFilter = (
customerNode: IARAgingSummaryCustomer,
): boolean => {
const { noneZero } = this.query;
const conditions = [[noneZero, this.filterNoneZeroAccountNode]];
return allPassedConditionsPass(conditions)(customerNode);
};
/**
* Filters customers report nodes.
* @param {IARAgingSummaryCustomer[]} customers
* @returns {IARAgingSummaryCustomer[]}
*/
private customersFilter = (
customers: IARAgingSummaryCustomer[],
): IARAgingSummaryCustomer[] => {
return customers.filter(this.customerNodeFilter);
};
/**
* Detarmines the customers nodes filter is enabled.
* @returns {boolean}
*/
private isCustomersFilterEnabled = (): boolean => {
return isEmpty(this.query.customersIds);
};
/**
* Retrieve customers report.
* @param {ICustomer[]} customers
* @return {IARAgingSummaryCustomer[]}
*/
private customersWalker = (
customers: ModelObject<Customer>[],
): IARAgingSummaryCustomer[] => {
return R.compose(
R.when(this.isCustomersFilterEnabled, this.customersFilter),
this.customersMapper,
)(customers);
};
/**
* 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.repository.customers,
);
const customersTotal = this.getCustomersTotal(customersAgingPeriods);
return {
customers: customersAgingPeriods,
total: customersTotal,
};
};
/**
* Retrieve A/R aging summary report columns.
* @return {IARAgingSummaryColumns}
*/
public reportColumns(): IARAgingSummaryColumns {
return this.agingPeriods;
}
}