mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-22 15:50:32 +00:00
fix: AR/AP aging report
This commit is contained in:
@@ -1,25 +1,54 @@
|
|||||||
import { Type } from "class-transformer";
|
import { Type } from 'class-transformer';
|
||||||
import { IsBoolean, IsEnum, IsNumber, IsOptional, IsPositive } from "class-validator";
|
import {
|
||||||
|
IsBoolean,
|
||||||
|
IsEnum,
|
||||||
|
IsNumber,
|
||||||
|
IsOptional,
|
||||||
|
IsPositive,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
export class NumberFormatQueryDto {
|
export class NumberFormatQueryDto {
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number of decimal places to display',
|
||||||
|
example: 2,
|
||||||
|
})
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsPositive()
|
@IsPositive()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly precision: number;
|
readonly precision: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Whether to divide the number by 1000',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly divideOn1000: boolean;
|
readonly divideOn1000: boolean;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Whether to show zero values',
|
||||||
|
example: true,
|
||||||
|
})
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly showZero: boolean;
|
readonly showZero: boolean;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'How to format money values',
|
||||||
|
example: 'total',
|
||||||
|
enum: ['total', 'always', 'none'],
|
||||||
|
})
|
||||||
@IsEnum(['total', 'always', 'none'])
|
@IsEnum(['total', 'always', 'none'])
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly formatMoney: 'total' | 'always' | 'none';
|
readonly formatMoney: 'total' | 'always' | 'none';
|
||||||
|
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'How to format negative numbers',
|
||||||
|
example: 'parentheses',
|
||||||
|
enum: ['parentheses', 'mines'],
|
||||||
|
})
|
||||||
@IsEnum(['parentheses', 'mines'])
|
@IsEnum(['parentheses', 'mines'])
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly negativeFormat: 'parentheses' | 'mines';
|
readonly negativeFormat: 'parentheses' | 'mines';
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
import { Response } from 'express';
|
||||||
import { Controller, Get, Headers, Query, Res } from '@nestjs/common';
|
import { Controller, Get, Headers, Query, Res } from '@nestjs/common';
|
||||||
import { APAgingSummaryApplication } from './APAgingSummaryApplication';
|
import { APAgingSummaryApplication } from './APAgingSummaryApplication';
|
||||||
import { IAPAgingSummaryQuery } from './APAgingSummary.types';
|
|
||||||
import { AcceptType } from '@/constants/accept-type';
|
import { AcceptType } from '@/constants/accept-type';
|
||||||
import { Response } from 'express';
|
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import {
|
|||||||
IAgingSummaryContact,
|
IAgingSummaryContact,
|
||||||
IAgingSummaryData,
|
IAgingSummaryData,
|
||||||
} from '../AgingSummary/AgingSummary.types';
|
} from '../AgingSummary/AgingSummary.types';
|
||||||
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
export interface IAPAgingSummaryQuery extends IAgingSummaryQuery {
|
|
||||||
vendorsIds: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IAPAgingSummaryVendor extends IAgingSummaryContact {
|
export interface IAPAgingSummaryVendor extends IAgingSummaryContact {
|
||||||
vendorName: string;
|
vendorName: string;
|
||||||
@@ -33,13 +30,13 @@ export interface IAPAgingSummaryMeta extends IFinancialSheetCommonMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IAPAgingSummaryTable extends IFinancialTable {
|
export interface IAPAgingSummaryTable extends IFinancialTable {
|
||||||
query: IAPAgingSummaryQuery;
|
query: APAgingSummaryQueryDto;
|
||||||
meta: IAPAgingSummaryMeta;
|
meta: IAPAgingSummaryMeta;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAPAgingSummarySheet {
|
export interface IAPAgingSummarySheet {
|
||||||
data: IAPAgingSummaryData;
|
data: IAPAgingSummaryData;
|
||||||
meta: IAPAgingSummaryMeta;
|
meta: IAPAgingSummaryMeta;
|
||||||
query: IAPAgingSummaryQuery;
|
query: APAgingSummaryQueryDto;
|
||||||
columns: any;
|
columns: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
import { APAgingSummaryExportInjectable } from './APAgingSummaryExportInjectable';
|
import { APAgingSummaryExportInjectable } from './APAgingSummaryExportInjectable';
|
||||||
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
||||||
import { IAPAgingSummaryQuery } from './APAgingSummary.types';
|
|
||||||
import { APAgingSummaryService } from './APAgingSummaryService';
|
import { APAgingSummaryService } from './APAgingSummaryService';
|
||||||
import { APAgingSummaryPdfInjectable } from './APAgingSummaryPdfInjectable';
|
import { APAgingSummaryPdfInjectable } from './APAgingSummaryPdfInjectable';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class APAgingSummaryApplication {
|
export class APAgingSummaryApplication {
|
||||||
@@ -16,42 +16,42 @@ export class APAgingSummaryApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/P aging summary in sheet format.
|
* Retrieve the A/P aging summary in sheet format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public sheet(query: IAPAgingSummaryQuery) {
|
public sheet(query: APAgingSummaryQueryDto) {
|
||||||
return this.APAgingSummarySheet.APAgingSummary(query);
|
return this.APAgingSummarySheet.APAgingSummary(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/P aging summary in table format.
|
* Retrieve the A/P aging summary in table format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public table(query: IAPAgingSummaryQuery) {
|
public table(query: APAgingSummaryQueryDto) {
|
||||||
return this.APAgingSummaryTable.table(query);
|
return this.APAgingSummaryTable.table(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/P aging summary in CSV format.
|
* Retrieve the A/P aging summary in CSV format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public csv(query: IAPAgingSummaryQuery) {
|
public csv(query: APAgingSummaryQueryDto) {
|
||||||
return this.APAgingSummaryExport.csv(query);
|
return this.APAgingSummaryExport.csv(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/P aging summary in XLSX format.
|
* Retrieve the A/P aging summary in XLSX format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public xlsx(query: IAPAgingSummaryQuery) {
|
public xlsx(query: APAgingSummaryQueryDto) {
|
||||||
return this.APAgingSummaryExport.xlsx(query);
|
return this.APAgingSummaryExport.xlsx(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/P aging summary in pdf format.
|
* Retrieves the A/P aging summary in pdf format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public pdf(query: IAPAgingSummaryQuery) {
|
public pdf(query: APAgingSummaryQueryDto) {
|
||||||
return this.APAgingSumaryPdf.pdf(query);
|
return this.APAgingSumaryPdf.pdf(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { TableSheet } from '../../common/TableSheet';
|
import { TableSheet } from '../../common/TableSheet';
|
||||||
import { IAPAgingSummaryQuery } from './APAgingSummary.types';
|
|
||||||
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
||||||
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class APAgingSummaryExportInjectable {
|
export class APAgingSummaryExportInjectable {
|
||||||
@@ -11,10 +11,10 @@ export class APAgingSummaryExportInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/P aging summary sheet in XLSX format.
|
* Retrieves the A/P aging summary sheet in XLSX format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async xlsx(query: IAPAgingSummaryQuery) {
|
public async xlsx(query: APAgingSummaryQueryDto) {
|
||||||
const table = await this.APAgingSummaryTable.table(query);
|
const table = await this.APAgingSummaryTable.table(query);
|
||||||
|
|
||||||
const tableSheet = new TableSheet(table.table);
|
const tableSheet = new TableSheet(table.table);
|
||||||
@@ -25,10 +25,10 @@ export class APAgingSummaryExportInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/P aging summary sheet in CSV format.
|
* Retrieves the A/P aging summary sheet in CSV format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {APAgingSummaryQueryDto} query
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async csv(query: IAPAgingSummaryQuery): Promise<string> {
|
public async csv(query: APAgingSummaryQueryDto): Promise<string> {
|
||||||
const table = await this.APAgingSummaryTable.table(query);
|
const table = await this.APAgingSummaryTable.table(query);
|
||||||
|
|
||||||
const tableSheet = new TableSheet(table.table);
|
const tableSheet = new TableSheet(table.table);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
import { TableSheetPdf } from '../../common/TableSheetPdf';
|
import { TableSheetPdf } from '../../common/TableSheetPdf';
|
||||||
import { HtmlTableCss } from '../AgingSummary/_constants';
|
import { HtmlTableCss } from '../AgingSummary/_constants';
|
||||||
import { IAPAgingSummaryQuery } from './APAgingSummary.types';
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
import { APAgingSummaryTableInjectable } from './APAgingSummaryTableInjectable';
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class APAgingSummaryPdfInjectable {
|
export class APAgingSummaryPdfInjectable {
|
||||||
@@ -13,10 +13,10 @@ export class APAgingSummaryPdfInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given A/P aging summary sheet table to pdf.
|
* Converts the given A/P aging summary sheet table to pdf.
|
||||||
* @param {IAPAgingSummaryQuery} query - Balance sheet query.
|
* @param {APAgingSummaryQueryDto} query - Balance sheet query.
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async pdf(query: IAPAgingSummaryQuery): Promise<Buffer> {
|
public async pdf(query: APAgingSummaryQueryDto): Promise<Buffer> {
|
||||||
const table = await this.APAgingSummaryTable.table(query);
|
const table = await this.APAgingSummaryTable.table(query);
|
||||||
|
|
||||||
return this.tableSheetPdf.convertToPdf(
|
return this.tableSheetPdf.convertToPdf(
|
||||||
|
|||||||
@@ -1,36 +1,74 @@
|
|||||||
import { Transform, Type } from 'class-transformer';
|
import { Transform, Type } from 'class-transformer';
|
||||||
import { IsNumber, IsOptional, IsDateString, IsBoolean, ValidateNested, IsArray } from 'class-validator';
|
import {
|
||||||
|
IsNumber,
|
||||||
|
IsOptional,
|
||||||
|
IsDateString,
|
||||||
|
IsBoolean,
|
||||||
|
ValidateNested,
|
||||||
|
IsArray,
|
||||||
|
} from 'class-validator';
|
||||||
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
||||||
import { parseBoolean } from '@/utils/parse-boolean';
|
import { parseBoolean } from '@/utils/parse-boolean';
|
||||||
import { ToNumber } from '@/common/decorators/Validators';
|
import { ToNumber } from '@/common/decorators/Validators';
|
||||||
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
export class APAgingSummaryQueryDto extends FinancialSheetBranchesQueryDto {
|
export class APAgingSummaryQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
@IsDateString()
|
@IsDateString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'The date as of which the AP aging summary is calculated',
|
||||||
|
example: '2024-06-01',
|
||||||
|
})
|
||||||
asDate: Date | string;
|
asDate: Date | string;
|
||||||
|
|
||||||
@ToNumber()
|
@ToNumber()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number of days before the aging period starts',
|
||||||
|
example: 30,
|
||||||
|
})
|
||||||
agingDaysBefore: number;
|
agingDaysBefore: number;
|
||||||
|
|
||||||
@ToNumber()
|
@ToNumber()
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number of aging periods to calculate',
|
||||||
|
example: 4,
|
||||||
|
})
|
||||||
agingPeriods: number;
|
agingPeriods: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@ValidateNested()
|
@ValidateNested()
|
||||||
@Type(() => NumberFormatQueryDto)
|
@Type(() => NumberFormatQueryDto)
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number format configuration',
|
||||||
|
example: {
|
||||||
|
precision: 2,
|
||||||
|
divideOn1000: false,
|
||||||
|
showZero: true,
|
||||||
|
formatMoney: 'total',
|
||||||
|
negativeFormat: 'parentheses',
|
||||||
|
},
|
||||||
|
})
|
||||||
numberFormat: NumberFormatQueryDto;
|
numberFormat: NumberFormatQueryDto;
|
||||||
|
|
||||||
@Transform(({ value }) => parseBoolean(value, false))
|
@Transform(({ value }) => parseBoolean(value, false))
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Whether to exclude zero values',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
noneZero: boolean;
|
noneZero: boolean;
|
||||||
|
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Array of vendor IDs to include',
|
||||||
|
example: [1, 2, 3],
|
||||||
|
})
|
||||||
vendorsIds: number[];
|
vendorsIds: number[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Inject } from '@nestjs/common';
|
import { Inject, Injectable, Scope } from '@nestjs/common';
|
||||||
import { isEmpty, groupBy } from 'lodash';
|
import { isEmpty, groupBy } from 'lodash';
|
||||||
|
import { ModelObject } from 'objection';
|
||||||
import { Bill } from '@/modules/Bills/models/Bill';
|
import { Bill } from '@/modules/Bills/models/Bill';
|
||||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||||
import { IAPAgingSummaryQuery } from './APAgingSummary.types';
|
|
||||||
import { ModelObject } from 'objection';
|
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
export class APAgingSummaryRepository {
|
export class APAgingSummaryRepository {
|
||||||
@Inject(Vendor.name)
|
@Inject(Vendor.name)
|
||||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>;
|
private readonly vendorModel: TenantModelProxy<typeof Vendor>;
|
||||||
@@ -18,10 +19,10 @@ export class APAgingSummaryRepository {
|
|||||||
private readonly tenancyContext: TenancyContext;
|
private readonly tenancyContext: TenancyContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter.
|
* A/P aging filter.
|
||||||
* @param {IAPAgingSummaryQuery} filter
|
* @param {APAgingSummaryQueryDto} filter
|
||||||
*/
|
*/
|
||||||
filter: IAPAgingSummaryQuery;
|
filter: APAgingSummaryQueryDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Due bills.
|
* Due bills.
|
||||||
@@ -45,7 +46,7 @@ export class APAgingSummaryRepository {
|
|||||||
* Overdue bills by vendor id.
|
* Overdue bills by vendor id.
|
||||||
* @param {Record<string, Bill[]>} overdueBillsByVendorId - Overdue bills by vendor id.
|
* @param {Record<string, Bill[]>} overdueBillsByVendorId - Overdue bills by vendor id.
|
||||||
*/
|
*/
|
||||||
overdueBillsByVendorId: ModelObject<Bill>[];
|
overdueBillsByVendorId: Record<string, Array<ModelObject<Bill>>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendors.
|
* Vendors.
|
||||||
@@ -61,9 +62,9 @@ export class APAgingSummaryRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the filter.
|
* Set the filter.
|
||||||
* @param {IAPAgingSummaryQuery} filter
|
* @param {APAgingSummaryQueryDto} filter
|
||||||
*/
|
*/
|
||||||
setFilter(filter: IAPAgingSummaryQuery) {
|
setFilter(filter: APAgingSummaryQueryDto) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import {
|
import { IAPAgingSummarySheet } from './APAgingSummary.types';
|
||||||
IAPAgingSummaryQuery,
|
|
||||||
IAPAgingSummarySheet,
|
|
||||||
} from './APAgingSummary.types';
|
|
||||||
import { APAgingSummarySheet } from './APAgingSummarySheet';
|
import { APAgingSummarySheet } from './APAgingSummarySheet';
|
||||||
import { APAgingSummaryMeta } from './APAgingSummaryMeta';
|
import { APAgingSummaryMeta } from './APAgingSummaryMeta';
|
||||||
import { getAPAgingSummaryDefaultQuery } from './utils';
|
import { getAPAgingSummaryDefaultQuery } from './utils';
|
||||||
import { APAgingSummaryRepository } from './APAgingSummaryRepository';
|
import { APAgingSummaryRepository } from './APAgingSummaryRepository';
|
||||||
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class APAgingSummaryService {
|
export class APAgingSummaryService {
|
||||||
@@ -20,13 +18,12 @@ export class APAgingSummaryService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve A/P aging summary report.
|
* Retrieve A/P aging summary report.
|
||||||
* @param {IAPAgingSummaryQuery} query - A/P aging summary query.
|
* @param {APAgingSummaryQueryDto} query - A/P aging summary query.
|
||||||
* @returns {Promise<IAPAgingSummarySheet>}
|
* @returns {Promise<IAPAgingSummarySheet>}
|
||||||
*/
|
*/
|
||||||
public async APAgingSummary(
|
public async APAgingSummary(
|
||||||
query: IAPAgingSummaryQuery,
|
query: APAgingSummaryQueryDto,
|
||||||
): Promise<IAPAgingSummarySheet> {
|
): Promise<IAPAgingSummarySheet> {
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
...getAPAgingSummaryDefaultQuery(),
|
...getAPAgingSummaryDefaultQuery(),
|
||||||
...query,
|
...query,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { sum, isEmpty } from 'lodash';
|
import { sum, isEmpty } from 'lodash';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import {
|
import {
|
||||||
IAPAgingSummaryQuery,
|
|
||||||
IAPAgingSummaryData,
|
IAPAgingSummaryData,
|
||||||
IAPAgingSummaryVendor,
|
IAPAgingSummaryVendor,
|
||||||
IAPAgingSummaryColumns,
|
IAPAgingSummaryColumns,
|
||||||
@@ -13,21 +12,24 @@ import { ModelObject } from 'objection';
|
|||||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||||
import { allPassedConditionsPass } from '@/utils/all-conditions-passed';
|
import { allPassedConditionsPass } from '@/utils/all-conditions-passed';
|
||||||
import { APAgingSummaryRepository } from './APAgingSummaryRepository';
|
import { APAgingSummaryRepository } from './APAgingSummaryRepository';
|
||||||
|
import { Bill } from '@/modules/Bills/models/Bill';
|
||||||
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
export class APAgingSummarySheet extends AgingSummaryReport {
|
export class APAgingSummarySheet extends AgingSummaryReport {
|
||||||
readonly repository: APAgingSummaryRepository;
|
readonly repository: APAgingSummaryRepository;
|
||||||
readonly query: IAPAgingSummaryQuery;
|
readonly query: APAgingSummaryQueryDto;
|
||||||
readonly agingPeriods: IAgingPeriod[];
|
readonly agingPeriods: IAgingPeriod[];
|
||||||
|
|
||||||
|
readonly overdueInvoicesByContactId: Record<string, Array<ModelObject<Bill>>>;
|
||||||
|
readonly currentInvoicesByContactId: Record<number, Array<ModelObject<Bill>>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor method.
|
* Constructor method.
|
||||||
* @param {number} tenantId - Tenant id.
|
* @param {APAgingSummaryQueryDto} query - Report query.
|
||||||
* @param {IAPAgingSummaryQuery} query - Report query.
|
* @param {APAgingSummaryRepository} repository - Repository
|
||||||
* @param {ModelObject<Vendor>[]} vendors - Unpaid bills.
|
|
||||||
* @param {string} baseCurrency - Base currency of the organization.
|
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
query: IAPAgingSummaryQuery,
|
query: APAgingSummaryQueryDto,
|
||||||
repository: APAgingSummaryRepository,
|
repository: APAgingSummaryRepository,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
@@ -36,6 +38,9 @@ export class APAgingSummarySheet extends AgingSummaryReport {
|
|||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.numberFormat = this.query.numberFormat;
|
this.numberFormat = this.query.numberFormat;
|
||||||
|
|
||||||
|
this.overdueInvoicesByContactId = this.repository.overdueBillsByVendorId;
|
||||||
|
this.currentInvoicesByContactId = this.repository.dueBillsByVendorId;
|
||||||
|
|
||||||
// Initializes the aging periods.
|
// Initializes the aging periods.
|
||||||
this.agingPeriods = this.agingRangePeriods(
|
this.agingPeriods = this.agingRangePeriods(
|
||||||
this.query.asDate,
|
this.query.asDate,
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
import { I18nService } from 'nestjs-i18n';
|
import { I18nService } from 'nestjs-i18n';
|
||||||
import {
|
import { IAPAgingSummaryTable } from './APAgingSummary.types';
|
||||||
IAPAgingSummaryQuery,
|
|
||||||
IAPAgingSummaryTable,
|
|
||||||
} from './APAgingSummary.types';
|
|
||||||
import { APAgingSummaryService } from './APAgingSummaryService';
|
import { APAgingSummaryService } from './APAgingSummaryService';
|
||||||
import { APAgingSummaryTable } from './APAgingSummaryTable';
|
import { APAgingSummaryTable } from './APAgingSummaryTable';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { APAgingSummaryQueryDto } from './APAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class APAgingSummaryTableInjectable {
|
export class APAgingSummaryTableInjectable {
|
||||||
@@ -16,11 +14,11 @@ export class APAgingSummaryTableInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves A/P aging summary in table format.
|
* Retrieves A/P aging summary in table format.
|
||||||
* @param {IAPAgingSummaryQuery} query -
|
* @param {APAgingSummaryQueryDto} query -
|
||||||
* @returns {Promise<IAPAgingSummaryTable>}
|
* @returns {Promise<IAPAgingSummaryTable>}
|
||||||
*/
|
*/
|
||||||
public async table(
|
public async table(
|
||||||
query: IAPAgingSummaryQuery,
|
query: APAgingSummaryQueryDto,
|
||||||
): Promise<IAPAgingSummaryTable> {
|
): Promise<IAPAgingSummaryTable> {
|
||||||
const report = await this.APAgingSummarySheet.APAgingSummary(query);
|
const report = await this.APAgingSummarySheet.APAgingSummary(query);
|
||||||
const table = new APAgingSummaryTable(report.data, query, this.i18nService);
|
const table = new APAgingSummaryTable(report.data, query, this.i18nService);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
export const getAPAgingSummaryDefaultQuery = () => {
|
export const getAPAgingSummaryDefaultQuery = () => {
|
||||||
return {
|
return {
|
||||||
asDate: moment().format('YYYY-MM-DD'),
|
asDate: moment().format('YYYY-MM-DD'),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
|
||||||
import { Controller, Get, Headers } from '@nestjs/common';
|
import { Controller, Get, Headers } from '@nestjs/common';
|
||||||
import { Query, Res } from '@nestjs/common';
|
import { Query, Res } from '@nestjs/common';
|
||||||
import { ARAgingSummaryApplication } from './ARAgingSummaryApplication';
|
import { ARAgingSummaryApplication } from './ARAgingSummaryApplication';
|
||||||
import { AcceptType } from '@/constants/accept-type';
|
import { AcceptType } from '@/constants/accept-type';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Controller('reports/receivable-aging-summary')
|
@Controller('reports/receivable-aging-summary')
|
||||||
@ApiTags('Reports')
|
@ApiTags('Reports')
|
||||||
@@ -14,7 +14,7 @@ export class ARAgingSummaryController {
|
|||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: 'Get receivable aging summary' })
|
@ApiOperation({ summary: 'Get receivable aging summary' })
|
||||||
public async get(
|
public async get(
|
||||||
@Query() filter: IARAgingSummaryQuery,
|
@Query() filter: ARAgingSummaryQueryDto,
|
||||||
@Res({ passthrough: true }) res: Response,
|
@Res({ passthrough: true }) res: Response,
|
||||||
@Headers('accept') acceptHeader: string,
|
@Headers('accept') acceptHeader: string,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
IAgingPeriod,
|
IAgingPeriod,
|
||||||
IAgingSummaryQuery,
|
|
||||||
IAgingSummaryTotal,
|
IAgingSummaryTotal,
|
||||||
IAgingSummaryContact,
|
IAgingSummaryContact,
|
||||||
IAgingSummaryData,
|
IAgingSummaryData,
|
||||||
IAgingSummaryMeta,
|
IAgingSummaryMeta,
|
||||||
} from '../AgingSummary/AgingSummary.types';
|
} from '../AgingSummary/AgingSummary.types';
|
||||||
import { IFinancialTable } from '../../types/Table.types';
|
import { IFinancialTable } from '../../types/Table.types';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
export interface IARAgingSummaryQuery extends IAgingSummaryQuery {
|
|
||||||
customersIds: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IARAgingSummaryCustomer extends IAgingSummaryContact {
|
export interface IARAgingSummaryCustomer extends IAgingSummaryContact {
|
||||||
customerName: string;
|
customerName: string;
|
||||||
@@ -31,13 +27,12 @@ export interface IARAgingSummaryMeta extends IAgingSummaryMeta {
|
|||||||
|
|
||||||
export interface IARAgingSummaryTable extends IFinancialTable {
|
export interface IARAgingSummaryTable extends IFinancialTable {
|
||||||
meta: IARAgingSummaryMeta;
|
meta: IARAgingSummaryMeta;
|
||||||
query: IARAgingSummaryQuery;
|
query: ARAgingSummaryQueryDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IARAgingSummarySheet {
|
export interface IARAgingSummarySheet {
|
||||||
data: IARAgingSummaryData;
|
data: IARAgingSummaryData;
|
||||||
meta: IARAgingSummaryMeta;
|
meta: IARAgingSummaryMeta;
|
||||||
query: IARAgingSummaryQuery;
|
query: ARAgingSummaryQueryDto;
|
||||||
columns: IARAgingSummaryColumns;
|
columns: IARAgingSummaryColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
||||||
import { ARAgingSummaryExportInjectable } from './ARAgingSummaryExportInjectable';
|
import { ARAgingSummaryExportInjectable } from './ARAgingSummaryExportInjectable';
|
||||||
import { ARAgingSummaryService } from './ARAgingSummaryService';
|
import { ARAgingSummaryService } from './ARAgingSummaryService';
|
||||||
import { ARAgingSummaryPdfInjectable } from './ARAgingSummaryPdfInjectable';
|
import { ARAgingSummaryPdfInjectable } from './ARAgingSummaryPdfInjectable';
|
||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ARAgingSummaryApplication {
|
export class ARAgingSummaryApplication {
|
||||||
@@ -16,42 +16,42 @@ export class ARAgingSummaryApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/R aging summary sheet.
|
* Retrieve the A/R aging summary sheet.
|
||||||
* @param {IARAgingSummaryQuery} query
|
* @param {ARAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public sheet(query: IARAgingSummaryQuery) {
|
public sheet(query: ARAgingSummaryQueryDto) {
|
||||||
return this.ARAgingSummarySheet.ARAgingSummary(query);
|
return this.ARAgingSummarySheet.ARAgingSummary(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/R aging summary in table format.
|
* Retrieve the A/R aging summary in table format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {ARAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public table(query: IARAgingSummaryQuery) {
|
public table(query: ARAgingSummaryQueryDto) {
|
||||||
return this.ARAgingSummaryTable.table(query);
|
return this.ARAgingSummaryTable.table(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/R aging summary in XLSX format.
|
* Retrieve the A/R aging summary in XLSX format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {ARAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public xlsx(query: IARAgingSummaryQuery) {
|
public xlsx(query: ARAgingSummaryQueryDto) {
|
||||||
return this.ARAgingSummaryExport.xlsx(query);
|
return this.ARAgingSummaryExport.xlsx(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the A/R aging summary in CSV format.
|
* Retrieve the A/R aging summary in CSV format.
|
||||||
* @param {IAPAgingSummaryQuery} query
|
* @param {ARAgingSummaryQueryDto} query
|
||||||
*/
|
*/
|
||||||
public csv(query: IARAgingSummaryQuery) {
|
public csv(query: ARAgingSummaryQueryDto) {
|
||||||
return this.ARAgingSummaryExport.csv(query);
|
return this.ARAgingSummaryExport.csv(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/R aging summary in pdf format.
|
* Retrieves the A/R aging summary in pdf format.
|
||||||
* @param {IARAgingSummaryQuery} query
|
* @param {ARAgingSummaryQueryDto} query
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public pdf(query: IARAgingSummaryQuery) {
|
public pdf(query: ARAgingSummaryQueryDto) {
|
||||||
return this.ARAgingSummaryPdf.pdf(query);
|
return this.ARAgingSummaryPdf.pdf(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
|
||||||
import { TableSheet } from '../../common/TableSheet';
|
import { TableSheet } from '../../common/TableSheet';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ARAgingSummaryExportInjectable {
|
export class ARAgingSummaryExportInjectable {
|
||||||
@@ -11,12 +11,10 @@ export class ARAgingSummaryExportInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/R aging summary sheet in XLSX format.
|
* Retrieves the A/R aging summary sheet in XLSX format.
|
||||||
* @param {IARAgingSummaryQuery} query - A/R aging summary query.
|
* @param {ARAgingSummaryQueryDto} query - A/R aging summary query.
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async xlsx(
|
public async xlsx(query: ARAgingSummaryQueryDto): Promise<Buffer> {
|
||||||
query: IARAgingSummaryQuery
|
|
||||||
): Promise<Buffer> {
|
|
||||||
const table = await this.ARAgingSummaryTable.table(query);
|
const table = await this.ARAgingSummaryTable.table(query);
|
||||||
|
|
||||||
const tableSheet = new TableSheet(table.table);
|
const tableSheet = new TableSheet(table.table);
|
||||||
@@ -27,12 +25,10 @@ export class ARAgingSummaryExportInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the A/R aging summary sheet in CSV format.
|
* Retrieves the A/R aging summary sheet in CSV format.
|
||||||
* @param {IARAgingSummaryQuery} query - A/R aging summary query.
|
* @param {ARAgingSummaryQueryDto} query - A/R aging summary query.
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
public async csv(
|
public async csv(query: ARAgingSummaryQueryDto): Promise<string> {
|
||||||
query: IARAgingSummaryQuery
|
|
||||||
): Promise<string> {
|
|
||||||
const table = await this.ARAgingSummaryTable.table(query);
|
const table = await this.ARAgingSummaryTable.table(query);
|
||||||
|
|
||||||
const tableSheet = new TableSheet(table.table);
|
const tableSheet = new TableSheet(table.table);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
import { ARAgingSummaryTableInjectable } from './ARAgingSummaryTableInjectable';
|
||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
|
||||||
import { TableSheetPdf } from '../../common/TableSheetPdf';
|
import { TableSheetPdf } from '../../common/TableSheetPdf';
|
||||||
import { HtmlTableCss } from '../AgingSummary/_constants';
|
import { HtmlTableCss } from '../AgingSummary/_constants';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ARAgingSummaryPdfInjectable {
|
export class ARAgingSummaryPdfInjectable {
|
||||||
@@ -16,7 +16,7 @@ export class ARAgingSummaryPdfInjectable {
|
|||||||
* @param {IBalanceSheetQuery} query - Balance sheet query.
|
* @param {IBalanceSheetQuery} query - Balance sheet query.
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async pdf(query: IARAgingSummaryQuery): Promise<Buffer> {
|
public async pdf(query: ARAgingSummaryQueryDto): Promise<Buffer> {
|
||||||
const table = await this.ARAgingSummaryTable.table(query);
|
const table = await this.ARAgingSummaryTable.table(query);
|
||||||
|
|
||||||
return this.tableSheetPdf.convertToPdf(
|
return this.tableSheetPdf.convertToPdf(
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { Transform, Type } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
IsNumber,
|
||||||
|
IsOptional,
|
||||||
|
IsDateString,
|
||||||
|
IsBoolean,
|
||||||
|
ValidateNested,
|
||||||
|
IsArray,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { FinancialSheetBranchesQueryDto } from '../../dtos/FinancialSheetBranchesQuery.dto';
|
||||||
|
import { ToNumber } from '@/common/decorators/Validators';
|
||||||
|
import { NumberFormatQueryDto } from '@/modules/BankingTransactions/dtos/NumberFormatQuery.dto';
|
||||||
|
import { parseBoolean } from '@/utils/parse-boolean';
|
||||||
|
|
||||||
|
export class ARAgingSummaryQueryDto extends FinancialSheetBranchesQueryDto {
|
||||||
|
@IsDateString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'The date as of which the A/R aging summary is calculated',
|
||||||
|
example: '2024-06-01',
|
||||||
|
})
|
||||||
|
asDate: Date | string;
|
||||||
|
|
||||||
|
@ToNumber()
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number of days before the aging period starts',
|
||||||
|
example: 30,
|
||||||
|
})
|
||||||
|
agingDaysBefore: number;
|
||||||
|
|
||||||
|
@ToNumber()
|
||||||
|
@IsNumber()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number of aging periods to calculate',
|
||||||
|
example: 4,
|
||||||
|
})
|
||||||
|
agingPeriods: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => NumberFormatQueryDto)
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Number format configuration',
|
||||||
|
example: {
|
||||||
|
precision: 2,
|
||||||
|
divideOn1000: false,
|
||||||
|
showZero: true,
|
||||||
|
formatMoney: 'total',
|
||||||
|
negativeFormat: 'parentheses',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
numberFormat: NumberFormatQueryDto;
|
||||||
|
|
||||||
|
@Transform(({ value }) => parseBoolean(value, false))
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Whether to exclude zero values',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
noneZero: boolean;
|
||||||
|
|
||||||
|
@IsArray()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
description: 'Array of customer IDs to include',
|
||||||
|
example: [1, 2, 3],
|
||||||
|
})
|
||||||
|
customersIds: number[];
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Inject } from '@nestjs/common';
|
import { Inject, Injectable, Scope } from '@nestjs/common';
|
||||||
import { isEmpty, groupBy } from 'lodash';
|
import { isEmpty, groupBy } from 'lodash';
|
||||||
import { Customer } from '@/modules/Customers/models/Customer';
|
import { Customer } from '@/modules/Customers/models/Customer';
|
||||||
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
|
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
|
||||||
import { ModelObject } from 'objection';
|
import { ModelObject } from 'objection';
|
||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
|
||||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
export class ARAgingSummaryRepository {
|
export class ARAgingSummaryRepository {
|
||||||
@Inject(TenancyContext)
|
@Inject(TenancyContext)
|
||||||
private tenancyContext: TenancyContext;
|
private tenancyContext: TenancyContext;
|
||||||
@@ -19,9 +20,9 @@ export class ARAgingSummaryRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter.
|
* Filter.
|
||||||
* @param {IARAgingSummaryQuery} filter
|
* @param {ARAgingSummaryQueryDto} filter
|
||||||
*/
|
*/
|
||||||
filter: IARAgingSummaryQuery;
|
filter: ARAgingSummaryQueryDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base currency.
|
* Base currency.
|
||||||
@@ -61,9 +62,9 @@ export class ARAgingSummaryRepository {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the filter.
|
* Set the filter.
|
||||||
* @param {IARAgingSummaryQuery} filter
|
* @param {ARAgingSummaryQueryDto} filter
|
||||||
*/
|
*/
|
||||||
setFilter(filter: IARAgingSummaryQuery) {
|
setFilter(filter: ARAgingSummaryQueryDto) {
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,9 +140,6 @@ export class ARAgingSummaryRepository {
|
|||||||
.onBuild(commonQuery);
|
.onBuild(commonQuery);
|
||||||
|
|
||||||
this.currentInvoices = currentInvoices;
|
this.currentInvoices = currentInvoices;
|
||||||
this.currentInvoicesByContactId = groupBy(
|
this.currentInvoicesByContactId = groupBy(currentInvoices, 'customerId');
|
||||||
currentInvoices,
|
|
||||||
'customerId',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { ARAgingSummaryMeta } from './ARAgingSummaryMeta';
|
|||||||
import { getARAgingSummaryDefaultQuery } from './utils';
|
import { getARAgingSummaryDefaultQuery } from './utils';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { IARAgingSummaryQuery } from './ARAgingSummary.types';
|
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { ARAgingSummaryRepository } from './ARAgingSummaryRepository';
|
import { ARAgingSummaryRepository } from './ARAgingSummaryRepository';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ARAgingSummaryService {
|
export class ARAgingSummaryService {
|
||||||
@@ -17,9 +17,9 @@ export class ARAgingSummaryService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve A/R aging summary report.
|
* Retrieve A/R aging summary report.
|
||||||
* @param {IARAgingSummaryQuery} query -
|
* @param {ARAgingSummaryQueryDto} query -
|
||||||
*/
|
*/
|
||||||
async ARAgingSummary(query: IARAgingSummaryQuery) {
|
async ARAgingSummary(query: ARAgingSummaryQueryDto) {
|
||||||
const filter = {
|
const filter = {
|
||||||
...getARAgingSummaryDefaultQuery(),
|
...getARAgingSummaryDefaultQuery(),
|
||||||
...query,
|
...query,
|
||||||
@@ -28,12 +28,12 @@ export class ARAgingSummaryService {
|
|||||||
this.ARAgingSummaryRepository.setFilter(filter);
|
this.ARAgingSummaryRepository.setFilter(filter);
|
||||||
await this.ARAgingSummaryRepository.load();
|
await this.ARAgingSummaryRepository.load();
|
||||||
|
|
||||||
// AR aging summary report instance.
|
// A/R aging summary report instance.
|
||||||
const ARAgingSummaryReport = new ARAgingSummarySheet(
|
const ARAgingSummaryReport = new ARAgingSummarySheet(
|
||||||
filter,
|
filter,
|
||||||
this.ARAgingSummaryRepository,
|
this.ARAgingSummaryRepository,
|
||||||
);
|
);
|
||||||
// AR aging summary report data and columns.
|
// A/R aging summary report data and columns.
|
||||||
const data = ARAgingSummaryReport.reportData();
|
const data = ARAgingSummaryReport.reportData();
|
||||||
const columns = ARAgingSummaryReport.reportColumns();
|
const columns = ARAgingSummaryReport.reportColumns();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as R from 'ramda';
|
|||||||
import { isEmpty, sum } from 'lodash';
|
import { isEmpty, sum } from 'lodash';
|
||||||
import { IAgingPeriod } from '../AgingSummary/AgingSummary.types';
|
import { IAgingPeriod } from '../AgingSummary/AgingSummary.types';
|
||||||
import {
|
import {
|
||||||
IARAgingSummaryQuery,
|
|
||||||
IARAgingSummaryCustomer,
|
IARAgingSummaryCustomer,
|
||||||
IARAgingSummaryData,
|
IARAgingSummaryData,
|
||||||
IARAgingSummaryColumns,
|
IARAgingSummaryColumns,
|
||||||
@@ -11,23 +10,31 @@ import {
|
|||||||
import { AgingSummaryReport } from '../AgingSummary/AgingSummary';
|
import { AgingSummaryReport } from '../AgingSummary/AgingSummary';
|
||||||
import { allPassedConditionsPass } from '@/utils/all-conditions-passed';
|
import { allPassedConditionsPass } from '@/utils/all-conditions-passed';
|
||||||
import { ModelObject } from 'objection';
|
import { ModelObject } from 'objection';
|
||||||
import { Customer } from '@/modules/Customers/models/Customer';
|
|
||||||
import { ARAgingSummaryRepository } from './ARAgingSummaryRepository';
|
import { ARAgingSummaryRepository } from './ARAgingSummaryRepository';
|
||||||
|
import { Customer } from '@/modules/Customers/models/Customer';
|
||||||
|
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
|
||||||
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
|
|
||||||
export class ARAgingSummarySheet extends AgingSummaryReport {
|
export class ARAgingSummarySheet extends AgingSummaryReport {
|
||||||
readonly query: IARAgingSummaryQuery;
|
readonly query: ARAgingSummaryQueryDto;
|
||||||
readonly agingPeriods: IAgingPeriod[];
|
readonly agingPeriods: IAgingPeriod[];
|
||||||
readonly repository: ARAgingSummaryRepository;
|
readonly repository: ARAgingSummaryRepository;
|
||||||
|
readonly overdueInvoicesByContactId: Record<
|
||||||
|
string,
|
||||||
|
ModelObject<SaleInvoice>[]
|
||||||
|
>;
|
||||||
|
readonly currentInvoicesByContactId: Record<
|
||||||
|
number,
|
||||||
|
Array<ModelObject<SaleInvoice>>
|
||||||
|
>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor method.
|
* Constructor method.
|
||||||
* @param {number} tenantId
|
* @param {ARAgingSummaryQueryDto} query - Query
|
||||||
* @param {IARAgingSummaryQuery} query
|
* @param {ARAgingSummaryRepository} repository - Repository.
|
||||||
* @param {ICustomer[]} customers
|
|
||||||
* @param {IJournalPoster} journal
|
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
query: IARAgingSummaryQuery,
|
query: ARAgingSummaryQueryDto,
|
||||||
repository: ARAgingSummaryRepository,
|
repository: ARAgingSummaryRepository,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
@@ -36,6 +43,11 @@ export class ARAgingSummarySheet extends AgingSummaryReport {
|
|||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.numberFormat = this.query.numberFormat;
|
this.numberFormat = this.query.numberFormat;
|
||||||
|
|
||||||
|
this.overdueInvoicesByContactId =
|
||||||
|
this.repository.overdueInvoicesByContactId;
|
||||||
|
this.currentInvoicesByContactId =
|
||||||
|
this.repository.currentInvoicesByContactId;
|
||||||
|
|
||||||
// Initializes the aging periods.
|
// Initializes the aging periods.
|
||||||
this.agingPeriods = this.agingRangePeriods(
|
this.agingPeriods = this.agingRangePeriods(
|
||||||
this.query.asDate,
|
this.query.asDate,
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { ARAgingSummaryTable } from './ARAgingSummaryTable';
|
import { ARAgingSummaryTable } from './ARAgingSummaryTable';
|
||||||
import { ARAgingSummaryService } from './ARAgingSummaryService';
|
import { ARAgingSummaryService } from './ARAgingSummaryService';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import {
|
import { IARAgingSummaryTable } from './ARAgingSummary.types';
|
||||||
IARAgingSummaryQuery,
|
import { ARAgingSummaryQueryDto } from './ARAgingSummaryQuery.dto';
|
||||||
IARAgingSummaryTable,
|
|
||||||
} from './ARAgingSummary.types';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ARAgingSummaryTableInjectable {
|
export class ARAgingSummaryTableInjectable {
|
||||||
@@ -12,11 +10,11 @@ export class ARAgingSummaryTableInjectable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves A/R aging summary in table format.
|
* Retrieves A/R aging summary in table format.
|
||||||
* @param {IARAgingSummaryQuery} query - Aging summary query.
|
* @param {ARAgingSummaryQueryDto} query - Aging summary query.
|
||||||
* @returns {Promise<IARAgingSummaryTable>}
|
* @returns {Promise<IARAgingSummaryTable>}
|
||||||
*/
|
*/
|
||||||
public async table(
|
public async table(
|
||||||
query: IARAgingSummaryQuery,
|
query: ARAgingSummaryQueryDto,
|
||||||
): Promise<IARAgingSummaryTable> {
|
): Promise<IARAgingSummaryTable> {
|
||||||
const report = await this.ARAgingSummarySheet.ARAgingSummary(query);
|
const report = await this.ARAgingSummarySheet.ARAgingSummary(query);
|
||||||
const table = new ARAgingSummaryTable(report.data, query, {});
|
const table = new ARAgingSummaryTable(report.data, query, {});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export class CustomerBalanceSummaryPdf {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given customer balance summary sheet table to pdf.
|
* Converts the given customer balance summary sheet table to pdf.
|
||||||
* @param {IAPAgingSummaryQuery} query - Balance sheet query.
|
* @param {ICustomerBalanceSummaryQuery} query - Balance sheet query.
|
||||||
* @returns {Promise<Buffer>}
|
* @returns {Promise<Buffer>}
|
||||||
*/
|
*/
|
||||||
public async pdf(query: ICustomerBalanceSummaryQuery): Promise<Buffer> {
|
public async pdf(query: ICustomerBalanceSummaryQuery): Promise<Buffer> {
|
||||||
|
|||||||
Reference in New Issue
Block a user