mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
fix: vendor summary balance and transaction report.
This commit is contained in:
@@ -2,6 +2,7 @@ import { INumberFormatQuery } from './FinancialStatements';
|
|||||||
|
|
||||||
export interface IVendorBalanceSummaryQuery {
|
export interface IVendorBalanceSummaryQuery {
|
||||||
asDate: Date;
|
asDate: Date;
|
||||||
|
vendorsIds: number[],
|
||||||
numberFormat: INumberFormatQuery;
|
numberFormat: INumberFormatQuery;
|
||||||
comparison: {
|
comparison: {
|
||||||
percentageOfColumn: boolean;
|
percentageOfColumn: boolean;
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export class ContactBalanceSummaryReport extends FinancialSheet {
|
|||||||
protected getTotalFormat(amount: number): IContactBalanceSummaryAmount {
|
protected getTotalFormat(amount: number): IContactBalanceSummaryAmount {
|
||||||
return {
|
return {
|
||||||
amount,
|
amount,
|
||||||
formattedAmount: this.formatNumber(amount, { money: true }),
|
formattedAmount: this.formatTotalNumber(amount, { money: true }),
|
||||||
currencyCode: this.baseCurrency,
|
currencyCode: this.baseCurrency,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { sumBy } from 'lodash';
|
|
||||||
import {
|
import {
|
||||||
ITransactionsByCustomersTransaction,
|
ITransactionsByCustomersTransaction,
|
||||||
ITransactionsByCustomersFilter,
|
ITransactionsByCustomersFilter,
|
||||||
ITransactionsByCustomersCustomer,
|
ITransactionsByCustomersCustomer,
|
||||||
ITransactionsByCustomersAmount,
|
|
||||||
ITransactionsByCustomersData,
|
ITransactionsByCustomersData,
|
||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
IAccountTransaction,
|
|
||||||
ICustomer,
|
ICustomer,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import TransactionsByContact from '../TransactionsByContact/TransactionsByContact';
|
import TransactionsByContact from '../TransactionsByContact/TransactionsByContact';
|
||||||
|
|||||||
@@ -173,13 +173,10 @@ export default class TransactionsByCustomersService
|
|||||||
filter,
|
filter,
|
||||||
baseCurrency
|
baseCurrency
|
||||||
);
|
);
|
||||||
const reportData = reportInstance.reportData();
|
|
||||||
|
|
||||||
const reportColumns = reportInstance.reportColumns();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: reportData,
|
data: reportInstance.reportData(),
|
||||||
columns: reportColumns,
|
columns: reportInstance.reportColumns(),
|
||||||
query: filter,
|
query: filter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import {
|
|||||||
ITransactionsByVendorsFilter,
|
ITransactionsByVendorsFilter,
|
||||||
ITransactionsByVendorsTransaction,
|
ITransactionsByVendorsTransaction,
|
||||||
ITransactionsByVendorsVendor,
|
ITransactionsByVendorsVendor,
|
||||||
ITransactionsByVendorsAmount,
|
|
||||||
ITransactionsByVendorsData,
|
ITransactionsByVendorsData,
|
||||||
IAccountTransaction,
|
ILedger,
|
||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
IVendor
|
IVendor
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
@@ -18,6 +17,8 @@ export default class TransactionsByVendors extends TransactionsByContact{
|
|||||||
readonly filter: ITransactionsByVendorsFilter;
|
readonly filter: ITransactionsByVendorsFilter;
|
||||||
readonly baseCurrency: string;
|
readonly baseCurrency: string;
|
||||||
readonly numberFormat: INumberFormatQuery;
|
readonly numberFormat: INumberFormatQuery;
|
||||||
|
readonly accountsGraph: any;
|
||||||
|
readonly ledger: ILedger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor method.
|
* Constructor method.
|
||||||
@@ -27,14 +28,16 @@ export default class TransactionsByVendors extends TransactionsByContact{
|
|||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
vendors: IVendor[],
|
vendors: IVendor[],
|
||||||
transactionsByContact: Map<number, IAccountTransaction[]>,
|
accountsGraph: any,
|
||||||
|
ledger: ILedger,
|
||||||
filter: ITransactionsByVendorsFilter,
|
filter: ITransactionsByVendorsFilter,
|
||||||
baseCurrency: string
|
baseCurrency: string
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.contacts = vendors;
|
this.contacts = vendors;
|
||||||
this.transactionsByContact = transactionsByContact;
|
this.accountsGraph = accountsGraph;
|
||||||
|
this.ledger = ledger;
|
||||||
this.baseCurrency = baseCurrency;
|
this.baseCurrency = baseCurrency;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
this.numberFormat = this.filter.numberFormat;
|
this.numberFormat = this.filter.numberFormat;
|
||||||
@@ -50,12 +53,17 @@ export default class TransactionsByVendors extends TransactionsByContact{
|
|||||||
vendorId: number,
|
vendorId: number,
|
||||||
openingBalance: number
|
openingBalance: number
|
||||||
): ITransactionsByVendorsTransaction[] {
|
): ITransactionsByVendorsTransaction[] {
|
||||||
const transactions = this.transactionsByContact.get(vendorId + '') || [];
|
const openingBalanceLedger = this.ledger
|
||||||
|
.whereContactId(vendorId)
|
||||||
|
.whereFromDate(this.filter.fromDate)
|
||||||
|
.whereToDate(this.filter.toDate);
|
||||||
|
|
||||||
|
const openingEntries = openingBalanceLedger.getEntries();
|
||||||
|
|
||||||
return R.compose(
|
return R.compose(
|
||||||
R.curry(this.contactTransactionRunningBalance)(openingBalance),
|
R.curry(this.contactTransactionRunningBalance)(openingBalance),
|
||||||
R.map(this.contactTransactionMapper.bind(this))
|
R.map(this.contactTransactionMapper.bind(this))
|
||||||
).bind(this)(transactions);
|
).bind(this)(openingEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,17 +74,17 @@ export default class TransactionsByVendors extends TransactionsByContact{
|
|||||||
private vendorMapper(
|
private vendorMapper(
|
||||||
vendor: IVendor
|
vendor: IVendor
|
||||||
): ITransactionsByVendorsVendor {
|
): ITransactionsByVendorsVendor {
|
||||||
const openingBalance = this.getContactOpeningBalance(1);
|
const openingBalance = this.getContactOpeningBalance(vendor.id);
|
||||||
const transactions = this.vendorTransactions(vendor.id, openingBalance);
|
const transactions = this.vendorTransactions(vendor.id, openingBalance);
|
||||||
const closingBalance = this.getContactClosingBalance(transactions, 0);
|
const closingBalance = this.getContactClosingBalance(transactions, openingBalance);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vendorName: vendor.displayName,
|
vendorName: vendor.displayName,
|
||||||
openingBalance: this.getContactAmount(
|
openingBalance: this.getTotalAmountMeta(
|
||||||
openingBalance,
|
openingBalance,
|
||||||
vendor.currencyCode
|
vendor.currencyCode
|
||||||
),
|
),
|
||||||
closingBalance: this.getContactAmount(
|
closingBalance: this.getTotalAmountMeta(
|
||||||
closingBalance,
|
closingBalance,
|
||||||
vendor.currencyCode
|
vendor.currencyCode
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import { Inject } from 'typedi';
|
import { Inject } from 'typedi';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { groupBy } from 'lodash';
|
import * as R from 'ramda';
|
||||||
|
import { map } from 'lodash';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import {
|
import {
|
||||||
|
IVendor,
|
||||||
ITransactionsByVendorsService,
|
ITransactionsByVendorsService,
|
||||||
ITransactionsByVendorsFilter,
|
ITransactionsByVendorsFilter,
|
||||||
ITransactionsByVendorsStatement,
|
ITransactionsByVendorsStatement,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import TransactionsByVendor from './TransactionsByVendor';
|
import TransactionsByVendor from './TransactionsByVendor';
|
||||||
|
import { ACCOUNT_TYPE } from 'data/AccountTypes';
|
||||||
|
import Ledger from 'services/Accounting/Ledger';
|
||||||
|
|
||||||
export default class TransactionsByVendorsService
|
export default class TransactionsByVendorsService
|
||||||
implements ITransactionsByVendorsService {
|
implements ITransactionsByVendorsService {
|
||||||
@@ -40,6 +44,100 @@ export default class TransactionsByVendorsService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the report vendors.
|
||||||
|
* @param tenantId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private getReportVendors(tenantId: number): Promise<IVendor[]> {
|
||||||
|
const { Vendor } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
return Vendor.query().orderBy('displayName');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the accounts receivable.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
private async getPayableAccounts(tenantId: number) {
|
||||||
|
const { Account } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const accounts = await Account.query().where(
|
||||||
|
'accountType',
|
||||||
|
ACCOUNT_TYPE.ACCOUNTS_PAYABLE
|
||||||
|
);
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the customers opening balance transactions.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} openingDate
|
||||||
|
* @param {number} customersIds
|
||||||
|
* @returns {}
|
||||||
|
*/
|
||||||
|
private async getVendorsOpeningBalance(
|
||||||
|
tenantId: number,
|
||||||
|
openingDate: Date,
|
||||||
|
customersIds?: number[]
|
||||||
|
): Promise<ILedgerEntry[]> {
|
||||||
|
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const payableAccounts = await this.getPayableAccounts(tenantId);
|
||||||
|
const payableAccountsIds = map(payableAccounts, 'id');
|
||||||
|
|
||||||
|
const openingTransactions = await AccountTransaction.query().modify(
|
||||||
|
'contactsOpeningBalance',
|
||||||
|
openingDate,
|
||||||
|
payableAccountsIds,
|
||||||
|
customersIds
|
||||||
|
);
|
||||||
|
return R.compose(
|
||||||
|
R.map(R.assoc('date', openingDate)),
|
||||||
|
R.map(R.assoc('accountNormal', 'credit'))
|
||||||
|
)(openingTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Date|string} openingDate
|
||||||
|
* @param {number[]} customersIds
|
||||||
|
*/
|
||||||
|
async getVendorsPeriodTransactions(
|
||||||
|
tenantId: number,
|
||||||
|
fromDate: Date,
|
||||||
|
toDate: Date
|
||||||
|
): Promise<ILedgerEntry[]> {
|
||||||
|
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
const receivableAccounts = await this.getPayableAccounts(tenantId);
|
||||||
|
const receivableAccountsIds = map(receivableAccounts, 'id');
|
||||||
|
|
||||||
|
const transactions = await AccountTransaction.query().onBuild((query) => {
|
||||||
|
// Filter by date.
|
||||||
|
query.modify('filterDateRange', fromDate, toDate);
|
||||||
|
|
||||||
|
// Filter by customers.
|
||||||
|
query.whereNot('contactId', null);
|
||||||
|
|
||||||
|
// Filter by accounts.
|
||||||
|
query.whereIn('accountId', receivableAccountsIds);
|
||||||
|
});
|
||||||
|
|
||||||
|
return R.compose(R.map(R.assoc('accountNormal', 'credit')))(transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getReportTransactions(tenantId: number, fromDate: Date, toDate: Date) {
|
||||||
|
const openingBalanceDate = moment(fromDate).subtract(1, 'days').toDate();
|
||||||
|
|
||||||
|
return [
|
||||||
|
...(await this.getVendorsOpeningBalance(tenantId, openingBalanceDate)),
|
||||||
|
...(await this.getVendorsPeriodTransactions(tenantId, fromDate, toDate)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve transactions by by the customers.
|
* Retrieve transactions by by the customers.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -50,8 +148,7 @@ export default class TransactionsByVendorsService
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
query: ITransactionsByVendorsFilter
|
query: ITransactionsByVendorsFilter
|
||||||
): Promise<ITransactionsByVendorsStatement> {
|
): Promise<ITransactionsByVendorsStatement> {
|
||||||
const { transactionsRepository } = this.tenancy.repositories(tenantId);
|
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||||
const { Vendor } = this.tenancy.models(tenantId);
|
|
||||||
|
|
||||||
// Settings tenant service.
|
// Settings tenant service.
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
@@ -60,37 +157,35 @@ export default class TransactionsByVendorsService
|
|||||||
key: 'base_currency',
|
key: 'base_currency',
|
||||||
});
|
});
|
||||||
|
|
||||||
const filter = {
|
const filter = { ...this.defaultQuery, ...query };
|
||||||
...this.defaultQuery,
|
|
||||||
...query,
|
|
||||||
};
|
|
||||||
const vendors = await Vendor.query().orderBy('displayName');
|
|
||||||
|
|
||||||
// Retrieve all journal transactions based on the given query.
|
// Retrieve the report vendors.
|
||||||
const transactions = await transactionsRepository.journal({
|
const vendors = await this.getReportVendors(tenantId);
|
||||||
fromDate: query.fromDate,
|
|
||||||
toDate: query.toDate,
|
// Retrieve the accounts graph.
|
||||||
});
|
const accountsGraph = await accountRepository.getDependencyGraph();
|
||||||
// Transactions map by contact id.
|
|
||||||
const transactionsMap = new Map(
|
// Journal transactions.
|
||||||
Object.entries(groupBy(transactions, 'contactId'))
|
const journalTransactions = await this.getReportTransactions(
|
||||||
|
tenantId,
|
||||||
|
filter.fromDate,
|
||||||
|
filter.toDate
|
||||||
);
|
);
|
||||||
|
// Ledger collection.
|
||||||
|
const journal = new Ledger(journalTransactions);
|
||||||
|
|
||||||
// Transactions by customers data mapper.
|
// Transactions by customers data mapper.
|
||||||
const reportInstance = new TransactionsByVendor(
|
const reportInstance = new TransactionsByVendor(
|
||||||
vendors,
|
vendors,
|
||||||
transactionsMap,
|
accountsGraph,
|
||||||
|
journal,
|
||||||
filter,
|
filter,
|
||||||
baseCurrency
|
baseCurrency
|
||||||
);
|
);
|
||||||
// Retrieve the report data.
|
|
||||||
const reportData = reportInstance.reportData();
|
|
||||||
|
|
||||||
// Retireve the report columns.
|
|
||||||
const reportColumns = reportInstance.reportColumns();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: reportData,
|
data: reportInstance.reportData(),
|
||||||
columns: reportColumns,
|
columns: reportInstance.reportColumns(),
|
||||||
|
query: filter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import {
|
import {
|
||||||
IJournalPoster,
|
ILedger,
|
||||||
IVendor,
|
IVendor,
|
||||||
IVendorBalanceSummaryVendor,
|
IVendorBalanceSummaryVendor,
|
||||||
IVendorBalanceSummaryQuery,
|
IVendorBalanceSummaryQuery,
|
||||||
IVendorBalanceSummaryData,
|
IVendorBalanceSummaryData,
|
||||||
IVendorBalanceSummaryTotal,
|
|
||||||
INumberFormatQuery,
|
INumberFormatQuery,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { ContactBalanceSummaryReport } from '../ContactBalanceSummary/ContactBalanceSummary';
|
import { ContactBalanceSummaryReport } from '../ContactBalanceSummary/ContactBalanceSummary';
|
||||||
|
|
||||||
export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport {
|
export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport {
|
||||||
readonly payableLedger: IJournalPoster;
|
readonly ledger: ILedger;
|
||||||
readonly baseCurrency: string;
|
readonly baseCurrency: string;
|
||||||
readonly vendors: IVendor[];
|
readonly vendors: IVendor[];
|
||||||
readonly filter: IVendorBalanceSummaryQuery;
|
readonly filter: IVendorBalanceSummaryQuery;
|
||||||
@@ -25,14 +24,14 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport {
|
|||||||
* @param {string} baseCurrency
|
* @param {string} baseCurrency
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
payableLedger: IJournalPoster,
|
ledger: ILedger,
|
||||||
vendors: IVendor[],
|
vendors: IVendor[],
|
||||||
filter: IVendorBalanceSummaryQuery,
|
filter: IVendorBalanceSummaryQuery,
|
||||||
baseCurrency: string
|
baseCurrency: string
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.payableLedger = payableLedger;
|
this.ledger = ledger;
|
||||||
this.baseCurrency = baseCurrency;
|
this.baseCurrency = baseCurrency;
|
||||||
this.vendors = vendors;
|
this.vendors = vendors;
|
||||||
this.filter = filter;
|
this.filter = filter;
|
||||||
@@ -45,11 +44,13 @@ export class VendorBalanceSummaryReport extends ContactBalanceSummaryReport {
|
|||||||
* @returns {IVendorBalanceSummaryVendor}
|
* @returns {IVendorBalanceSummaryVendor}
|
||||||
*/
|
*/
|
||||||
private vendorMapper(vendor: IVendor): IVendorBalanceSummaryVendor {
|
private vendorMapper(vendor: IVendor): IVendorBalanceSummaryVendor {
|
||||||
const balance = this.payableLedger.getContactBalance(null, vendor.id);
|
const closingBalance = this.ledger
|
||||||
|
.whereContactId(vendor.id)
|
||||||
|
.getClosingBalance();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vendorName: vendor.displayName,
|
vendorName: vendor.displayName,
|
||||||
total: this.getContactTotalFormat(balance),
|
total: this.getContactTotalFormat(closingBalance),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import { Inject } from 'typedi';
|
import { Inject } from 'typedi';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { map } from 'lodash';
|
||||||
|
import * as R from 'ramda';
|
||||||
import TenancyService from 'services/Tenancy/TenancyService';
|
import TenancyService from 'services/Tenancy/TenancyService';
|
||||||
import Journal from 'services/Accounting/JournalPoster';
|
|
||||||
import {
|
import {
|
||||||
|
IVendor,
|
||||||
IVendorBalanceSummaryService,
|
IVendorBalanceSummaryService,
|
||||||
IVendorBalanceSummaryQuery,
|
IVendorBalanceSummaryQuery,
|
||||||
IVendorBalanceSummaryStatement,
|
IVendorBalanceSummaryStatement,
|
||||||
} from 'interfaces';
|
} from 'interfaces';
|
||||||
import { VendorBalanceSummaryReport } from './VendorBalanceSummary';
|
import { VendorBalanceSummaryReport } from './VendorBalanceSummary';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import { ACCOUNT_TYPE } from 'data/AccountTypes';
|
||||||
|
import Ledger from 'services/Accounting/Ledger';
|
||||||
|
|
||||||
export default class VendorBalanceSummaryService
|
export default class VendorBalanceSummaryService
|
||||||
implements IVendorBalanceSummaryService {
|
implements IVendorBalanceSummaryService {
|
||||||
|
|
||||||
@Inject()
|
@Inject()
|
||||||
tenancy: TenancyService;
|
tenancy: TenancyService;
|
||||||
|
|
||||||
@@ -40,6 +44,62 @@ export default class VendorBalanceSummaryService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the report vendors.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number[]} vendorsIds - Vendors ids.
|
||||||
|
* @returns {IVendor[]}
|
||||||
|
*/
|
||||||
|
getReportVendors(
|
||||||
|
tenantId: number,
|
||||||
|
vendorsIds?: number[]
|
||||||
|
): Promise<IVendor[]> {
|
||||||
|
const { Vendor } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
return Vendor.query()
|
||||||
|
.orderBy('displayName')
|
||||||
|
.onBuild((query) => {
|
||||||
|
if (!isEmpty(vendorsIds)) {
|
||||||
|
query.whereIn('id', vendorsIds);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getPayableAccounts(tenantId: number) {
|
||||||
|
const { Account } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
return Account.query().where('accountType', ACCOUNT_TYPE.ACCOUNTS_PAYABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve
|
||||||
|
* @param tenantId
|
||||||
|
* @param asDate
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async getReportVendorsTransactions(tenantId: number, asDate: Date | string) {
|
||||||
|
const { AccountTransaction } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
// Retrieve payable accounts .
|
||||||
|
const payableAccounts = await this.getPayableAccounts(tenantId);
|
||||||
|
const payableAccountsIds = map(payableAccounts, 'id');
|
||||||
|
|
||||||
|
// Retrieve the customers transactions of A/R accounts.
|
||||||
|
const customersTranasctions = await AccountTransaction.query().onBuild(
|
||||||
|
(query) => {
|
||||||
|
query.whereIn('accountId', payableAccountsIds);
|
||||||
|
query.modify('filterDateRange', null, asDate);
|
||||||
|
query.groupBy('contactId');
|
||||||
|
query.sum('credit as credit');
|
||||||
|
query.sum('debit as debit');
|
||||||
|
query.select('contactId');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const commonProps = { accountNormal: 'credit', date: asDate };
|
||||||
|
|
||||||
|
return R.map(R.merge(commonProps))(customersTranasctions);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the statment of customer balance summary report.
|
* Retrieve the statment of customer balance summary report.
|
||||||
* @param {number} tenantId - Tenant id.
|
* @param {number} tenantId - Tenant id.
|
||||||
@@ -50,60 +110,44 @@ export default class VendorBalanceSummaryService
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
query: IVendorBalanceSummaryQuery
|
query: IVendorBalanceSummaryQuery
|
||||||
): Promise<IVendorBalanceSummaryStatement> {
|
): Promise<IVendorBalanceSummaryStatement> {
|
||||||
const {
|
|
||||||
accountRepository,
|
|
||||||
transactionsRepository,
|
|
||||||
} = this.tenancy.repositories(tenantId);
|
|
||||||
|
|
||||||
const { Vendor } = this.tenancy.models(tenantId);
|
|
||||||
|
|
||||||
// Settings tenant service.
|
// Settings tenant service.
|
||||||
const settings = this.tenancy.settings(tenantId);
|
const settings = this.tenancy.settings(tenantId);
|
||||||
const baseCurrency = settings.get({
|
const baseCurrency = settings.get({
|
||||||
group: 'organization', key: 'base_currency',
|
group: 'organization',
|
||||||
|
key: 'base_currency',
|
||||||
});
|
});
|
||||||
|
|
||||||
const filter = {
|
const filter = { ...this.defaultQuery, ...query };
|
||||||
...this.defaultQuery,
|
this.logger.info(
|
||||||
...query,
|
'[customer_balance_summary] trying to calculate the report.',
|
||||||
};
|
{
|
||||||
this.logger.info('[customer_balance_summary] trying to calculate the report.', {
|
filter,
|
||||||
filter,
|
tenantId,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Retrieve the vendors transactions.
|
||||||
|
const vendorsTransactions = await this.getReportVendorsTransactions(
|
||||||
tenantId,
|
tenantId,
|
||||||
});
|
query.asDate
|
||||||
// Retrieve all accounts on the storage.
|
|
||||||
const accounts = await accountRepository.all();
|
|
||||||
const accountsGraph = await accountRepository.getDependencyGraph();
|
|
||||||
|
|
||||||
// Retrieve all journal transactions based on the given query.
|
|
||||||
const transactions = await transactionsRepository.journal({
|
|
||||||
toDate: query.asDate,
|
|
||||||
});
|
|
||||||
// Transform transactions to journal collection.
|
|
||||||
const transactionsJournal = Journal.fromTransactions(
|
|
||||||
transactions,
|
|
||||||
tenantId,
|
|
||||||
accountsGraph
|
|
||||||
);
|
);
|
||||||
// Retrieve the customers list ordered by the display name.
|
// Retrieve the customers list ordered by the display name.
|
||||||
const vendors = await Vendor.query().orderBy('displayName');
|
const vendors = await this.getReportVendors(tenantId, query.vendorsIds);
|
||||||
|
|
||||||
|
// Ledger query.
|
||||||
|
const ledger = new Ledger(vendorsTransactions);
|
||||||
|
|
||||||
// Report instance.
|
// Report instance.
|
||||||
const reportInstance = new VendorBalanceSummaryReport(
|
const reportInstance = new VendorBalanceSummaryReport(
|
||||||
transactionsJournal,
|
ledger,
|
||||||
vendors,
|
vendors,
|
||||||
filter,
|
filter,
|
||||||
baseCurrency,
|
baseCurrency
|
||||||
);
|
);
|
||||||
// Retrieve the report statement.
|
|
||||||
const reportData = reportInstance.reportData();
|
|
||||||
|
|
||||||
// Retrieve the report columns.
|
|
||||||
const reportColumns = reportInstance.reportColumns();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: reportData,
|
data: reportInstance.reportData(),
|
||||||
columns: reportColumns,
|
columns: reportInstance.reportColumns(),
|
||||||
|
query: filter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user