draft: AR and AP aging summary report.

This commit is contained in:
a.bouhuolia
2021-01-07 13:48:45 +02:00
parent 7fa6822905
commit 22b2fd5918
17 changed files with 639 additions and 590 deletions

View File

@@ -1,6 +1,75 @@
import moment from 'moment';
import { Inject, Service } from 'typedi';
import TenancyService from 'services/Tenancy/TenancyService';
import APAgingSummarySheet from './APAgingSummarySheet';
@Service()
export default class PayableAgingSummaryService {
@Inject()
tenancy: TenancyService;
@Inject('logger')
logger: any;
/**
* Default report query.
*/
get defaultQuery() {
return {
asDate: moment().format('YYYY-MM-DD'),
agingDaysBefore: 30,
agingPeriods: 3,
numberFormat: {
noCents: false,
divideOn1000: false,
},
vendorsIds: [],
noneZero: false,
}
}
/**
*
* @param {number} tenantId
* @param query
*/
async APAgingSummary(tenantId: number, query) {
const {
vendorRepository,
} = this.tenancy.repositories(tenantId);
const { Bill } = this.tenancy.models(tenantId);
const filter = {
...this.defaultQuery,
...query,
};
this.logger.info('[AR_Aging_Summary] trying to prepairing the report.', {
tenantId, filter,
});
// Settings tenant service.
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
// Retrieve all vendors from the storage.
const vendors = await vendorRepository.all();
// Retrieve all unpaid vendors bills.
const unpaidBills = await Bill.query().modify('unpaid');
// A/P aging summary report instance.
const APAgingSummaryReport = new APAgingSummarySheet(
tenantId,
filter,
vendors,
unpaidBills,
baseCurrency,
);
// A/P aging summary report data and columns.
const data = APAgingSummaryReport.reportData();
const columns = APAgingSummaryReport.reportColumns();
return { data, columns, query: filter };
}
}

View File

@@ -1,12 +1,97 @@
import FinancialSheet from "../FinancialSheet";
import { groupBy, sumBy } from 'lodash';
import AgingSummaryReport from './AgingSummary';
import {
IAPAgingSummaryQuery,
IAgingPeriod,
IBill,
IVendor,
IAPAgingSummaryData,
IAPAgingSummaryVendor,
IAPAgingSummaryColumns
} from 'interfaces';
import { Dictionary } from 'tsyringe/dist/typings/types';
export default class APAgingSummarySheet extends AgingSummaryReport {
readonly tenantId: number;
readonly query: IAPAgingSummaryQuery;
readonly contacts: IVendor[];
readonly unpaidBills: IBill[];
readonly baseCurrency: string;
readonly unpaidInvoicesByContactId: Dictionary<IBill[]>;
readonly agingPeriods: IAgingPeriod[];
constructor(
tenantId: number,
query: IAPAgingSummaryQuery,
vendors: IVendor[],
unpaidBills: IBill[],
baseCurrency: string
) {
super();
export default class APAgingSummarySheet extends FinancialSheet {
this.tenantId = tenantId;
this.query = query;
this.numberFormat = this.query.numberFormat;
this.contacts = vendors;
this.unpaidBills = unpaidBills;
this.baseCurrency = baseCurrency;
this.unpaidInvoicesByContactId = groupBy(unpaidBills, 'vendorId');
reportData() {
// Initializes the aging periods.
this.agingPeriods = this.agingRangePeriods(
this.query.asDate,
this.query.agingDaysBefore,
this.query.agingPeriods
);
this.initContactsAgingPeriods();
this.calcUnpaidInvoicesAgingPeriods();
}
/**
* Retrieve the vendor section data.
* @param {IVendor} vendor
* @return {IAPAgingSummaryData}
*/
protected vendorData(vendor: IVendor): IAPAgingSummaryVendor {
const agingPeriods = this.getContactAgingPeriods(vendor.id);
const amount = sumBy(agingPeriods, 'total');
return {
vendorName: vendor.displayName,
aging: agingPeriods,
total: this.formatTotalAmount(amount),
};
}
/**
* Retrieve vendors aging periods.
* @return {IAPAgingSummaryVendor[]}
*/
private vendorsWalker(): IAPAgingSummaryVendor[] {
return this.contacts
.map((vendor) => this.vendorData(vendor))
.filter(
(vendor: IAPAgingSummaryVendor) =>
!(vendor.total.total === 0 && this.query.noneZero)
);
}
/**
* Retrieve the A/P aging summary report data.
* @return {IAPAgingSummaryData}
*/
public reportData(): IAPAgingSummaryData {
return {
vendors: this.vendorsWalker(),
total: this.getTotalAgingPeriods(),
}
}
/**
* Retrieve the A/P aging summary report columns.
*/
reportColumns(): IAPAgingSummaryColumns {
return this.agingPeriods;
}
}

View File

@@ -2,7 +2,6 @@ import moment from 'moment';
import { Inject, Service } from 'typedi';
import { IARAgingSummaryQuery } from 'interfaces';
import TenancyService from 'services/Tenancy/TenancyService';
import Journal from 'services/Accounting/JournalPoster';
import ARAgingSummarySheet from './ARAgingSummarySheet';
@Service()
@@ -31,63 +30,48 @@ export default class ARAgingSummaryService {
}
/**
* Retreive th accounts receivable aging summary data and columns.
* @param {number} tenantId
* @param query
*
* @param {number} tenantId
* @param query
*/
async ARAgingSummary(tenantId: number, query: IARAgingSummaryQuery) {
const {
customerRepository,
accountRepository,
transactionsRepository,
accountTypeRepository
saleInvoiceRepository
} = this.tenancy.repositories(tenantId);
const { Account } = this.tenancy.models(tenantId);
const filter = {
...this.defaultQuery,
...query,
};
this.logger.info('[AR_Aging_Summary] try to calculate the report.', { tenantId, filter });
this.logger.info('[AR_Aging_Summary] try to calculate the report.', {
tenantId,
filter,
});
// Settings tenant service.
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({ group: 'organization', key: 'base_currency' });
// Retrieve all accounts graph on the storage.
const accountsGraph = await accountRepository.getDependencyGraph();
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
// Retrieve all customers from the storage.
const customers = await customerRepository.all();
// Retrieve AR account type.
const ARType = await accountTypeRepository.getByKey('accounts_receivable');
// Retrieve all due sale invoices.
const dueSaleInvoices = await saleInvoiceRepository.dueInvoices();
// Retreive AR account.
const ARAccount = await Account.query().findOne('account_type_id', ARType.id);
// Retrieve journal transactions based on the given query.
const transactions = await transactionsRepository.journal({
toDate: filter.asDate,
contactType: 'customer',
contactsIds: customers.map(customer => customer.id),
});
// Converts transactions array to journal collection.
const journal = Journal.fromTransactions(transactions, tenantId, accountsGraph);
// AR aging summary report instnace.
// AR aging summary report instance.
const ARAgingSummaryReport = new ARAgingSummarySheet(
tenantId,
filter,
customers,
journal,
ARAccount,
dueSaleInvoices,
baseCurrency
);
// AR aging summary report data and columns.
const data = ARAgingSummaryReport.reportData();
const columns = ARAgingSummaryReport.reportColumns();
return { data, columns };
return { data, columns, query: filter };
}
}
}

View File

@@ -1,154 +1,107 @@
import { groupBy, sumBy, defaultTo } from 'lodash';
import {
ICustomer,
IARAgingSummaryQuery,
ARAgingSummaryCustomer,
IAgingPeriodClosingBalance,
IARAgingSummaryCustomer,
IAgingPeriodTotal,
IJournalPoster,
IAccount,
IAgingPeriod
} from "interfaces";
IAgingPeriod,
ISaleInvoice,
IARAgingSummaryData,
IARAgingSummaryColumns,
} from 'interfaces';
import AgingSummaryReport from './AgingSummary';
import { Dictionary } from 'tsyringe/dist/typings/types';
export default class ARAgingSummarySheet extends AgingSummaryReport {
tenantId: number;
query: IARAgingSummaryQuery;
customers: ICustomer[];
journal: IJournalPoster;
ARAccount: IAccount;
agingPeriods: IAgingPeriod[];
baseCurrency: string;
readonly tenantId: number;
readonly query: IARAgingSummaryQuery;
readonly contacts: ICustomer[];
readonly agingPeriods: IAgingPeriod[];
readonly baseCurrency: string;
readonly dueInvoices: ISaleInvoice[];
readonly unpaidInvoicesByContactId: Dictionary<ISaleInvoice[]>;
/**
* Constructor method.
* @param {number} tenantId
* @param {IARAgingSummaryQuery} query
* @param {ICustomer[]} customers
* @param {IJournalPoster} journal
* @param {number} tenantId
* @param {IARAgingSummaryQuery} query
* @param {ICustomer[]} customers
* @param {IJournalPoster} journal
*/
constructor(
tenantId: number,
query: IARAgingSummaryQuery,
customers: ICustomer[],
journal: IJournalPoster,
ARAccount: IAccount,
baseCurrency: string,
unpaidSaleInvoices: ISaleInvoice[],
baseCurrency: string
) {
super();
this.tenantId = tenantId;
this.customers = customers;
this.contacts = customers;
this.query = query;
this.numberFormat = this.query.numberFormat;
this.journal = journal;
this.ARAccount = ARAccount;
this.baseCurrency = baseCurrency;
this.numberFormat = this.query.numberFormat;
this.unpaidInvoicesByContactId = groupBy(unpaidSaleInvoices, 'customerId');
this.dueInvoices = unpaidSaleInvoices;
this.periodsByContactId = {};
this.initAgingPeriod();
}
/**
* Initializes the aging periods.
*/
private initAgingPeriod() {
// Initializes the aging periods.
this.agingPeriods = this.agingRangePeriods(
this.query.asDate,
this.query.agingDaysBefore,
this.query.agingPeriods
);
}
/**
*
* @param {ICustomer} customer
* @param {IAgingPeriod} agingPeriod
*/
private agingPeriodCloser(
customer: ICustomer,
agingPeriod: IAgingPeriod,
): IAgingPeriodClosingBalance {
// Calculate the trial balance between the given date period.
const agingTrialBalance = this.journal.getContactTrialBalance(
this.ARAccount.id,
customer.id,
'customer',
agingPeriod.fromPeriod,
);
return {
...agingPeriod,
closingBalance: agingTrialBalance.debit,
};
}
/**
*
* @param {ICustomer} customer
*/
private getCustomerAging(customer: ICustomer, totalReceivable: number): IAgingPeriodTotal[] {
const agingClosingBalance = this.agingPeriods
.map((agingPeriod: IAgingPeriod) => this.agingPeriodCloser(customer, agingPeriod));
const aging = this.contactAgingBalance(
agingClosingBalance,
totalReceivable
);
return aging;
this.initContactsAgingPeriods();
this.calcUnpaidInvoicesAgingPeriods();
}
/**
* Mapping aging customer.
* @param {ICustomer} customer -
* @return {ARAgingSummaryCustomer[]}
* @return {IARAgingSummaryCustomer[]}
*/
private customerMapper(customer: ICustomer): ARAgingSummaryCustomer {
// Calculate the trial balance total of the given customer.
const trialBalance = this.journal.getContactTrialBalance(
this.ARAccount.id,
customer.id,
'customer'
);
const amount = trialBalance.balance;
const formattedAmount = this.formatNumber(amount);
const currencyCode = this.baseCurrency;
private customerData(customer: ICustomer): IARAgingSummaryCustomer {
const agingPeriods = this.getContactAgingPeriods(customer.id);
const amount = sumBy(agingPeriods, 'total');
return {
customerName: customer.displayName,
aging: this.getCustomerAging(customer, trialBalance.balance),
total: {
amount,
formattedAmount,
currencyCode,
},
aging: agingPeriods,
total: this.formatTotalAmount(amount),
};
}
/**
* Retrieve customers walker.
* @param {ICustomer[]} customers
* @return {ARAgingSummaryCustomer[]}
* Retrieve customers report.
* @param {ICustomer[]} customers
* @return {IARAgingSummaryCustomer[]}
*/
private customersWalker(customers: ICustomer[]): ARAgingSummaryCustomer[] {
return customers
.map((customer: ICustomer) => this.customerMapper(customer))
// Filter customers that have zero total amount when `noneZero` is on.
.filter((customer: ARAgingSummaryCustomer) =>
!(customer.total.amount === 0 && this.query.noneZero),
private customersWalker(): IARAgingSummaryCustomer[] {
return this.contacts
.map((customer) => this.customerData(customer))
.filter(
(customer: IARAgingSummaryCustomer) =>
!(customer.total.total === 0 && this.query.noneZero)
);
}
/**
* Retrieve AR. aging summary report data.
* Retrieve A/R aging summary report data.
* @return {IARAgingSummaryData}
*/
public reportData() {
return this.customersWalker(this.customers);
public reportData(): IARAgingSummaryData {
return {
customers: this.customersWalker(),
total: this.getTotalAgingPeriods(),
};
}
/**
* Retrieve AR aging summary report columns.
* @return {IARAgingSummaryColumns}
*/
reportColumns() {
return []
public reportColumns(): IARAgingSummaryColumns {
return this.agingPeriods;
}
}
}

View File

@@ -0,0 +1,54 @@
import moment from 'moment';
import {
IAgingPeriod,
} from 'interfaces';
import FinancialSheet from "../FinancialSheet";
export default abstract class AgingReport extends FinancialSheet{
/**
* Retrieve the aging periods range.
* @param {string} asDay
* @param {number} agingDaysBefore
* @param {number} agingPeriodsFreq
*/
agingRangePeriods(
asDay: string,
agingDaysBefore: number,
agingPeriodsFreq: number
): IAgingPeriod[] {
const totalAgingDays = agingDaysBefore * agingPeriodsFreq;
const startAging = moment(asDay).startOf('day');
const endAging = startAging
.clone()
.subtract(totalAgingDays, 'days')
.endOf('day');
const agingPeriods: IAgingPeriod[] = [];
const startingAging = startAging.clone();
let beforeDays = 1;
let toDays = 0;
while (startingAging > endAging) {
const currentAging = startingAging.clone();
startingAging.subtract(agingDaysBefore, 'days').endOf('day');
toDays += agingDaysBefore;
agingPeriods.push({
fromPeriod: moment(currentAging).format('YYYY-MM-DD'),
toPeriod: moment(startingAging).format('YYYY-MM-DD'),
beforeDays: beforeDays === 1 ? 0 : beforeDays,
toDays: toDays,
...(startingAging.valueOf() === endAging.valueOf()
? {
toPeriod: null,
toDays: null,
}
: {}),
});
beforeDays += agingDaysBefore;
}
return agingPeriods;
}
}

View File

@@ -1,75 +1,158 @@
import moment from 'moment';
import { omit, reverse } from 'lodash';
import { IAgingPeriod, IAgingPeriodClosingBalance, IAgingPeriodTotal } from 'interfaces';
import FinancialSheet from '../FinancialSheet';
import { defaultTo } from 'lodash';
import {
IAgingPeriod,
ISaleInvoice,
IBill,
IAgingPeriodTotal,
IContact,
} from 'interfaces';
import AgingReport from './AgingReport';
import { Dictionary } from 'tsyringe/dist/typings/types';
export default class AgingSummaryReport extends FinancialSheet{
export default abstract class AgingSummaryReport extends AgingReport {
protected readonly contacts: IContact[];
protected readonly agingPeriods: IAgingPeriod[] = [];
protected readonly baseCurrency: string;
protected readonly unpaidInvoices: (ISaleInvoice | IBill)[];
readonly unpaidInvoicesByContactId: Dictionary<
(ISaleInvoice | IBill)[]
>;
protected periodsByContactId: {
[key: number]: (IAgingPeriod & IAgingPeriodTotal)[];
} = {};
/**
*
* @param {Array} agingPeriods
* @param {Numeric} customerBalance
* Setes initial aging periods to the given customer id.
* @param {number} customerId - Customer id.
*/
contactAgingBalance(
agingPeriods: IAgingPeriodClosingBalance[],
receivableTotalCredit: number,
): IAgingPeriodTotal[] {
let prevAging = 0;
let receivableCredit = receivableTotalCredit;
let diff = receivableCredit;
const periods = reverse(agingPeriods).map((agingPeriod) => {
const agingAmount = (agingPeriod.closingBalance - prevAging);
const subtract = Math.min(diff, agingAmount);
diff -= Math.min(agingAmount, diff);
const total = Math.max(agingAmount - subtract, 0);
const output = {
...omit(agingPeriod, ['closingBalance']),
total,
};
prevAging = agingPeriod.closingBalance;
return output;
});
return reverse(periods);
protected setInitialAgingPeriods(contactId: number): void {
this.periodsByContactId[contactId] = this.agingPeriods.map(
(agingPeriod) => ({
...agingPeriod,
...this.formatTotalAmount(0),
})
);
}
/**
*
* @param {*} asDay
* @param {*} agingDaysBefore
* @param {*} agingPeriodsFreq
* Calculates the given contact aging periods.
* @param {ICustomer} customer
* @return {(IAgingPeriod & IAgingPeriodTotal)[]}
*/
agingRangePeriods(asDay, agingDaysBefore, agingPeriodsFreq): IAgingPeriod[] {
const totalAgingDays = agingDaysBefore * agingPeriodsFreq;
const startAging = moment(asDay).startOf('day');
const endAging = startAging.clone().subtract('days', totalAgingDays).endOf('day');
protected getContactAgingPeriods(
contactId: number
): (IAgingPeriod & IAgingPeriodTotal)[] {
return defaultTo(this.periodsByContactId[contactId], []);
}
const agingPeriods: IAgingPeriod[] = [];
const startingAging = startAging.clone();
let beforeDays = 1;
let toDays = 0;
while (startingAging > endAging) {
const currentAging = startingAging.clone();
startingAging.subtract('days', agingDaysBefore).endOf('day');
toDays += agingDaysBefore;
agingPeriods.push({
fromPeriod: moment(currentAging).toDate(),
toPeriod: moment(startingAging).toDate(),
beforeDays: beforeDays === 1 ? 0 : beforeDays,
toDays: toDays,
...(startingAging.valueOf() === endAging.valueOf()) ? {
toPeriod: null,
toDays: null,
} : {},
});
beforeDays += agingDaysBefore;
/**
* Sets the customer aging due amount to the table.
* @param {number} customerId - Customer id.
* @param {number} dueAmount - Due amount.
* @param {number} overdueDays - Overdue days.
*/
protected setContactAgingDueAmount(
customerId: number,
dueAmount: number,
overdueDays: number
): void {
if (!this.periodsByContactId[customerId]) {
this.setInitialAgingPeriods(customerId);
}
return agingPeriods;
const agingPeriods = this.periodsByContactId[customerId];
const newAgingPeriods = agingPeriods.map((agingPeriod) => {
const isInAgingPeriod =
agingPeriod.beforeDays < overdueDays &&
agingPeriod.toDays > overdueDays;
return {
...agingPeriod,
total: isInAgingPeriod
? agingPeriod.total + dueAmount
: agingPeriod.total,
};
});
this.periodsByContactId[customerId] = newAgingPeriods;
}
}
/**
* Retrieve the aging period total object.
* @param {number} amount
* @return {IAgingPeriodTotal}
*/
protected formatTotalAmount(amount: number): IAgingPeriodTotal {
return {
total: amount,
formattedTotal: this.formatNumber(amount),
currencyCode: this.baseCurrency,
};
}
/**
* Calculates the total of the aging period by the given index.
* @param {number} index
* @return {number}
*/
protected getTotalAgingPeriodByIndex(index: number): number {
return this.contacts.reduce((acc, customer) => {
const periods = this.getContactAgingPeriods(customer.id);
const totalPeriod = periods[index] ? periods[index].total : 0;
return acc + totalPeriod;
}, 0);
}
/**
* Sets the initial aging periods to the all customers.
*/
protected initContactsAgingPeriods(): void {
this.contacts.forEach((contact) => {
this.setInitialAgingPeriods(contact.id);
});
}
/**
* Retrieve the due invoices by the given customer id.
* @param {number} customerId -
* @return {ISaleInvoice[]}
*/
protected getUnpaidInvoicesByContactId(
contactId: number
): (ISaleInvoice | IBill)[] {
return defaultTo(this.unpaidInvoicesByContactId[contactId], []);
}
/**
* Retrieve total aging periods of the report.
* @return {(IAgingPeriodTotal & IAgingPeriod)[]}
*/
protected getTotalAgingPeriods(): (IAgingPeriodTotal & IAgingPeriod)[] {
return this.agingPeriods.map((agingPeriod, index) => {
const total = this.getTotalAgingPeriodByIndex(index);
return {
...agingPeriod,
...this.formatTotalAmount(total),
};
});
}
/**
* 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
);
});
});
}
}

View File

@@ -14,13 +14,13 @@ import BalanceSheetStructure from 'data/BalanceSheetStructure';
import FinancialSheet from '../FinancialSheet';
export default class BalanceSheetStatement extends FinancialSheet {
query: IBalanceSheetQuery;
tenantId: number;
accounts: IAccount & { type: IAccountType }[];
journalFinancial: IJournalPoster;
comparatorDateType: string;
dateRangeSet: string[];
baseCurrency: string;
readonly query: IBalanceSheetQuery;
readonly tenantId: number;
readonly accounts: IAccount & { type: IAccountType }[];
readonly journalFinancial: IJournalPoster;
readonly comparatorDateType: string;
readonly dateRangeSet: string[];
readonly baseCurrency: string;
/**
* Constructor method.

View File

@@ -1,10 +1,10 @@
import { Service, Inject } from "typedi";
import { Service, Inject } from 'typedi';
import moment from 'moment';
import { ServiceError } from "exceptions";
import { ServiceError } from 'exceptions';
import { difference } from 'lodash';
import { IGeneralLedgerSheetQuery } from 'interfaces';
import TenancyService from 'services/Tenancy/TenancyService';
import Journal from "services/Accounting/JournalPoster";
import Journal from 'services/Accounting/JournalPoster';
import GeneralLedgerSheet from 'services/FinancialStatements/GeneralLedger/GeneralLedger';
const ERRORS = {
@@ -39,8 +39,8 @@ export default class GeneralLedgerService {
/**
* Validates accounts existance on the storage.
* @param {number} tenantId
* @param {number[]} accountsIds
* @param {number} tenantId
* @param {number[]} accountsIds
*/
async validateAccountsExistance(tenantId: number, accountsIds: number[]) {
const { Account } = this.tenancy.models(tenantId);
@@ -49,35 +49,42 @@ export default class GeneralLedgerService {
const storedAccountsIds = storedAccounts.map((a) => a.id);
if (difference(accountsIds, storedAccountsIds).length > 0) {
throw new ServiceError(ERRORS.ACCOUNTS_NOT_FOUND)
throw new ServiceError(ERRORS.ACCOUNTS_NOT_FOUND);
}
}
/**
* Retrieve general ledger report statement.
* ----------
* @param {number} tenantId
* @param {IGeneralLedgerSheetQuery} query
* @param {number} tenantId
* @param {IGeneralLedgerSheetQuery} query
* @return {IGeneralLedgerStatement}
*/
async generalLedger(tenantId: number, query: IGeneralLedgerSheetQuery):
Promise<{
data: any,
query: IGeneralLedgerSheetQuery,
}> {
async generalLedger(
tenantId: number,
query: IGeneralLedgerSheetQuery
): Promise<{
data: any;
query: IGeneralLedgerSheetQuery;
}> {
const {
accountRepository,
transactionsRepository,
} = this.tenancy.repositories(tenantId);
const settings = this.tenancy.settings(tenantId);
const filter = {
...this.defaultQuery,
...query,
};
this.logger.info('[general_ledger] trying to calculate the report.', { tenantId, filter })
const settings = this.tenancy.settings(tenantId);
const baseCurrency = settings.get({ group: 'organization', key: 'base_currency' });
this.logger.info('[general_ledger] trying to calculate the report.', {
tenantId,
filter,
});
const baseCurrency = settings.get({
group: 'organization',
key: 'base_currency',
});
// Retrieve all accounts from the storage.
const accounts = await accountRepository.all('type');
@@ -98,12 +105,22 @@ export default class GeneralLedgerService {
toDate: filter.toDate,
sumationCreditDebit: true,
});
// Transform array transactions to journal collection.
const transactionsJournal = Journal.fromTransactions(transactions, tenantId, accountsGraph);
const openingTransJournal = Journal.fromTransactions(openingBalanceTrans, tenantId, accountsGraph);
const closingTransJournal = Journal.fromTransactions(closingBalanceTrans, tenantId, accountsGraph);
const transactionsJournal = Journal.fromTransactions(
transactions,
tenantId,
accountsGraph
);
const openingTransJournal = Journal.fromTransactions(
openingBalanceTrans,
tenantId,
accountsGraph
);
const closingTransJournal = Journal.fromTransactions(
closingBalanceTrans,
tenantId,
accountsGraph
);
// General ledger report instance.
const generalLedgerInstance = new GeneralLedgerSheet(
tenantId,
@@ -120,6 +137,6 @@ export default class GeneralLedgerService {
return {
data: reportData,
query: filter,
}
};
}
}
}