From 1ba67f183b852d468b892a137ae5ccde2329ca0a Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Tue, 30 Mar 2021 16:18:57 +0200 Subject: [PATCH] fix(Currencies): Currency code in services. --- .../QuickPaymentMadeFormFields.js | 6 +++ .../QuickPaymentReceiveFormFields.js | 7 ++- .../ExpenseForm/ExpenseFormPageProvider.js | 12 ++--- .../InventoryValuationTable.js | 1 + .../FinancialStatements/Journal/components.js | 2 +- .../PurchasesByItems/PurchasesByItemsTable.js | 1 + .../SalesByItems/SalesByItemsTable.js | 1 + .../PaymentMadeFormHeaderFields.js | 6 +++ .../PaymentReceiveHeaderFields.js | 6 +++ .../ReceiptForm/ReceiptFormHeaderFields.js | 7 ++- .../FinancialStatements/APAgingSummary.scss | 2 +- .../FinancialStatements/ARAgingSummary.scss | 2 +- .../SalesAndPurchasesSheet.scss | 2 +- .../TrialBalanceSheet.scss | 2 +- ...251_create_inventory_transactions_table.js | 1 + ...create_inventory_cost_lot_tracker_table.js | 2 + server/src/interfaces/Account.ts | 4 ++ server/src/interfaces/FinancialStatements.ts | 2 +- .../interfaces/IInventoryValuationSheet.ts | 5 ++- server/src/interfaces/InventoryTransaction.ts | 2 +- server/src/interfaces/SalesByItemsSheet.ts | 4 +- .../services/Accounting/JournalCommands.ts | 2 +- .../src/services/Accounts/AccountsService.ts | 45 ++++++++++++------- .../BalanceSheet/BalanceSheet.ts | 2 + .../FinancialStatements/FinancialSheet.ts | 4 +- .../InventoryValuationSheet.ts | 26 +++++------ .../InventoryValuationSheetService.ts | 8 ++++ .../JournalSheet/JournalSheet.ts | 8 ++-- .../JournalSheet/JournalSheetService.ts | 14 +++--- .../PurchasesByItems/PurchasesByItems.ts | 6 +-- .../SalesByItems/SalesByItems.ts | 6 +-- server/src/services/Inventory/Inventory.ts | 1 + .../Inventory/InventoryAdjustmentService.ts | 1 - .../Inventory/InventoryAverageCost.ts | 2 + .../Purchases/BillPayments/BillPayments.ts | 11 ++++- .../Sales/PaymentReceives/PaymentsReceives.ts | 12 +++-- server/src/utils/index.ts | 8 +++- 37 files changed, 160 insertions(+), 73 deletions(-) diff --git a/client/src/containers/Dialogs/QuickPaymentMadeFormDialog/QuickPaymentMadeFormFields.js b/client/src/containers/Dialogs/QuickPaymentMadeFormDialog/QuickPaymentMadeFormFields.js index c5f16d93c..dc0ea26ea 100644 --- a/client/src/containers/Dialogs/QuickPaymentMadeFormDialog/QuickPaymentMadeFormFields.js +++ b/client/src/containers/Dialogs/QuickPaymentMadeFormDialog/QuickPaymentMadeFormFields.js @@ -14,6 +14,7 @@ import classNames from 'classnames'; import { CLASSES } from 'common/classes'; import { DateInput } from '@blueprintjs/datetime'; import { FieldRequiredHint, Col, Row } from 'components'; +import { ACCOUNT_TYPE } from 'common/accountTypes'; import { AccountsSuggestField, InputPrependText, @@ -164,6 +165,11 @@ export default function QuickPaymentMadeFormFields() { id: 'select_account', }), }} + filterByTypes={[ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]} /> )} diff --git a/client/src/containers/Dialogs/QuickPaymentReceiveFormDialog/QuickPaymentReceiveFormFields.js b/client/src/containers/Dialogs/QuickPaymentReceiveFormDialog/QuickPaymentReceiveFormFields.js index 083d8f2a2..c47a07896 100644 --- a/client/src/containers/Dialogs/QuickPaymentReceiveFormDialog/QuickPaymentReceiveFormFields.js +++ b/client/src/containers/Dialogs/QuickPaymentReceiveFormDialog/QuickPaymentReceiveFormFields.js @@ -20,7 +20,7 @@ import { MoneyInputGroup, Icon, } from 'components'; - +import { ACCOUNT_TYPE } from 'common/accountTypes'; import { inputIntent, momentFormatter, @@ -166,6 +166,11 @@ export default function QuickPaymentReceiveFormFields({}) { id: 'select_account', }), }} + filterByTypes={[ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]} /> )} diff --git a/client/src/containers/Expenses/ExpenseForm/ExpenseFormPageProvider.js b/client/src/containers/Expenses/ExpenseForm/ExpenseFormPageProvider.js index c9fc648ba..23b72b704 100644 --- a/client/src/containers/Expenses/ExpenseForm/ExpenseFormPageProvider.js +++ b/client/src/containers/Expenses/ExpenseForm/ExpenseFormPageProvider.js @@ -15,16 +15,16 @@ const ExpenseFormPageContext = createContext(); * Accounts chart data provider. */ function ExpenseFormPageProvider({ expenseId, ...props }) { - const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies(); + const { data: currencies, isLoading: isCurrenciesLoading } = useCurrencies(); // Fetches customers list. const { data: { customers }, - isFetching: isFieldsLoading, + isLoading: isCustomersLoading, } = useCustomers(); // Fetch the expense details. - const { data: expense, isFetching: isExpenseLoading } = useExpense( + const { data: expense, isLoading: isExpenseLoading } = useExpense( expenseId, { enabled: !!expenseId, @@ -32,7 +32,7 @@ function ExpenseFormPageProvider({ expenseId, ...props }) { ); // Fetch accounts list. - const { data: accounts, isFetching: isAccountsLoading } = useAccounts(); + const { data: accounts, isLoading: isAccountsLoading } = useAccounts(); // Create and edit expense mutate. const { mutateAsync: createExpenseMutate } = useCreateExpense(); @@ -57,7 +57,7 @@ function ExpenseFormPageProvider({ expenseId, ...props }) { isCurrenciesLoading, isExpenseLoading, - isFieldsLoading, + isCustomersLoading, isAccountsLoading, createExpenseMutate, @@ -70,7 +70,7 @@ function ExpenseFormPageProvider({ expenseId, ...props }) { loading={ isCurrenciesLoading || isExpenseLoading || - isFieldsLoading || + isCustomersLoading || isAccountsLoading } name={'expense-form'} diff --git a/client/src/containers/FinancialStatements/InventoryValuation/InventoryValuationTable.js b/client/src/containers/FinancialStatements/InventoryValuation/InventoryValuationTable.js index 177a406e0..43efa58cb 100644 --- a/client/src/containers/FinancialStatements/InventoryValuation/InventoryValuationTable.js +++ b/client/src/containers/FinancialStatements/InventoryValuation/InventoryValuationTable.js @@ -56,6 +56,7 @@ export default function InventoryValuationTable({ expandColumnSpace={1} sticky={true} rowClassNames={rowClassNames} + noResults={'There were no inventory transactions during the selected date range.'} /> ); diff --git a/client/src/containers/FinancialStatements/Journal/components.js b/client/src/containers/FinancialStatements/Journal/components.js index c8667a724..a658be52a 100644 --- a/client/src/containers/FinancialStatements/Journal/components.js +++ b/client/src/containers/FinancialStatements/Journal/components.js @@ -29,7 +29,7 @@ export const useJournalTableColumns = () => { }, { Header: formatMessage({ id: 'num' }), - accessor: 'reference_id', + accessor: 'transaction_number', className: 'reference_id', width: 70, }, diff --git a/client/src/containers/FinancialStatements/PurchasesByItems/PurchasesByItemsTable.js b/client/src/containers/FinancialStatements/PurchasesByItems/PurchasesByItemsTable.js index 140bd28ae..662f8ae76 100644 --- a/client/src/containers/FinancialStatements/PurchasesByItems/PurchasesByItemsTable.js +++ b/client/src/containers/FinancialStatements/PurchasesByItems/PurchasesByItemsTable.js @@ -55,6 +55,7 @@ export default function PurchasesByItemsTable({ companyName }) { expandColumnSpace={1} sticky={true} rowClassNames={rowClassNames} + noResults={'There were no purchases during the selected date range.'} /> ); diff --git a/client/src/containers/FinancialStatements/SalesByItems/SalesByItemsTable.js b/client/src/containers/FinancialStatements/SalesByItems/SalesByItemsTable.js index 94611e888..74580b570 100644 --- a/client/src/containers/FinancialStatements/SalesByItems/SalesByItemsTable.js +++ b/client/src/containers/FinancialStatements/SalesByItems/SalesByItemsTable.js @@ -53,6 +53,7 @@ export default function SalesByItemsTable({ companyName }) { expandColumnSpace={1} sticky={true} rowClassNames={rowClassNames} + noResults={'There were no sales during the selected date range.'} /> ); diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormHeaderFields.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormHeaderFields.js index adb12da66..d107cdb5e 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormHeaderFields.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormHeaderFields.js @@ -25,6 +25,7 @@ import { } from 'components'; import withSettings from 'containers/Settings/withSettings'; import { usePaymentMadeFormContext } from './PaymentMadeFormProvider'; +import { ACCOUNT_TYPE } from 'common/accountTypes'; import { momentFormatter, tansformDateValue, @@ -205,6 +206,11 @@ function PaymentMadeFormHeaderFields({ baseCurrency }) { }} defaultSelectText={} selectedAccountId={value} + filterByTypes={[ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]} /> )} diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.js index 2df4dbdc4..091d38e24 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveHeaderFields.js @@ -33,6 +33,7 @@ import { Money, } from 'components'; import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider'; +import { ACCOUNT_TYPE } from 'common/accountTypes'; import withDialogActions from 'containers/Dialog/withDialogActions'; import withSettings from 'containers/Settings/withSettings'; @@ -263,6 +264,11 @@ function PaymentReceiveHeaderFields({ }} defaultSelectText={} selectedAccountId={value} + filterByTypes={[ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]} /> )} diff --git a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeaderFields.js b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeaderFields.js index 5f04fc976..a3e2ecb7b 100644 --- a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeaderFields.js +++ b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeaderFields.js @@ -19,6 +19,7 @@ import { } from 'components'; import withSettings from 'containers/Settings/withSettings'; import withDialogActions from 'containers/Dialog/withDialogActions'; +import { ACCOUNT_TYPE } from 'common/accountTypes'; import { momentFormatter, compose, @@ -113,8 +114,12 @@ function ReceiptFormHeader({ }} defaultSelectText={} selectedAccountId={value} - // filterByTypes={['current_asset']} popoverFill={true} + filterByTypes={[ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]} /> )} diff --git a/client/src/style/pages/FinancialStatements/APAgingSummary.scss b/client/src/style/pages/FinancialStatements/APAgingSummary.scss index e833471a5..f61ee093e 100644 --- a/client/src/style/pages/FinancialStatements/APAgingSummary.scss +++ b/client/src/style/pages/FinancialStatements/APAgingSummary.scss @@ -26,7 +26,7 @@ font-weight: 500; .td{ - border-top: 1px solid #333; + border-top: 1px solid #BBB; border-bottom: 3px double #333; } } diff --git a/client/src/style/pages/FinancialStatements/ARAgingSummary.scss b/client/src/style/pages/FinancialStatements/ARAgingSummary.scss index f3602b66f..d663e5f8a 100644 --- a/client/src/style/pages/FinancialStatements/ARAgingSummary.scss +++ b/client/src/style/pages/FinancialStatements/ARAgingSummary.scss @@ -26,7 +26,7 @@ font-weight: 500; .td{ - border-top: 1px solid #333; + border-top: 1px solid #BBB; border-bottom: 3px double #333; } } diff --git a/client/src/style/pages/FinancialStatements/SalesAndPurchasesSheet.scss b/client/src/style/pages/FinancialStatements/SalesAndPurchasesSheet.scss index 3607c8a94..48f9656b6 100644 --- a/client/src/style/pages/FinancialStatements/SalesAndPurchasesSheet.scss +++ b/client/src/style/pages/FinancialStatements/SalesAndPurchasesSheet.scss @@ -19,7 +19,7 @@ padding-bottom: 0.4rem; } .tr.row_type--total .td { - border-top: 1px solid #000; + border-top: 1px solid #BBB; font-weight: 500; border-bottom: 3px double #000; } diff --git a/client/src/style/pages/FinancialStatements/TrialBalanceSheet.scss b/client/src/style/pages/FinancialStatements/TrialBalanceSheet.scss index acf0a843c..2eff7447d 100644 --- a/client/src/style/pages/FinancialStatements/TrialBalanceSheet.scss +++ b/client/src/style/pages/FinancialStatements/TrialBalanceSheet.scss @@ -22,7 +22,7 @@ border-top-color: #000; } .tr.row_type--total .td{ - border-top: 1px solid #000; + border-top: 1px solid #bbb; font-weight: 500; border-bottom: 3px double #000; } diff --git a/server/src/database/migrations/20200722164251_create_inventory_transactions_table.js b/server/src/database/migrations/20200722164251_create_inventory_transactions_table.js index 9871e5d15..bf8de6184 100644 --- a/server/src/database/migrations/20200722164251_create_inventory_transactions_table.js +++ b/server/src/database/migrations/20200722164251_create_inventory_transactions_table.js @@ -16,6 +16,7 @@ exports.up = function (knex) { table.integer('transaction_id').unsigned().index(); table.integer('entry_id').unsigned().index(); + table.integer('cost_account_id').unsigned(); table.timestamps(); }); }; diff --git a/server/src/database/migrations/20200810121807_create_inventory_cost_lot_tracker_table.js b/server/src/database/migrations/20200810121807_create_inventory_cost_lot_tracker_table.js index 55bcbcbb1..7f45dbdef 100644 --- a/server/src/database/migrations/20200810121807_create_inventory_cost_lot_tracker_table.js +++ b/server/src/database/migrations/20200810121807_create_inventory_cost_lot_tracker_table.js @@ -14,6 +14,8 @@ exports.up = function (knex) { table.integer('transaction_id').unsigned().index(); table.integer('entry_id').unsigned().index(); + table.integer('cost_account_id').unsigned(); + table.datetime('created_at').index(); }); }; diff --git a/server/src/interfaces/Account.ts b/server/src/interfaces/Account.ts index fd48ae3da..1893a3ade 100644 --- a/server/src/interfaces/Account.ts +++ b/server/src/interfaces/Account.ts @@ -28,6 +28,10 @@ export interface IAccount { accountParentType: string, }; +export interface IAccountResponse extends IAccount { + +} + export interface IAccountsFilter extends IDynamicListFilterDTO { stringifiedFilterRoles?: string, }; diff --git a/server/src/interfaces/FinancialStatements.ts b/server/src/interfaces/FinancialStatements.ts index 52ae49478..c956afd17 100644 --- a/server/src/interfaces/FinancialStatements.ts +++ b/server/src/interfaces/FinancialStatements.ts @@ -14,6 +14,6 @@ export interface IFormatNumberSettings { thousand?: string; decimal?: string; zeroSign?: string; - symbol?: string; + currencyCode?: string; money?: boolean, } diff --git a/server/src/interfaces/IInventoryValuationSheet.ts b/server/src/interfaces/IInventoryValuationSheet.ts index 9bf4f151b..8a6cf5f40 100644 --- a/server/src/interfaces/IInventoryValuationSheet.ts +++ b/server/src/interfaces/IInventoryValuationSheet.ts @@ -12,6 +12,7 @@ export interface IInventoryValuationReportQuery { export interface IInventoryValuationSheetMeta { organizationName: string, baseCurrency: string, + isCostComputeRunning: boolean }; export interface IInventoryValuationItem { @@ -35,8 +36,8 @@ export interface IInventoryValuationTotal { quantityFormatted: string, } -export interface IInventoryValuationStatement { +export type IInventoryValuationStatement = { items: IInventoryValuationItem[], total: IInventoryValuationTotal -}; +} | {}; diff --git a/server/src/interfaces/InventoryTransaction.ts b/server/src/interfaces/InventoryTransaction.ts index 7c2a668c7..47e4d4219 100644 --- a/server/src/interfaces/InventoryTransaction.ts +++ b/server/src/interfaces/InventoryTransaction.ts @@ -11,6 +11,7 @@ export interface IInventoryTransaction { transactionType: string, transactionId: number, entryId: number, + costAccountId: number, createdAt?: Date, updatedAt?: Date, }; @@ -27,7 +28,6 @@ export interface IInventoryLotCost { transactionType: string, transactionId: number, costAccountId: number, - sellAccountId: number, entryId: number, createdAt: Date, }; diff --git a/server/src/interfaces/SalesByItemsSheet.ts b/server/src/interfaces/SalesByItemsSheet.ts index 50ddfaea0..d90fff55e 100644 --- a/server/src/interfaces/SalesByItemsSheet.ts +++ b/server/src/interfaces/SalesByItemsSheet.ts @@ -36,8 +36,8 @@ export interface ISalesByItemsTotal { currencyCode: string, }; -export interface ISalesByItemsSheetStatement { +export type ISalesByItemsSheetStatement = { items: ISalesByItemsItem[], total: ISalesByItemsTotal -}; +} | {}; diff --git a/server/src/services/Accounting/JournalCommands.ts b/server/src/services/Accounting/JournalCommands.ts index 2f73a3cf0..15f731f3c 100644 --- a/server/src/services/Accounting/JournalCommands.ts +++ b/server/src/services/Accounting/JournalCommands.ts @@ -350,7 +350,7 @@ export default class JournalCommands { const costEntry = new JournalEntry({ ...commonEntry, debit: inventoryCostLot.cost, - account: inventoryCostLot.itemEntry.costAccountId, + account: inventoryCostLot.costAccountId, itemId: inventoryCostLot.itemId, index: getIndexIncrement(), }); diff --git a/server/src/services/Accounts/AccountsService.ts b/server/src/services/Accounts/AccountsService.ts index 6d3647dfe..9a190454d 100644 --- a/server/src/services/Accounts/AccountsService.ts +++ b/server/src/services/Accounts/AccountsService.ts @@ -8,6 +8,7 @@ import { IAccount, IAccountsFilter, IFilterMeta, + IAccountResponse } from 'interfaces'; import { EventDispatcher, @@ -38,11 +39,9 @@ export default class AccountsService { * @param {number} accountTypeId - * @return {IAccountType} */ - private getAccountTypeOrThrowError( - accountTypeKey: string - ) { + private getAccountTypeOrThrowError(accountTypeKey: string) { this.logger.info('[accounts] validating account type existance.', { - accountTypeKey + accountTypeKey, }); const accountType = AccountTypesUtils.getType(accountTypeKey); @@ -298,7 +297,7 @@ export default class AccountsService { } // Update the account on the storage. const account = await accountRepository.update( - { ...accountDTO, }, + { ...accountDTO }, { id: oldAccount.id } ); this.logger.info('[account] account edited successfully.', { @@ -549,9 +548,9 @@ export default class AccountsService { { accountsIds } ); // Activate or inactivate the given accounts ids in bulk. - (activate) ? - await accountRepository.activateByIds(patchAccountsIds) : - await accountRepository.inactivateByIds(patchAccountsIds); + activate + ? await accountRepository.activateByIds(patchAccountsIds) + : await accountRepository.inactivateByIds(patchAccountsIds); this.logger.info('[account] accounts have been activated successfully.', { tenantId, @@ -587,9 +586,9 @@ export default class AccountsService { const patchAccountsIds = [...dependenciesAccounts, accountId]; // Activate and inactivate the given accounts ids. - (activate) ? - await accountRepository.activateByIds(patchAccountsIds) : - await accountRepository.inactivateByIds(patchAccountsIds); + activate + ? await accountRepository.activateByIds(patchAccountsIds) + : await accountRepository.inactivateByIds(patchAccountsIds); this.logger.info('[account] account have been activated successfully.', { tenantId, @@ -607,7 +606,7 @@ export default class AccountsService { public async getAccountsList( tenantId: number, filter: IAccountsFilter - ): Promise<{ accounts: IAccount[]; filterMeta: IFilterMeta }> { + ): Promise<{ accounts: IAccountResponse[]; filterMeta: IFilterMeta }> { const { Account } = this.tenancy.models(tenantId); const dynamicList = await this.dynamicListService.dynamicList( tenantId, @@ -624,11 +623,27 @@ export default class AccountsService { }); return { - accounts, + accounts: this.transformAccountsResponse(tenantId, accounts), filterMeta: dynamicList.getResponseMeta(), }; } + /** + * Transformes the accounts models to accounts response. + */ + private transformAccountsResponse(tenantId: number, accounts: IAccount[]) { + const settings = this.tenancy.settings(tenantId); + const baseCurrency = settings.get({ + group: 'organization', + key: 'base_currency', + }); + + return accounts.map((account) => ({ + ...account, + currencyCode: baseCurrency, + })); + } + /** * Closes the given account. * ----------- @@ -655,9 +670,7 @@ export default class AccountsService { deleteAfterClosing, }); const { AccountTransaction } = this.tenancy.models(tenantId); - const { - accountRepository, - } = this.tenancy.repositories(tenantId); + const { accountRepository } = this.tenancy.repositories(tenantId); const account = await this.getAccountOrThrowError(tenantId, accountId); const toAccount = await this.getAccountOrThrowError(tenantId, toAccountId); diff --git a/server/src/services/FinancialStatements/BalanceSheet/BalanceSheet.ts b/server/src/services/FinancialStatements/BalanceSheet/BalanceSheet.ts index 2fd256057..c166e123a 100644 --- a/server/src/services/FinancialStatements/BalanceSheet/BalanceSheet.ts +++ b/server/src/services/FinancialStatements/BalanceSheet/BalanceSheet.ts @@ -8,6 +8,7 @@ import { IAccount, IJournalPoster, IAccountType, + INumberFormatQuery, } from 'interfaces'; import { dateRangeCollection, flatToNestedArray } from 'utils'; import BalanceSheetStructure from 'data/BalanceSheetStructure'; @@ -21,6 +22,7 @@ export default class BalanceSheetStatement extends FinancialSheet { readonly comparatorDateType: string; readonly dateRangeSet: string[]; readonly baseCurrency: string; + readonly numberFormat: INumberFormatQuery; /** * Constructor method. diff --git a/server/src/services/FinancialStatements/FinancialSheet.ts b/server/src/services/FinancialStatements/FinancialSheet.ts index df78de504..64ef0cc5b 100644 --- a/server/src/services/FinancialStatements/FinancialSheet.ts +++ b/server/src/services/FinancialStatements/FinancialSheet.ts @@ -2,7 +2,8 @@ import { IFormatNumberSettings, INumberFormatQuery } from 'interfaces'; import { formatNumber } from 'utils'; export default class FinancialSheet { - numberFormat: INumberFormatQuery; + readonly numberFormat: INumberFormatQuery; + readonly baseCurrency: string; /** * Transformes the number format query to settings @@ -16,6 +17,7 @@ export default class FinancialSheet { excerptZero: !numberFormat.showZero, negativeFormat: numberFormat.negativeFormat, money: numberFormat.formatMoney === 'always', + currencyCode: this.baseCurrency, }; } diff --git a/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheet.ts b/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheet.ts index 98e9b0823..0a27147ce 100644 --- a/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheet.ts +++ b/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheet.ts @@ -48,7 +48,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * @param {number} itemId * @returns */ - getItemTransaction( + private getItemTransaction( transactionsMap: Map, itemId: number, ): { cost: number, quantity: number } { @@ -64,7 +64,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the cost and quantity of the givne item from `IN` transactions. * @param {number} itemId - */ - getItemINTransaction( + private getItemINTransaction( itemId: number, ): { cost: number, quantity: number } { return this.getItemTransaction(this.INInventoryCostLots, itemId); @@ -74,7 +74,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the cost and quantity of the given item from `OUT` transactions. * @param {number} itemId - */ - getItemOUTTransaction( + private getItemOUTTransaction( itemId: number, ): { cost: number, quantity: number } { return this.getItemTransaction(this.OUTInventoryCostLots, itemId); @@ -84,7 +84,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the item closing valuation. * @param {number} itemId - Item id. */ - getItemValuation(itemId: number): number { + private getItemValuation(itemId: number): number { const { cost: INValuation } = this.getItemINTransaction(itemId); const { cost: OUTValuation } = this.getItemOUTTransaction(itemId); @@ -95,7 +95,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the item closing quantity. * @param {number} itemId - Item id. */ - getItemQuantity(itemId: number): number { + private getItemQuantity(itemId: number): number { const { quantity: INQuantity } = this.getItemINTransaction(itemId); const { quantity: OUTQuantity } = this.getItemOUTTransaction(itemId); @@ -108,7 +108,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * @param {number} quantity * @returns {number} */ - calcAverage(valuation: number, quantity: number): number { + private calcAverage(valuation: number, quantity: number): number { return quantity ? valuation / quantity : 0; } @@ -117,7 +117,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * @param {IItem} item * @returns {IInventoryValuationItem} */ - itemMapper(item: IItem): IInventoryValuationItem { + private itemMapper(item: IItem): IInventoryValuationItem { const valuation = this.getItemValuation(item.id); const quantity = this.getItemQuantity(item.id); const average = this.calcAverage(valuation, quantity); @@ -140,7 +140,7 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the inventory valuation items. * @returns {IInventoryValuationItem[]} */ - itemsSection(): IInventoryValuationItem[] { + private itemsSection(): IInventoryValuationItem[] { return this.items.map(this.itemMapper.bind(this)); } @@ -149,15 +149,15 @@ export default class InventoryValuationSheet extends FinancialSheet { * @param {IInventoryValuationItem[]} items * @returns {IInventoryValuationTotal} */ - totalSection(items: IInventoryValuationItem[]): IInventoryValuationTotal { + private totalSection(items: IInventoryValuationItem[]): IInventoryValuationTotal { const valuation = sumBy(items, item => item.valuation); const quantity = sumBy(items, item => item.quantity); return { valuation, quantity, - valuationFormatted: this.formatNumber(valuation), - quantityFormatted: this.formatNumber(quantity, { money: false }), + valuationFormatted: this.formatTotalNumber(valuation), + quantityFormatted: this.formatTotalNumber(quantity, { money: false }), }; } @@ -165,10 +165,10 @@ export default class InventoryValuationSheet extends FinancialSheet { * Retrieve the inventory valuation report data. * @returns {IInventoryValuationStatement} */ - reportData(): IInventoryValuationStatement { + public reportData(): IInventoryValuationStatement { const items = this.itemsSection(); const total = this.totalSection(items); - return { items, total }; + return items.length > 0 ? { items, total } : {}; } } \ No newline at end of file diff --git a/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts b/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts index d9f833b58..fe818b419 100644 --- a/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts +++ b/server/src/services/FinancialStatements/InventoryValuationSheet/InventoryValuationSheetService.ts @@ -6,6 +6,7 @@ import { } from 'interfaces'; import TenancyService from 'services/Tenancy/TenancyService'; import InventoryValuationSheet from './InventoryValuationSheet'; +import InventoryService from 'services/Inventory/Inventory'; @Service() export default class InventoryValuationSheetService { @@ -15,6 +16,9 @@ export default class InventoryValuationSheetService { @Inject('logger') logger: any; + @Inject() + inventoryService: InventoryService; + /** * Defaults balance sheet filter query. * @return {IBalanceSheetQuery} @@ -41,6 +45,9 @@ export default class InventoryValuationSheetService { reportMetadata(tenantId: number): IInventoryValuationSheetMeta { const settings = this.tenancy.settings(tenantId); + const isCostComputeRunning = this.inventoryService + .isItemsCostComputeRunning(tenantId); + const organizationName = settings.get({ group: 'organization', key: 'name', @@ -53,6 +60,7 @@ export default class InventoryValuationSheetService { return { organizationName, baseCurrency, + isCostComputeRunning }; } diff --git a/server/src/services/FinancialStatements/JournalSheet/JournalSheet.ts b/server/src/services/FinancialStatements/JournalSheet/JournalSheet.ts index 313eb58f9..3c8df9d5e 100644 --- a/server/src/services/FinancialStatements/JournalSheet/JournalSheet.ts +++ b/server/src/services/FinancialStatements/JournalSheet/JournalSheet.ts @@ -10,10 +10,10 @@ import { import FinancialSheet from '../FinancialSheet'; export default class JournalSheet extends FinancialSheet { - tenantId: number; - journal: IJournalPoster; - query: IJournalReportQuery; - baseCurrency: string; + readonly tenantId: number; + readonly journal: IJournalPoster; + readonly query: IJournalReportQuery; + readonly baseCurrency: string; readonly contactsById: Map; /** diff --git a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts index 99455a886..7723b1598 100644 --- a/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts +++ b/server/src/services/FinancialStatements/JournalSheet/JournalSheetService.ts @@ -76,6 +76,8 @@ export default class JournalSheetService { contactRepository, } = this.tenancy.repositories(tenantId); + const { AccountTransaction } = this.tenancy.models(tenantId); + const filter = { ...this.defaultQuery, ...query, @@ -98,12 +100,12 @@ export default class JournalSheetService { const contactsByIdMap = transformToMap(contacts, 'id'); // Retrieve all journal transactions based on the given query. - const transactions = await transactionsRepository.journal({ - fromDate: filter.fromDate, - toDate: filter.toDate, - transactionsTypes: filter.transactionTypes, - fromAmount: filter.fromRange, - toAmount: filter.toRange, + const transactions = await AccountTransaction.query().onBuild((query) => { + if (filter.fromRange || filter.toRange) { + query.modify('filterAmountRange', filter.fromRange, filter.toRange); + } + query.modify('filterDateRange', filter.fromDate, filter.toDate); + query.orderBy(['date', 'createdAt', 'indexGroup', 'index']); }); // Transform the transactions array to journal collection. const transactionsJournal = Journal.fromTransactions( diff --git a/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItems.ts b/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItems.ts index c6b119ae7..a507ba590 100644 --- a/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItems.ts +++ b/server/src/services/FinancialStatements/PurchasesByItems/PurchasesByItems.ts @@ -99,10 +99,10 @@ export default class InventoryValuationReport extends FinancialSheet { return { quantityPurchased, purchaseCost, - quantityPurchasedFormatted: this.formatNumber(quantityPurchased, { + quantityPurchasedFormatted: this.formatTotalNumber(quantityPurchased, { money: false, }), - purchaseCostFormatted: this.formatNumber(purchaseCost), + purchaseCostFormatted: this.formatTotalNumber(purchaseCost), currencyCode: this.baseCurrency, }; } @@ -115,6 +115,6 @@ export default class InventoryValuationReport extends FinancialSheet { const items = this.itemsSection(); const total = this.totalSection(items); - return { items, total }; + return items.length > 0 ? { items, total } : {}; } } diff --git a/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts b/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts index d527609a7..cde8721b0 100644 --- a/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts +++ b/server/src/services/FinancialStatements/SalesByItems/SalesByItems.ts @@ -99,10 +99,10 @@ export default class SalesByItemsReport extends FinancialSheet { return { quantitySold, soldCost, - quantitySoldFormatted: this.formatNumber(quantitySold, { + quantitySoldFormatted: this.formatTotalNumber(quantitySold, { money: false, }), - soldCostFormatted: this.formatNumber(soldCost), + soldCostFormatted: this.formatTotalNumber(soldCost), currencyCode: this.baseCurrency, }; } @@ -115,6 +115,6 @@ export default class SalesByItemsReport extends FinancialSheet { const items = this.itemsSection(); const total = this.totalSection(items); - return { items, total }; + return items.length > 0 ? { items, total } : {}; } } diff --git a/server/src/services/Inventory/Inventory.ts b/server/src/services/Inventory/Inventory.ts index d98686548..64b03fa15 100644 --- a/server/src/services/Inventory/Inventory.ts +++ b/server/src/services/Inventory/Inventory.ts @@ -55,6 +55,7 @@ export default class InventoryService { date: transaction.date, entryId: entry.id, createdAt: transaction.createdAt, + costAccountId: entry.costAccountId, })); } diff --git a/server/src/services/Inventory/InventoryAdjustmentService.ts b/server/src/services/Inventory/InventoryAdjustmentService.ts index b953859ec..2019c4a94 100644 --- a/server/src/services/Inventory/InventoryAdjustmentService.ts +++ b/server/src/services/Inventory/InventoryAdjustmentService.ts @@ -20,7 +20,6 @@ import ItemsService from 'services/Items/ItemsService'; import DynamicListingService from 'services/DynamicListing/DynamicListService'; import HasTenancyService from 'services/Tenancy/TenancyService'; import InventoryService from './Inventory'; -import { increment } from 'utils'; const ERRORS = { INVENTORY_ADJUSTMENT_NOT_FOUND: 'INVENTORY_ADJUSTMENT_NOT_FOUND', diff --git a/server/src/services/Inventory/InventoryAverageCost.ts b/server/src/services/Inventory/InventoryAverageCost.ts index f5a55c42f..ca7801dd6 100644 --- a/server/src/services/Inventory/InventoryAverageCost.ts +++ b/server/src/services/Inventory/InventoryAverageCost.ts @@ -165,6 +165,8 @@ export default class InventoryAverageCostMethod 'transactionId', 'transactionType', 'createdAt', + + 'costAccountId', ]), }; switch (invTransaction.direction) { diff --git a/server/src/services/Purchases/BillPayments/BillPayments.ts b/server/src/services/Purchases/BillPayments/BillPayments.ts index 28947c38d..896f6c5dc 100644 --- a/server/src/services/Purchases/BillPayments/BillPayments.ts +++ b/server/src/services/Purchases/BillPayments/BillPayments.ts @@ -25,7 +25,7 @@ import TenancyService from 'services/Tenancy/TenancyService'; import DynamicListingService from 'services/DynamicListing/DynamicListService'; import { entriesAmountDiff, formatDateFields } from 'utils'; import { ServiceError } from 'exceptions'; -import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes'; +import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from 'data/AccountTypes'; import VendorsService from 'services/Contacts/VendorsService'; import { ERRORS } from './constants'; @@ -113,7 +113,14 @@ export default class BillPaymentsService implements IBillPaymentsService { if (!paymentAccount) { throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_NOT_FOUND); } - if (!paymentAccount.isParentType(ACCOUNT_PARENT_TYPE.CURRENT_ASSET)) { + // Validate the payment account type. + if ( + !paymentAccount.isAccountType([ + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]) + ) { throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_NOT_CURRENT_ASSET_TYPE); } return paymentAccount; diff --git a/server/src/services/Sales/PaymentReceives/PaymentsReceives.ts b/server/src/services/Sales/PaymentReceives/PaymentsReceives.ts index 51aa786c0..0db0a1931 100644 --- a/server/src/services/Sales/PaymentReceives/PaymentsReceives.ts +++ b/server/src/services/Sales/PaymentReceives/PaymentsReceives.ts @@ -30,7 +30,7 @@ import { ServiceError } from 'exceptions'; import CustomersService from 'services/Contacts/CustomersService'; import ItemsEntriesService from 'services/Items/ItemsEntriesService'; import JournalCommands from 'services/Accounting/JournalCommands'; -import { ACCOUNT_PARENT_TYPE } from 'data/AccountTypes'; +import { ACCOUNT_PARENT_TYPE, ACCOUNT_TYPE } from 'data/AccountTypes'; import AutoIncrementOrdersService from '../AutoIncrementOrdersService'; import { ERRORS } from './constants'; @@ -129,8 +129,14 @@ export default class PaymentReceiveService implements IPaymentsReceiveService { if (!depositAccount) { throw new ServiceError(ERRORS.DEPOSIT_ACCOUNT_NOT_FOUND); } - // Detarmines whether the account is cash equivalents. - if (!depositAccount.isParentType(ACCOUNT_PARENT_TYPE.CURRENT_ASSET)) { + // Detarmines whether the account is cash, bank or other current asset. + if ( + !depositAccount.isAccountType([ + ACCOUNT_TYPE.CASH, + ACCOUNT_TYPE.BANK, + ACCOUNT_TYPE.OTHER_CURRENT_ASSET, + ]) + ) { throw new ServiceError(ERRORS.DEPOSIT_ACCOUNT_INVALID_TYPE); } return depositAccount; diff --git a/server/src/utils/index.ts b/server/src/utils/index.ts index 82246a0f2..0e1f83bd4 100644 --- a/server/src/utils/index.ts +++ b/server/src/utils/index.ts @@ -2,6 +2,7 @@ import bcrypt from 'bcryptjs'; import moment from 'moment'; import _ from 'lodash'; import accounting from 'accounting'; +import Currencies from 'js-money/lib/currency'; import definedOptions from 'data/options'; const hashPassword = (password) => @@ -224,6 +225,10 @@ const getNegativeFormat = (formatName) => { } }; +const getCurrencySign = (currencyCode) => { + return _.get(Currencies, `${currencyCode}.symbol`); +}; + const formatNumber = ( balance, { @@ -234,10 +239,11 @@ const formatNumber = ( thousand = ',', decimal = '.', zeroSign = '', - symbol = '$', money = true, + currencyCode } ) => { + const symbol = getCurrencySign(currencyCode); const negForamt = getNegativeFormat(negativeFormat); const format = '%s%v';