diff --git a/server/src/api/controllers/FinancialStatements/APAgingSummary.ts b/server/src/api/controllers/FinancialStatements/APAgingSummary.ts index 5f18f2555..f827019fd 100644 --- a/server/src/api/controllers/FinancialStatements/APAgingSummary.ts +++ b/server/src/api/controllers/FinancialStatements/APAgingSummary.ts @@ -45,28 +45,19 @@ export default class APAgingSummaryReportController extends BaseFinancialReportC const { tenantId, settings } = req; const filter = this.matchedQueryData(req); - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - try { const { data, columns, query, + meta } = await this.APAgingSummaryService.APAgingSummary(tenantId, filter); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), columns: this.transfromToResponse(columns), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta) }); } catch (error) { next(error); diff --git a/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts b/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts index 979eea0c5..fbf79195c 100644 --- a/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts +++ b/server/src/api/controllers/FinancialStatements/ARAgingSummary.ts @@ -25,7 +25,7 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC } /** - * Receivable aging summary validation roles. + * AR aging summary validation roles. */ get validationSchema() { return [ @@ -41,34 +41,25 @@ export default class ARAgingSummaryReportController extends BaseFinancialReportC } /** - * Retrieve receivable aging summary report. + * Retrieve AR aging summary report. */ async receivableAgingSummary(req: Request, res: Response) { const { tenantId, settings } = req; const filter = this.matchedQueryData(req); - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - try { const { data, columns, query, + meta, } = await this.ARAgingSummaryService.ARAgingSummary(tenantId, filter); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), columns: this.transfromToResponse(columns), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta), }); } catch (error) { console.log(error); diff --git a/server/src/api/controllers/FinancialStatements/BalanceSheet.ts b/server/src/api/controllers/FinancialStatements/BalanceSheet.ts index 46163c04b..c8bca9cc8 100644 --- a/server/src/api/controllers/FinancialStatements/BalanceSheet.ts +++ b/server/src/api/controllers/FinancialStatements/BalanceSheet.ts @@ -59,28 +59,20 @@ export default class BalanceSheetStatementController extends BaseFinancialReport ...filter, accountsIds: castArray(filter.accountsIds), }; - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - + try { const { data, columns, query, + meta, } = await this.balanceSheetService.balanceSheet(tenantId, filter); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), columns: this.transfromToResponse(columns), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta), }); } catch (error) { next(error); diff --git a/server/src/api/controllers/FinancialStatements/GeneralLedger.ts b/server/src/api/controllers/FinancialStatements/GeneralLedger.ts index 071921a43..ce4ce3e44 100644 --- a/server/src/api/controllers/FinancialStatements/GeneralLedger.ts +++ b/server/src/api/controllers/FinancialStatements/GeneralLedger.ts @@ -51,24 +51,14 @@ export default class GeneralLedgerReportController extends BaseFinancialReportCo async generalLedger(req: Request, res: Response, next: NextFunction) { const { tenantId, settings } = req; const filter = this.matchedQueryData(req); - - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - + try { - const { data, query } = await this.generalLedgetService.generalLedger( + const { data, query, meta } = await this.generalLedgetService.generalLedger( tenantId, filter ); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, + meta: this.transfromToResponse(meta), data: this.transfromToResponse(data), query: this.transfromToResponse(query), }); diff --git a/server/src/api/controllers/FinancialStatements/JournalSheet.ts b/server/src/api/controllers/FinancialStatements/JournalSheet.ts index 350a80dbb..86748f6a4 100644 --- a/server/src/api/controllers/FinancialStatements/JournalSheet.ts +++ b/server/src/api/controllers/FinancialStatements/JournalSheet.ts @@ -66,26 +66,17 @@ export default class JournalSheetController extends BaseFinancialReportControlle ...filter, accountsIds: castArray(filter.accountsIds), }; - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); try { - const { data, query } = await this.journalService.journalSheet( + const { data, query, meta } = await this.journalService.journalSheet( tenantId, filter ); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta), }); } catch (error) { next(error); diff --git a/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts b/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts index e5b5125fb..bf2b9da95 100644 --- a/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts +++ b/server/src/api/controllers/FinancialStatements/ProfitLossSheet.ts @@ -54,22 +54,19 @@ export default class ProfitLossSheetController extends BaseFinancialReportContro const { tenantId, settings } = req; const filter = this.matchedQueryData(req); - const organizationName = settings.get({ group: 'organization', key: 'name' }); - const baseCurrency = settings.get({ group: 'organization', key: 'base_currency' }); - try { const { data, columns, query, + meta } = await this.profitLossSheetService.profitLossSheet(tenantId, filter); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), columns: this.transfromToResponse(columns), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta) }); } catch (error) { next(error); diff --git a/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts b/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts index 9ea0f4113..6255ae8a9 100644 --- a/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts +++ b/server/src/api/controllers/FinancialStatements/TrialBalanceSheet.ts @@ -58,29 +58,21 @@ export default class TrialBalanceSheetController extends BaseFinancialReportCont ...filter, accountsIds: castArray(filter.accountsIds), }; - const organizationName = settings.get({ - group: 'organization', - key: 'name', - }); - const baseCurrency = settings.get({ - group: 'organization', - key: 'base_currency', - }); - + try { const { data, query, + meta } = await this.trialBalanceSheetService.trialBalanceSheet( tenantId, filter ); return res.status(200).send({ - organization_name: organizationName, - base_currency: baseCurrency, data: this.transfromToResponse(data), query: this.transfromToResponse(query), + meta: this.transfromToResponse(meta), }); } catch (error) { next(error); diff --git a/server/src/interfaces/APAgingSummaryReport.ts b/server/src/interfaces/APAgingSummaryReport.ts index dd62b4b1f..451b6bc85 100644 --- a/server/src/interfaces/APAgingSummaryReport.ts +++ b/server/src/interfaces/APAgingSummaryReport.ts @@ -34,4 +34,16 @@ export interface IAPAgingSummaryData { total: IAPAgingSummaryTotal, }; -export type IAPAgingSummaryColumns = IAgingPeriod[]; \ No newline at end of file +export type IAPAgingSummaryColumns = IAgingPeriod[]; + + +export interface IARAgingSummaryMeta { + baseCurrency: string, + organizationName: string, +} + + +export interface IAPAgingSummaryMeta { + baseCurrency: string, + organizationName: string, +} \ No newline at end of file diff --git a/server/src/interfaces/ARAgingSummaryReport.ts b/server/src/interfaces/ARAgingSummaryReport.ts index 20e3df42d..2313fe5c7 100644 --- a/server/src/interfaces/ARAgingSummaryReport.ts +++ b/server/src/interfaces/ARAgingSummaryReport.ts @@ -29,3 +29,8 @@ export interface IARAgingSummaryData { } export type IARAgingSummaryColumns = IAgingPeriod[]; + +export interface IARAgingSummaryMeta { + organizationName: string, + baseCurrency: string, +} \ No newline at end of file diff --git a/server/src/interfaces/BalanceSheet.ts b/server/src/interfaces/BalanceSheet.ts index cf330b1dc..29f6bf337 100644 --- a/server/src/interfaces/BalanceSheet.ts +++ b/server/src/interfaces/BalanceSheet.ts @@ -15,10 +15,16 @@ export interface IBalanceSheetQuery { accountIds: number[]; } +export interface IBalanceSheetMeta { + isCostComputeRunning: boolean, + organizationName: string, + baseCurrency: string, +}; + export interface IBalanceSheetFormatNumberSettings extends IFormatNumberSettings { type: string; -} +}; export interface IBalanceSheetStatementService { balanceSheet( @@ -35,6 +41,7 @@ export interface IBalanceSheetStatement { query: IBalanceSheetQuery; columns: IBalanceSheetStatementColumns; data: IBalanceSheetStatementData; + meta: IBalanceSheetMeta; } export interface IBalanceSheetStructureSection { diff --git a/server/src/interfaces/GeneralLedgerSheet.ts b/server/src/interfaces/GeneralLedgerSheet.ts index 84d0cc607..b071fbd57 100644 --- a/server/src/interfaces/GeneralLedgerSheet.ts +++ b/server/src/interfaces/GeneralLedgerSheet.ts @@ -71,4 +71,10 @@ export interface IAccountTransaction { date: string|Date, createdAt: string|Date, updatedAt: string|Date, -} \ No newline at end of file +} + +export interface IGeneralLedgerMeta { + isCostComputeRunning: boolean, + organizationName: string, + baseCurrency: string, +}; \ No newline at end of file diff --git a/server/src/interfaces/JournalReport.ts b/server/src/interfaces/JournalReport.ts index b3b21d92a..d7ff7a738 100644 --- a/server/src/interfaces/JournalReport.ts +++ b/server/src/interfaces/JournalReport.ts @@ -25,4 +25,10 @@ export interface IJournalReportEntriesGroup { export interface IJournalReport { entries: IJournalReportEntriesGroup[], +} + +export interface IJournalSheetMeta { + isCostComputeRunning: boolean, + organizationName: string, + baseCurrency: string, } \ No newline at end of file diff --git a/server/src/interfaces/ProfitLossSheet.ts b/server/src/interfaces/ProfitLossSheet.ts index f070c1f1b..ce3e849a0 100644 --- a/server/src/interfaces/ProfitLossSheet.ts +++ b/server/src/interfaces/ProfitLossSheet.ts @@ -54,4 +54,10 @@ export interface IProfitLossSheetStatement { netIncome: IProfitLossSheetTotalSection; operatingProfit: IProfitLossSheetTotalSection; grossProfit: IProfitLossSheetTotalSection; -}; \ No newline at end of file +}; + +export interface IProfitLossSheetMeta { + isCostComputeRunning: boolean, + organizationName: string, + baseCurrency: string, +} \ No newline at end of file diff --git a/server/src/interfaces/TrialBalanceSheet.ts b/server/src/interfaces/TrialBalanceSheet.ts index abd42e5a6..2c761eee5 100644 --- a/server/src/interfaces/TrialBalanceSheet.ts +++ b/server/src/interfaces/TrialBalanceSheet.ts @@ -21,6 +21,12 @@ export interface ITrialBalanceTotal { formattedBalance: string; } +export interface ITrialBalanceSheetMeta { + isCostComputeRunning: boolean, + organizationName: string, + baseCurrency: string, +}; + export interface ITrialBalanceAccount extends ITrialBalanceTotal { id: number; parentAccountId: number; @@ -38,4 +44,5 @@ export type ITrialBalanceSheetData = { export interface ITrialBalanceStatement { data: ITrialBalanceSheetData; query: ITrialBalanceSheetQuery; + meta: ITrialBalanceSheetMeta, } diff --git a/server/src/jobs/ComputeItemCost.ts b/server/src/jobs/ComputeItemCost.ts index ecc24ea08..f68e99c11 100644 --- a/server/src/jobs/ComputeItemCost.ts +++ b/server/src/jobs/ComputeItemCost.ts @@ -1,8 +1,5 @@ import { Container } from 'typedi'; import {EventDispatcher} from "event-dispatch"; -// import { -// EventDispatcher, -// } from 'decorators/eventDispatcher'; import events from 'subscribers/events'; import InventoryService from 'services/Inventory/Inventory'; @@ -11,7 +8,7 @@ export default class ComputeItemCostJob { eventDispatcher: EventDispatcher; /** - * + * Constructor method. * @param agenda */ constructor(agenda) { diff --git a/server/src/jobs/writeInvoicesJEntries.ts b/server/src/jobs/writeInvoicesJEntries.ts index 4523dcb62..c0eed27d7 100644 --- a/server/src/jobs/writeInvoicesJEntries.ts +++ b/server/src/jobs/writeInvoicesJEntries.ts @@ -1,13 +1,24 @@ import { Container } from 'typedi'; +import {EventDispatcher} from "event-dispatch"; +import events from 'subscribers/events'; import SalesInvoicesCost from 'services/Sales/SalesInvoicesCost'; export default class WriteInvoicesJournalEntries { + eventDispatcher: EventDispatcher; + + /** + * Constructor method. + */ constructor(agenda) { + const eventName = 'rewrite-invoices-journal-entries'; + this.eventDispatcher = new EventDispatcher(); + agenda.define( - 'rewrite-invoices-journal-entries', + eventName, { priority: 'normal', concurrency: 1 }, this.handler.bind(this) ); + agenda.on(`complete:${eventName}`, this.onJobCompleted.bind(this)); } public async handler(job, done: Function): Promise { @@ -36,4 +47,16 @@ export default class WriteInvoicesJournalEntries { done(e); } } + + /** + * Handle the job complete. + */ + async onJobCompleted(job) { + const { startingDate, itemId, tenantId } = job.attrs.data; + + await this.eventDispatcher.dispatch( + events.inventory.onInventoryCostEntriesWritten, + { startingDate, itemId, tenantId } + ); + } } diff --git a/server/src/models/AccountTransaction.js b/server/src/models/AccountTransaction.js index 291c984f4..afb8b26ec 100644 --- a/server/src/models/AccountTransaction.js +++ b/server/src/models/AccountTransaction.js @@ -17,6 +17,9 @@ export default class AccountTransaction extends TenantModel { return ['createdAt']; } + /** + * Virtual attributes. + */ static get virtualAttributes() { return ['referenceTypeFormatted']; } @@ -37,6 +40,7 @@ export default class AccountTransaction extends TenantModel { 'SaleInvoice': 'Sale invoice', 'SaleReceipt': 'Sale receipt', 'PaymentReceive': 'Payment receive', + 'Bill': 'Bill', 'BillPayment': 'Payment made', 'VendorOpeningBalance': 'Vendor opening balance', 'CustomerOpeningBalance': 'Customer opening balance', diff --git a/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts b/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts index ba1916b29..930ee66f8 100644 --- a/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts +++ b/server/src/services/FinancialStatements/AgingSummary/APAgingSummaryService.ts @@ -1,6 +1,6 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; -import { IAPAgingSummaryQuery } from 'interfaces'; +import { IAPAgingSummaryQuery, IARAgingSummaryMeta } from 'interfaces'; import TenancyService from 'services/Tenancy/TenancyService'; import APAgingSummarySheet from './APAgingSummarySheet'; @@ -25,13 +25,36 @@ export default class PayableAgingSummaryService { divideOn1000: false, showZero: false, formatMoney: 'total', - negativeFormat: 'mines' + negativeFormat: 'mines', }, vendorsIds: [], noneZero: false, }; } + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + reportMetadata(tenantId: number): IARAgingSummaryMeta { + const settings = this.tenancy.settings(tenantId); + + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + organizationName, + baseCurrency, + }; + } + /** * Retrieve A/P aging summary report. * @param {number} tenantId - @@ -81,6 +104,11 @@ export default class PayableAgingSummaryService { const data = APAgingSummaryReport.reportData(); const columns = APAgingSummaryReport.reportColumns(); - return { data, columns, query: filter }; + return { + data, + columns, + query: filter, + meta: this.reportMetadata(tenantId), + }; } } diff --git a/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts b/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts index c1d715216..de623f854 100644 --- a/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts +++ b/server/src/services/FinancialStatements/AgingSummary/ARAgingSummaryService.ts @@ -1,6 +1,6 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; -import { IARAgingSummaryQuery } from 'interfaces'; +import { IARAgingSummaryQuery, IARAgingSummaryMeta } from 'interfaces'; import TenancyService from 'services/Tenancy/TenancyService'; import ARAgingSummarySheet from './ARAgingSummarySheet'; @@ -32,6 +32,29 @@ export default class ARAgingSummaryService { }; } + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + reportMetadata(tenantId: number): IARAgingSummaryMeta { + const settings = this.tenancy.settings(tenantId); + + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + organizationName, + baseCurrency, + }; + } + /** * Retrieve A/R aging summary report. * @param {number} tenantId - Tenant id. @@ -85,6 +108,11 @@ export default class ARAgingSummaryService { const data = ARAgingSummaryReport.reportData(); const columns = ARAgingSummaryReport.reportColumns(); - return { data, columns, query: filter }; + return { + data, + columns, + query: filter, + meta: this.reportMetadata(tenantId), + }; } } diff --git a/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts b/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts index 3c6daa5aa..7b4ef5526 100644 --- a/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts +++ b/server/src/services/FinancialStatements/BalanceSheet/BalanceSheetService.ts @@ -4,10 +4,13 @@ import { IBalanceSheetStatementService, IBalanceSheetQuery, IBalanceSheetStatement, + IBalanceSheetMeta, } from 'interfaces'; import TenancyService from 'services/Tenancy/TenancyService'; import Journal from 'services/Accounting/JournalPoster'; import BalanceSheetStatement from './BalanceSheet'; +import InventoryService from 'services/Inventory/Inventory'; +import { parseBoolean } from 'utils'; @Service() export default class BalanceSheetStatementService @@ -18,6 +21,9 @@ export default class BalanceSheetStatementService @Inject('logger') logger: any; + @Inject() + inventoryService: InventoryService; + /** * Defaults balance sheet filter query. * @return {IBalanceSheetQuery} @@ -33,7 +39,7 @@ export default class BalanceSheetStatementService divideOn1000: false, showZero: false, formatMoney: 'total', - negativeFormat: 'mines' + negativeFormat: 'mines', }, noneZero: false, noneTransactions: false, @@ -42,6 +48,33 @@ export default class BalanceSheetStatementService }; } + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + reportMetadata(tenantId: number): IBalanceSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = this.inventoryService + .isItemsCostComputeRunning(tenantId); + + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency + }; + } + /** * Retrieve balance sheet statement. * ------------- @@ -61,14 +94,19 @@ export default class BalanceSheetStatementService // Settings tenant service. const settings = this.tenancy.settings(tenantId); - const baseCurrency = settings.get({ group: 'organization', key: 'base_currency' }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); const filter = { ...this.defaultQuery, ...query, }; - this.logger.info('[balance_sheet] trying to calculate the report.', { filter, tenantId }); - + this.logger.info('[balance_sheet] trying to calculate the report.', { + filter, + tenantId, + }); // Retrieve all accounts on the storage. const accounts = await accountRepository.all(); const accountsGraph = await accountRepository.getDependencyGraph(); @@ -82,7 +120,7 @@ export default class BalanceSheetStatementService const transactionsJournal = Journal.fromTransactions( transactions, tenantId, - accountsGraph, + accountsGraph ); // Balance sheet report instance. const balanceSheetInstanace = new BalanceSheetStatement( @@ -102,6 +140,7 @@ export default class BalanceSheetStatementService data: balanceSheetData, columns: balanceSheetColumns, query: filter, + meta: this.reportMetadata(tenantId), }; } } diff --git a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts index 6c2ec00e7..0878305e1 100644 --- a/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts +++ b/server/src/services/FinancialStatements/GeneralLedger/GeneralLedgerService.ts @@ -2,12 +2,12 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import { ServiceError } from 'exceptions'; import { difference } from 'lodash'; -import { IGeneralLedgerSheetQuery } from 'interfaces'; +import { IGeneralLedgerSheetQuery, IGeneralLedgerMeta } from 'interfaces'; import TenancyService from 'services/Tenancy/TenancyService'; import Journal from 'services/Accounting/JournalPoster'; import GeneralLedgerSheet from 'services/FinancialStatements/GeneralLedger/GeneralLedger'; - -import { transformToMap } from 'utils'; +import InventoryService from 'services/Inventory/Inventory'; +import { transformToMap, parseBoolean } from 'utils'; const ERRORS = { ACCOUNTS_NOT_FOUND: 'ACCOUNTS_NOT_FOUND', @@ -18,6 +18,9 @@ export default class GeneralLedgerService { @Inject() tenancy: TenancyService; + @Inject() + inventoryService: InventoryService; + @Inject('logger') logger: any; @@ -55,6 +58,33 @@ export default class GeneralLedgerService { } } + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IGeneralLedgerMeta} + */ + reportMetadata(tenantId: number): IGeneralLedgerMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = this.inventoryService + .isItemsCostComputeRunning(tenantId); + + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency + }; + } + /** * Retrieve general ledger report statement. * ---------- @@ -68,6 +98,7 @@ export default class GeneralLedgerService { ): Promise<{ data: any; query: IGeneralLedgerSheetQuery; + meta: IGeneralLedgerMeta }> { const { accountRepository, @@ -146,6 +177,7 @@ export default class GeneralLedgerService { return { data: reportData, query: filter, + meta: this.reportMetadata(tenantId), }; } } diff --git a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts index 686399c53..99455a886 100644 --- a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts +++ b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts @@ -1,18 +1,21 @@ import { Service, Inject } from 'typedi'; -import { IJournalReportQuery } from 'interfaces'; import moment from 'moment'; +import { IJournalReportQuery, IJournalSheetMeta } from 'interfaces'; import JournalSheet from './JournalSheet'; import TenancyService from 'services/Tenancy/TenancyService'; import Journal from 'services/Accounting/JournalPoster'; - -import { transformToMap } from 'utils'; +import InventoryService from 'services/Inventory/Inventory'; +import { parseBoolean, transformToMap } from 'utils'; @Service() export default class JournalSheetService { @Inject() tenancy: TenancyService; + @Inject() + inventoryService: InventoryService; + @Inject('logger') logger: any; @@ -34,6 +37,33 @@ export default class JournalSheetService { }; } + /** + * Retrieve the balance sheet meta. + * @param {number} tenantId - + * @returns {IBalanceSheetMeta} + */ + reportMetadata(tenantId: number): IJournalSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = this.inventoryService + .isItemsCostComputeRunning(tenantId); + + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency + }; + } + /** * Journal sheet. * @param {number} tenantId @@ -96,6 +126,7 @@ export default class JournalSheetService { return { data: journalSheetData, query: filter, + meta: this.reportMetadata(tenantId), }; } } diff --git a/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts b/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts index 7f90eee73..3ca848d38 100644 --- a/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts +++ b/server/src/services/FinancialStatements/ProfitLossSheet/ProfitLossSheetService.ts @@ -1,10 +1,12 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import Journal from 'services/Accounting/JournalPoster'; -import { IProfitLossSheetQuery } from 'interfaces'; +import { IProfitLossSheetQuery, IProfitLossSheetMeta } from 'interfaces'; import ProfitLossSheet from './ProfitLossSheet'; import TenancyService from 'services/Tenancy/TenancyService'; import AccountsService from 'services/Accounts/AccountsService'; +import InventoryService from 'services/Inventory/Inventory'; +import { parseBoolean } from 'utils'; // Profit/Loss sheet service. @Service() @@ -15,6 +17,9 @@ export default class ProfitLossSheetService { @Inject('logger') logger: any; + @Inject() + inventoryService: InventoryService; + @Inject() accountsService: AccountsService; @@ -42,6 +47,34 @@ export default class ProfitLossSheetService { }; } + + /** + * Retrieve the trial balance sheet meta. + * @param {number} tenantId - Tenant id. + * @returns {ITrialBalanceSheetMeta} + */ + reportMetadata(tenantId: number): IProfitLossSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = this.inventoryService.isItemsCostComputeRunning( + tenantId + ); + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency, + }; + } + /** * Retrieve profit/loss sheet statement. * @param {number} tenantId @@ -107,6 +140,7 @@ export default class ProfitLossSheetService { data: profitLossData, columns: profitLossColumns, query: filter, + meta: this.reportMetadata(tenantId), }; } } diff --git a/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts b/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts index 9f96dbc57..48abaa44a 100644 --- a/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts +++ b/server/src/services/FinancialStatements/TrialBalanceSheet/TrialBalanceSheetService.ts @@ -2,15 +2,20 @@ import { Service, Inject } from 'typedi'; import moment from 'moment'; import TenancyService from 'services/Tenancy/TenancyService'; import Journal from 'services/Accounting/JournalPoster'; -import { INumberFormatQuery, ITrialBalanceSheetQuery, ITrialBalanceStatement } from 'interfaces'; +import { ITrialBalanceSheetMeta, ITrialBalanceSheetQuery, ITrialBalanceStatement } from 'interfaces'; import TrialBalanceSheet from './TrialBalanceSheet'; import FinancialSheet from '../FinancialSheet'; +import InventoryService from 'services/Inventory/Inventory'; +import { parseBoolean } from 'utils'; @Service() export default class TrialBalanceSheetService extends FinancialSheet { @Inject() tenancy: TenancyService; + @Inject() + inventoryService: InventoryService; + @Inject('logger') logger: any; @@ -36,6 +41,33 @@ export default class TrialBalanceSheetService extends FinancialSheet { }; } + /** + * Retrieve the trial balance sheet meta. + * @param {number} tenantId - Tenant id. + * @returns {ITrialBalanceSheetMeta} + */ + reportMetadata(tenantId: number): ITrialBalanceSheetMeta { + const settings = this.tenancy.settings(tenantId); + + const isCostComputeRunning = this.inventoryService.isItemsCostComputeRunning( + tenantId + ); + const organizationName = settings.get({ + group: 'organization', + key: 'name', + }); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return { + isCostComputeRunning: parseBoolean(isCostComputeRunning, false), + organizationName, + baseCurrency, + }; + } + /** * Retrieve trial balance sheet statement. * ------------- @@ -46,7 +78,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { */ public async trialBalanceSheet( tenantId: number, - query: ITrialBalanceSheetQuery, + query: ITrialBalanceSheetQuery ): Promise { const filter = { ...this.defaultQuery, @@ -98,6 +130,7 @@ export default class TrialBalanceSheetService extends FinancialSheet { return { data: trialBalanceSheetData, query: filter, + meta: this.reportMetadata(tenantId), }; } } diff --git a/server/src/services/Inventory/Inventory.ts b/server/src/services/Inventory/Inventory.ts index 5159abd8a..ef9bda031 100644 --- a/server/src/services/Inventory/Inventory.ts +++ b/server/src/services/Inventory/Inventory.ts @@ -17,6 +17,7 @@ import InventoryCostLotTracker from 'services/Inventory/InventoryCostLotTracker' import TenancyService from 'services/Tenancy/TenancyService'; import events from 'subscribers/events'; import ItemsEntriesService from 'services/Items/ItemsEntriesService'; +import SettingsMiddleware from 'api/middleware/SettingsMiddleware'; type TCostMethod = 'FIFO' | 'LIFO' | 'AVG'; @@ -346,4 +347,37 @@ export default class InventoryService { return lotNumber; } + + /** + * Mark item cost computing is running. + * @param {number} tenantId - + * @param {boolean} isRunning - + */ + async markItemsCostComputeRunning( + tenantId: number, + isRunning: boolean = true + ) { + const settings = this.tenancy.settings(tenantId); + + settings.set({ + key: 'cost_compute_running', + group: 'inventory', + value: isRunning, + }); + await settings.save(); + } + + /** + * + * @param {number} tenantId + * @returns + */ + isItemsCostComputeRunning(tenantId) { + const settings = this.tenancy.settings(tenantId); + + return settings.get({ + key: 'cost_compute_running', + group: 'inventory' + }); + } } diff --git a/server/src/subscribers/Inventory/Inventory.ts b/server/src/subscribers/Inventory/Inventory.ts index 7caf72859..05c8c3fd2 100644 --- a/server/src/subscribers/Inventory/Inventory.ts +++ b/server/src/subscribers/Inventory/Inventory.ts @@ -2,25 +2,52 @@ import { Container } from 'typedi'; import { EventSubscriber, On } from 'event-dispatch'; import { map, head } from 'lodash'; import events from 'subscribers/events'; +import TenancyService from 'services/Tenancy/TenancyService'; import SaleInvoicesCost from 'services/Sales/SalesInvoicesCost'; import InventoryItemsQuantitySync from 'services/Inventory/InventoryItemsQuantitySync'; -import { InventoryTransaction } from 'models'; +import InventoryService from 'services/Inventory/Inventory'; @EventSubscriber() export class InventorySubscriber { depends: number = 0; startingDate: Date; saleInvoicesCost: SaleInvoicesCost; - + tenancy: TenancyService; itemsQuantitySync: InventoryItemsQuantitySync; + inventoryService: InventoryService; agenda: any; + /** + * Constructor method. + */ constructor() { this.saleInvoicesCost = Container.get(SaleInvoicesCost); this.itemsQuantitySync = Container.get(InventoryItemsQuantitySync); + this.inventoryService = Container.get(InventoryService); + this.tenancy = Container.get(TenancyService); this.agenda = Container.get('agenda'); } + /** + * Marks items cost compute running state. + */ + @On(events.inventory.onComputeItemCostJobScheduled) + async markGlobalSettingsComputeItems({ + tenantId + }) { + await this.inventoryService.markItemsCostComputeRunning(tenantId, true); + } + + /** + * Marks items cost compute as completed. + */ + @On(events.inventory.onInventoryCostEntriesWritten) + async markGlobalSettingsComputeItemsCompeted({ + tenantId + }) { + await this.inventoryService.markItemsCostComputeRunning(tenantId, false); + } + /** * Handle run writing the journal entries once the compute items jobs completed. */ diff --git a/server/src/subscribers/events.ts b/server/src/subscribers/events.ts index 62c41d7c2..48f8836b5 100644 --- a/server/src/subscribers/events.ts +++ b/server/src/subscribers/events.ts @@ -190,7 +190,9 @@ export default { onComputeItemCostJobScheduled: 'onComputeItemCostJobScheduled', onComputeItemCostJobStarted: 'onComputeItemCostJobStarted', - onComputeItemCostJobCompleted: 'onComputeItemCostJobCompleted' + onComputeItemCostJobCompleted: 'onComputeItemCostJobCompleted', + + onInventoryCostEntriesWritten: 'onInventoryCostEntriesWritten' }, /**