diff --git a/client/src/components/DataTableCells/MoneyFieldCell.js b/client/src/components/DataTableCells/MoneyFieldCell.js index 6c6271ee9..710840de3 100644 --- a/client/src/components/DataTableCells/MoneyFieldCell.js +++ b/client/src/components/DataTableCells/MoneyFieldCell.js @@ -39,7 +39,7 @@ const MoneyFieldCellRenderer = ({ className={CLASSES.FILL}> ( } + content={ + + } position={Position.RIGHT_TOP} boundary={'viewport'} > - + {r.amount_formatted} ); /** * Amount popover content line. */ -export const AmountPopoverContentLine = ({ journalEntry }) => { +export const AmountPopoverContentLine = ({ journalEntry, currencyCode }) => { const isCredit = !!journalEntry.credit; const isDebit = !!journalEntry.debit; const { account } = journalEntry; @@ -42,14 +47,14 @@ export const AmountPopoverContentLine = ({ journalEntry }) => {
- C. USD -{' '} + C. -{' '} {account.name} ({account.code})
- D. USD -{' '} + D. -{' '} {account.name} ({account.code})
@@ -60,7 +65,7 @@ export const AmountPopoverContentLine = ({ journalEntry }) => { /** * Amount popover content. */ -export function AmountPopoverContent({ journalEntries }) { +export function AmountPopoverContent({ journalEntries, currencyCode }) { const journalLinesProps = journalEntries.map((journalEntry) => ({ journalEntry, accountId: journalEntry.account_id, @@ -72,6 +77,7 @@ export function AmountPopoverContent({ journalEntries }) { ))} diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesField.js b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesField.js index 5bace16d6..49f138903 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesField.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesField.js @@ -12,15 +12,16 @@ export default function MakeJournalEntriesField() { return (
- {({ form, field: { value }, meta: { error, touched } }) => ( + {({ form:{values ,setFieldValue}, field: { value }, meta: { error, touched } }) => ( { - form.setFieldValue('entries', entries); + setFieldValue('entries', entries); }} entries={value} defaultEntry={defaultEntry} initialLinesNumber={MIN_LINES_NUMBER} error={error} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.js b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.js index 755c44f07..97658ea6f 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.js @@ -65,10 +65,10 @@ function MakeJournalEntriesForm({ } : { ...defaultManualJournal, - ...(journalAutoIncrement) && ({ + ...(journalAutoIncrement && { journal_number: defaultTo(journalNumber, ''), }), - currency_code: defaultTo(baseCurrency, ''), + currency_code: baseCurrency, entries: orderingLinesIndexes(defaultManualJournal.entries), }), }), @@ -111,7 +111,7 @@ function MakeJournalEntriesForm({ } const form = { ...omit(values, ['journal_number', 'journal_number_manually']), - ...(values.journal_number_manually) && ({ + ...(values.journal_number_manually && { journal_number: values.journal_number, }), entries, diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.js b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.js index 9b797dad8..aa037ffb8 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.js @@ -2,12 +2,14 @@ import React from 'react'; import classNames from 'classnames'; import { useFormikContext } from 'formik'; import { CLASSES } from 'common/classes'; -import MakeJournalEntriesHeaderFields from "./MakeJournalEntriesHeaderFields"; +import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields'; import { PageFormBigNumber } from 'components'; import { safeSumBy } from 'utils'; export default function MakeJournalEntriesHeader() { - const { values: { entries } } = useFormikContext(); + const { + values: { entries, currency_code }, + } = useFormikContext(); const totalCredit = safeSumBy(entries, 'credit'); const totalDebit = safeSumBy(entries, 'debit'); @@ -20,8 +22,8 @@ export default function MakeJournalEntriesHeader() {
- ) -} \ No newline at end of file + ); +} diff --git a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js index 0fb099ba3..ac61fadde 100644 --- a/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js +++ b/client/src/containers/Accounting/MakeJournal/MakeJournalEntriesTable.js @@ -23,6 +23,7 @@ export default function MakeJournalEntriesTable({ error, initialLinesNumber = 4, minLinesNumber = 4, + currencyCode, }) { const { accounts, customers } = useMakeJournalFormContext(); @@ -72,7 +73,8 @@ export default function MakeJournalEntriesTable({ contact_type: 'customer', })), autoFocus: ['account_id', 0], + currencyCode, }} /> ); -} \ No newline at end of file +} diff --git a/client/src/containers/Accounting/MakeJournal/components.js b/client/src/containers/Accounting/MakeJournal/components.js index 03174d82d..1a0937d55 100644 --- a/client/src/containers/Accounting/MakeJournal/components.js +++ b/client/src/containers/Accounting/MakeJournal/components.js @@ -1,7 +1,8 @@ import React from 'react'; import { Intent, Position, Button, Tooltip } from '@blueprintjs/core'; -import { FormattedMessage as T, useIntl } from 'react-intl'; +import { FormattedMessage as T } from 'react-intl'; import { Icon, Money, Hint } from 'components'; +import { formatMessage } from 'services/intl'; import { AccountsListFieldCell, MoneyFieldCell, @@ -25,22 +26,36 @@ export function ContactHeaderCell() { ); } +/** + * Credit header cell. + */ +export function CreditHeaderCell({ payload: { currencyCode } }) { + return formatMessage({ id: 'credit_currency' }, { currency: currencyCode }); +} + +/** + * debit header cell. + */ +export function DebitHeaderCell({ payload: { currencyCode } }) { + return formatMessage({ id: 'debit_currency' }, { currency: currencyCode }); +} + /** * Account footer cell. */ -function AccountFooterCell() { - return {'Total USD'}; +function AccountFooterCell({ payload: { currencyCode } }) { + return {`Total ${currencyCode} `}; } /** * Total credit table footer cell. */ -function TotalCreditFooterCell({ rows }) { +function TotalCreditFooterCell({ payload: { currencyCode }, rows }) { const credit = safeSumBy(rows, 'original.credit'); return ( - + ); } @@ -48,12 +63,12 @@ function TotalCreditFooterCell({ rows }) { /** * Total debit table footer cell. */ -function TotalDebitFooterCell({ rows }) { +function TotalDebitFooterCell({ payload: { currencyCode }, rows }) { const debit = safeSumBy(rows, 'original.debit'); return ( - + ); } @@ -88,8 +103,6 @@ export const ActionsCellRenderer = ({ * Retrieve columns of make journal entries table. */ export const useJournalTableEntriesColumns = () => { - const { formatMessage } = useIntl(); - return React.useMemo( () => [ { @@ -113,7 +126,7 @@ export const useJournalTableEntriesColumns = () => { width: 160, }, { - Header: formatMessage({ id: 'credit_currency' }, { currency: 'USD' }), + Header: CreditHeaderCell, accessor: 'credit', Cell: MoneyFieldCell, Footer: TotalCreditFooterCell, @@ -122,7 +135,7 @@ export const useJournalTableEntriesColumns = () => { width: 100, }, { - Header: formatMessage({ id: 'debit_currency' }, { currency: 'USD' }), + Header: DebitHeaderCell, accessor: 'debit', Cell: MoneyFieldCell, Footer: TotalDebitFooterCell, diff --git a/client/src/containers/Accounts/components.js b/client/src/containers/Accounts/components.js index 0ea6e45ea..f9d903088 100644 --- a/client/src/containers/Accounts/components.js +++ b/client/src/containers/Accounts/components.js @@ -117,7 +117,7 @@ export function BalanceCell({ cell }) { return account.amount !== null ? ( - + ) : ( diff --git a/client/src/containers/Accounts/utils.js b/client/src/containers/Accounts/utils.js index 7331d789e..29e4ce466 100644 --- a/client/src/containers/Accounts/utils.js +++ b/client/src/containers/Accounts/utils.js @@ -78,7 +78,7 @@ export const useAccountsTableColumns = () => { { id: 'currency', Header: formatMessage({ id: 'currency' }), - accessor: (row) => 'USD', + accessor: 'currency_code', width: 75, }, { diff --git a/client/src/containers/Entries/ItemsEntriesTable.js b/client/src/containers/Entries/ItemsEntriesTable.js index 491bced8b..c4a482012 100644 --- a/client/src/containers/Entries/ItemsEntriesTable.js +++ b/client/src/containers/Entries/ItemsEntriesTable.js @@ -28,6 +28,7 @@ function ItemsEntriesTable({ errors, onUpdateData, linesNumber, + currencyCode, itemType, // sellable or purchasable }) { const [rows, setRows] = React.useState(initialEntries); @@ -35,13 +36,14 @@ function ItemsEntriesTable({ const [cellsLoading, setCellsLoading] = React.useState(null); // Fetches the item details. - const { data: item, isFetching: isItemFetching, isSuccess: isItemSuccess } = useItem( - rowItem && rowItem.itemId, - { - enabled: !!(rowItem && rowItem.itemId), - }, - ); - + const { + data: item, + isFetching: isItemFetching, + isSuccess: isItemSuccess, + } = useItem(rowItem && rowItem.itemId, { + enabled: !!(rowItem && rowItem.itemId), + }); + // Once the item start loading give the table cells loading state. useEffect(() => { if (rowItem && isItemFetching) { @@ -141,6 +143,7 @@ function ItemsEntriesTable({ updateData: handleUpdateData, removeRow: handleRemoveRow, autoFocus: ['item_id', 0], + currencyCode, }} /> ); diff --git a/client/src/containers/Entries/components.js b/client/src/containers/Entries/components.js index 5fb3c0301..70118e59b 100644 --- a/client/src/containers/Entries/components.js +++ b/client/src/containers/Entries/components.js @@ -8,7 +8,7 @@ import { MoneyFieldCell, ItemsListCell, PercentFieldCell, - NumericInputCell + NumericInputCell, } from 'components/DataTableCells'; /** @@ -62,27 +62,27 @@ export function ActionsCellRenderer({ */ export function QuantityTotalFooterCell({ rows }) { const quantity = safeSumBy(rows, 'original.quantity'); - return { quantity }; + return {quantity}; } /** * Total footer cell. */ -export function TotalFooterCell({ rows }) { +export function TotalFooterCell({ payload: { currencyCode }, rows }) { const total = safeSumBy(rows, 'original.total'); - return { formattedAmount(total, 'USD') }; + return {formattedAmount(total, currencyCode)}; } /** * Total accessor. */ -export function TotalCell({ value }) { - return { formattedAmount(value, 'USD', { noZero: true }) }; +export function TotalCell({ payload: { currencyCode }, value }) { + return {formattedAmount(value, currencyCode, { noZero: true })}; } // Index table cell. -export function IndexTableCell({ row: { index } }){ - return ({index + 1}); +export function IndexTableCell({ row: { index } }) { + return {index + 1}; } /** @@ -167,4 +167,3 @@ export function useEditableItemsEntriesColumns() { [formatMessage], ); } - \ No newline at end of file diff --git a/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesField.js b/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesField.js index 4d579c5df..437b10bb8 100644 --- a/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesField.js +++ b/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesField.js @@ -6,20 +6,23 @@ import { defaultExpenseEntry } from './utils'; /** * Expense form entries field. */ -export default function ExpenseFormEntriesField({ - linesNumber = 4, -}) { +export default function ExpenseFormEntriesField({ linesNumber = 4 }) { return ( - {({ form, field: { value }, meta: { error, touched } }) => ( + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( { - form.setFieldValue('categories', entries); + setFieldValue('categories', entries); }} defaultEntry={defaultExpenseEntry} linesNumber={linesNumber} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesTable.js b/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesTable.js index 1aa3ecaf0..ab1c2cdbc 100644 --- a/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesTable.js +++ b/client/src/containers/Expenses/ExpenseForm/ExpenseFormEntriesTable.js @@ -21,6 +21,7 @@ export default function ExpenseFormEntriesTable({ defaultEntry, error, onChange, + currencyCode, }) { // Expense form context. const { accounts } = useExpenseFormContext(); @@ -69,6 +70,7 @@ export default function ExpenseFormEntriesTable({ updateData: handleUpdateData, removeRow: handleRemoveRow, autoFocus: ['expense_account_id', 0], + currencyCode }} footer={true} /> diff --git a/client/src/containers/Expenses/ExpenseForm/components.js b/client/src/containers/Expenses/ExpenseForm/components.js index adeac0c71..25bd34913 100644 --- a/client/src/containers/Expenses/ExpenseForm/components.js +++ b/client/src/containers/Expenses/ExpenseForm/components.js @@ -1,7 +1,8 @@ import React from 'react'; import { Button, Tooltip, Intent, Position } from '@blueprintjs/core'; -import { FormattedMessage as T, useIntl } from 'react-intl'; +import { FormattedMessage as T } from 'react-intl'; import { Icon, Hint } from 'components'; +import { formatMessage } from 'services/intl'; import { InputGroupCell, MoneyFieldCell, @@ -51,9 +52,16 @@ const ActionsCellRenderer = ({ /** * Amount footer cell. */ -function AmountFooterCell({ rows }) { +function AmountFooterCell({ payload: { currencyCode }, rows }) { const total = safeSumBy(rows, 'original.amount'); - return {formattedAmount(total, 'USD')}; + return {formattedAmount(total, currencyCode)}; +} + +/** + * Expense amount header cell. + */ + export function ExpenseAmountHeaderCell({ payload: { currencyCode } }) { + return formatMessage({ id: 'amount_currency' }, { currency: currencyCode }); } /** @@ -67,7 +75,6 @@ function ExpenseAccountFooterCell() { * Retrieve expense form table entries columns. */ export function useExpenseFormTableColumns() { - const { formatMessage } = useIntl(); return React.useMemo( () => [ @@ -92,7 +99,7 @@ export function useExpenseFormTableColumns() { filterAccountsByRootTypes: ['expense'], }, { - Header: formatMessage({ id: 'amount_currency' }, { currency: 'USD' }), + Header: ExpenseAmountHeaderCell, accessor: 'amount', Cell: MoneyFieldCell, Footer: AmountFooterCell, diff --git a/client/src/containers/Items/components.js b/client/src/containers/Items/components.js index b4f8609ac..f338c0298 100644 --- a/client/src/containers/Items/components.js +++ b/client/src/containers/Items/components.js @@ -181,16 +181,16 @@ export const useItemsTableColumns = () => { { id: 'sell_price', Header: formatMessage({ id: 'sell_price' }), - Cell: SellPriceCell, - accessor: 'sell_price', + // Cell: SellPriceCell, + accessor: 'sell_price_formatted', className: 'sell-price', width: 150, }, { id: 'cost_price', Header: formatMessage({ id: 'cost_price' }), - Cell: CostPriceCell, - accessor: 'cost_price', + // Cell: CostPriceCell, + accessor: 'cost_price_formatted', className: 'cost-price', width: 150, }, diff --git a/client/src/containers/Purchases/Bills/BillForm/BillForm.js b/client/src/containers/Purchases/Bills/BillForm/BillForm.js index 184a19053..869b84a11 100644 --- a/client/src/containers/Purchases/Bills/BillForm/BillForm.js +++ b/client/src/containers/Purchases/Bills/BillForm/BillForm.js @@ -17,13 +17,17 @@ import { AppToaster } from 'components'; import { ERROR } from 'common/errors'; import { useBillFormContext } from './BillFormProvider'; -import { orderingLinesIndexes, safeSumBy } from 'utils'; +import { compose, orderingLinesIndexes, safeSumBy } from 'utils'; import { defaultBill, transformToEditForm } from './utils'; +import withSettings from 'containers/Settings/withSettings'; /** * Bill form. */ -export default function BillForm() { +function BillForm({ + // #withSettings + baseCurrency, +}) { const { formatMessage } = useIntl(); const history = useHistory(); @@ -46,6 +50,7 @@ export default function BillForm() { : { ...defaultBill, entries: orderingLinesIndexes(defaultBill.entries), + currency_code: baseCurrency, }), }), [bill], @@ -142,3 +147,8 @@ export default function BillForm() { ); } +export default compose( + withSettings(({ organizationSettings }) => ({ + baseCurrency: organizationSettings?.baseCurrency, + })), +)(BillForm); diff --git a/client/src/containers/Purchases/Bills/BillForm/BillItemsEntriesEditor.js b/client/src/containers/Purchases/Bills/BillForm/BillItemsEntriesEditor.js index 722608afd..25136485e 100644 --- a/client/src/containers/Purchases/Bills/BillForm/BillItemsEntriesEditor.js +++ b/client/src/containers/Purchases/Bills/BillForm/BillItemsEntriesEditor.js @@ -11,15 +11,20 @@ export default function BillFormBody({ defaultBill }) { return (
- {({ form, field: { value }, meta: { error, touched } }) => ( + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( { - form.setFieldValue('entries', entries); + setFieldValue('entries', entries); }} items={items} errors={error} linesNumber={4} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeEntriesTable.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeEntriesTable.js index 56e1e20eb..2a7383042 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeEntriesTable.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeEntriesTable.js @@ -16,6 +16,7 @@ import { useFormikContext } from 'formik'; export default function PaymentMadeEntriesTable({ onUpdateData, entries, + currencyCode, }) { // Payment made inner context. const { isNewEntriesFetching } = usePaymentMadeInnerContext(); @@ -24,7 +25,9 @@ export default function PaymentMadeEntriesTable({ const columns = usePaymentMadeEntriesTableColumns(); // Formik context. - const { values: { vendor_id } } = useFormikContext(); + const { + values: { vendor_id }, + } = useFormikContext(); // Handle update data. const handleUpdateData = useCallback( @@ -54,10 +57,11 @@ export default function PaymentMadeEntriesTable({ payload={{ errors: [], updateData: handleUpdateData, + currencyCode, }} noResults={noResultsMessage} footer={true} /> ); -} \ No newline at end of file +} diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeForm.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeForm.js index 4f6a938c1..682dba4fb 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeForm.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeForm.js @@ -29,6 +29,7 @@ import { defaultPaymentMade, transformToEditForm, ERRORS } from './utils'; function PaymentMadeForm({ // #withSettings preferredPaymentAccount, + baseCurrency, }) { const history = useHistory(); const { formatMessage } = useIntl(); @@ -54,6 +55,7 @@ function PaymentMadeForm({ : { ...defaultPaymentMade, payment_account_id: defaultTo(preferredPaymentAccount), + currency_code: baseCurrency, entries: orderingLinesIndexes(defaultPaymentMade.entries), }), }), @@ -157,9 +159,10 @@ function PaymentMadeForm({ } export default compose( - withSettings(({ billPaymentSettings }) => ({ + withSettings(({ billPaymentSettings, organizationSettings }) => ({ paymentNextNumber: billPaymentSettings?.next_number, paymentNumberPrefix: billPaymentSettings?.number_prefix, preferredPaymentAccount: parseInt(billPaymentSettings?.withdrawalAccount), + baseCurrency: organizationSettings?.baseCurrency, })), )(PaymentMadeForm); diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormBody.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormBody.js index 9a3a5c200..534c7ab25 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormBody.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFormBody.js @@ -5,18 +5,23 @@ import { CLASSES } from 'common/classes'; import PaymentMadeEntriesTable from './PaymentMadeEntriesTable'; export default function PaymentMadeFormBody() { - return ( + return (
- {({ form, field: { value }, meta: { error, touched } }) => ( - ( + { - form.setFieldValue('entries', newEntries); + setFieldValue('entries', newEntries); }} + currencyCode={values.currency_code} /> )}
- ) -} \ No newline at end of file + ); +} diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/components.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/components.js index a2881df3d..59f949091 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/components.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/components.js @@ -1,5 +1,5 @@ import React from 'react'; -import { useIntl } from "react-intl"; +import { useIntl } from 'react-intl'; import moment from 'moment'; import { Money } from 'components'; import { safeSumBy, formattedAmount } from 'utils'; @@ -10,7 +10,7 @@ function BillNumberAccessor(row) { } function IndexTableCell({ row: { index } }) { - return ({index + 1}); + return {index + 1}; } function BillDateCell({ value }) { @@ -19,35 +19,34 @@ function BillDateCell({ value }) { /** * Balance footer cell. */ -function AmountFooterCell({ rows }) { +function AmountFooterCell({ payload: { currencyCode }, rows }) { const total = safeSumBy(rows, 'original.amount'); - return { formattedAmount(total, 'USD') }; + return {formattedAmount(total, currencyCode)}; } /** * Due amount footer cell. */ -function DueAmountFooterCell({ rows }) { +function DueAmountFooterCell({ payload: { currencyCode }, rows }) { const totalDueAmount = safeSumBy(rows, 'original.due_amount'); - return { formattedAmount(totalDueAmount, 'USD') }; + return {formattedAmount(totalDueAmount, currencyCode)}; } /** * Payment amount footer cell. */ -function PaymentAmountFooterCell({ rows }) { +function PaymentAmountFooterCell({ payload: { currencyCode }, rows }) { const totalPaymentAmount = safeSumBy(rows, 'original.payment_amount'); - return { formattedAmount(totalPaymentAmount, 'USD') }; + return {formattedAmount(totalPaymentAmount, currencyCode)}; } /** * Mobey table cell. */ -function MoneyTableCell({ value }) { - return +function MoneyTableCell({ row: { original }, value }) { + return ; } - /** * Payment made entries table columns */ @@ -63,7 +62,7 @@ export function usePaymentMadeEntriesTableColumns() { width: 40, disableResizing: true, disableSortBy: true, - className: 'index' + className: 'index', }, { Header: formatMessage({ id: 'Date' }), @@ -106,5 +105,5 @@ export function usePaymentMadeEntriesTableColumns() { }, ], [formatMessage], - ) -} \ No newline at end of file + ); +} diff --git a/client/src/containers/Purchases/PaymentMades/PaymentForm/utils.js b/client/src/containers/Purchases/PaymentMades/PaymentForm/utils.js index 7c493336f..be4d85762 100644 --- a/client/src/containers/Purchases/PaymentMades/PaymentForm/utils.js +++ b/client/src/containers/Purchases/PaymentMades/PaymentForm/utils.js @@ -12,6 +12,7 @@ export const defaultPaymentMadeEntry = { currency_code:'', id: null, due_amount: null, + amount:'' }; // Default initial values of payment made. @@ -46,5 +47,7 @@ export const transformToNewPageEntries = (entries) => { return entries.map((entry) => ({ ...transformToForm(entry, defaultPaymentMadeEntry), payment_amount: '', + currency_code:entry.currency_code, + })); } \ No newline at end of file diff --git a/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js b/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js index 8e49ca4db..a6fea267f 100644 --- a/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js +++ b/client/src/containers/Sales/Estimates/EstimateForm/EstimateForm.js @@ -34,6 +34,7 @@ function EstimateForm({ estimateNextNumber, estimateNumberPrefix, estimateIncrementMode, + baseCurrency, }) { const { formatMessage } = useIntl(); const history = useHistory(); @@ -57,10 +58,11 @@ function EstimateForm({ ? { ...transformToEditForm(estimate) } : { ...defaultEstimate, - ...(estimateIncrementMode) && ({ + ...(estimateIncrementMode && { estimate_number: estimateNumber, }), entries: orderingLinesIndexes(defaultEstimate.entries), + currency_code: baseCurrency, }), }), [estimate, estimateNumber, estimateIncrementMode], @@ -101,7 +103,7 @@ function EstimateForm({ } const form = { ...omit(values, ['estimate_number_manually', 'estimate_number']), - ...(values.estimate_number_manually) && ({ + ...(values.estimate_number_manually && { estimate_number: values.estimate_number, }), delivered: submitPayload.deliver, @@ -175,9 +177,10 @@ function EstimateForm({ } export default compose( - withSettings(({ estimatesSettings }) => ({ + withSettings(({ estimatesSettings, organizationSettings }) => ({ estimateNextNumber: estimatesSettings?.nextNumber, estimateNumberPrefix: estimatesSettings?.numberPrefix, estimateIncrementMode: estimatesSettings?.autoIncrement, + baseCurrency: organizationSettings?.baseCurrency, })), )(EstimateForm); diff --git a/client/src/containers/Sales/Estimates/EstimateForm/EstimateItemsEntriesField.js b/client/src/containers/Sales/Estimates/EstimateForm/EstimateItemsEntriesField.js index 52905a2b9..82125ccf2 100644 --- a/client/src/containers/Sales/Estimates/EstimateForm/EstimateItemsEntriesField.js +++ b/client/src/containers/Sales/Estimates/EstimateForm/EstimateItemsEntriesField.js @@ -14,15 +14,20 @@ export default function EstimateFormItemsEntriesField() { return (
- {({ form, field: { value }, meta: { error, touched } }) => ( + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( { - form.setFieldValue('entries', entries); + setFieldValue('entries', entries); }} items={items} errors={error} linesNumber={4} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.js b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.js index e40cd5b0b..d806a1edd 100644 --- a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.js +++ b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.js @@ -34,6 +34,7 @@ function InvoiceForm({ invoiceNextNumber, invoiceNumberPrefix, invoiceIncrementMode, + baseCurrency, }) { const { formatMessage } = useIntl(); const history = useHistory(); @@ -61,11 +62,12 @@ function InvoiceForm({ ? transformToEditForm(invoice) : { ...defaultInvoice, - ...(invoiceIncrementMode) && ({ + ...(invoiceIncrementMode && { invoice_no: invoiceNumber, }), entries: orderingLinesIndexes(defaultInvoice.entries), ...newInvoice, + currency_code: baseCurrency, }), }), [invoice, newInvoice, invoiceNumber, invoiceIncrementMode], @@ -91,7 +93,7 @@ function InvoiceForm({ } const form = { ...omit(values, ['invoice_no', 'invoice_no_manually']), - ...(values.invoice_no_manually) && ({ + ...(values.invoice_no_manually && { invoice_no: values.invoice_no, }), delivered: submitPayload.deliver, @@ -169,9 +171,10 @@ function InvoiceForm({ export default compose( withDashboardActions, withMediaActions, - withSettings(({ invoiceSettings }) => ({ + withSettings(({ invoiceSettings, organizationSettings }) => ({ invoiceNextNumber: invoiceSettings?.nextNumber, invoiceNumberPrefix: invoiceSettings?.numberPrefix, invoiceIncrementMode: invoiceSettings?.incrementMode, + baseCurrency: organizationSettings?.baseCurrency, })), )(InvoiceForm); diff --git a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceItemsEntriesEditorField.js b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceItemsEntriesEditorField.js index 6502f736a..4adf2e44e 100644 --- a/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceItemsEntriesEditorField.js +++ b/client/src/containers/Sales/Invoices/InvoiceForm/InvoiceItemsEntriesEditorField.js @@ -14,15 +14,20 @@ export default function InvoiceItemsEntriesEditorField() { return (
- {({ form, field: { value }, meta: { error, touched } }) => ( + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( { - form.setFieldValue('entries', entries); + setFieldValue('entries', entries); }} items={items} errors={error} linesNumber={4} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.js index f48c45542..be606d09f 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveForm.js @@ -37,6 +37,7 @@ function PaymentReceiveForm({ paymentReceiveNextNumber, paymentReceiveNumberPrefix, paymentReceiveAutoIncrement, + baseCurrency, }) { const history = useHistory(); const { formatMessage } = useIntl(); @@ -68,6 +69,7 @@ function PaymentReceiveForm({ payment_receive_no: nextPaymentNumber, deposit_account_id: defaultTo(preferredDepositAccount, ''), }), + currency_code: baseCurrency, }), }), [ @@ -199,11 +201,12 @@ function PaymentReceiveForm({ } export default compose( - withSettings(({ paymentReceiveSettings }) => ({ + withSettings(({ paymentReceiveSettings, organizationSettings }) => ({ paymentReceiveSettings, paymentReceiveNextNumber: paymentReceiveSettings?.nextNumber, paymentReceiveNumberPrefix: paymentReceiveSettings?.numberPrefix, paymentReceiveAutoIncrement: paymentReceiveSettings?.autoIncrement, preferredDepositAccount: paymentReceiveSettings?.depositAccount, + baseCurrency: organizationSettings?.baseCurrency, })), )(PaymentReceiveForm); diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormBody.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormBody.js index c64456d94..2dc08a9c1 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormBody.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormBody.js @@ -11,12 +11,13 @@ export default function PaymentReceiveFormBody() { return (
- {({ form, field: { value } }) => ( + {({ form: { values, setFieldValue }, field: { value } }) => ( { - form.setFieldValue('entries', newEntries); + setFieldValue('entries', newEntries); }} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveItemsTable.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveItemsTable.js index 40986c467..192ba8ecd 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveItemsTable.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveItemsTable.js @@ -15,6 +15,7 @@ import { compose, updateTableRow } from 'utils'; export default function PaymentReceiveItemsTable({ entries, onUpdateData, + currencyCode }) { // Payment receive form context. const { @@ -52,6 +53,7 @@ export default function PaymentReceiveItemsTable({ payload={{ errors: [], updateData: handleUpdateData, + currencyCode }} noResults={noResultsMessage} footer={true} diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/components.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/components.js index aabc012dc..87d63db8e 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/components.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/components.js @@ -9,14 +9,14 @@ import { safeSumBy, formattedAmount } from 'utils'; * Invoice date cell. */ function InvoiceDateCell({ value }) { - return { moment(value).format('YYYY MMM DD') } + return {moment(value).format('YYYY MMM DD')}; } /** * Index table cell. */ function IndexCell({ row: { index } }) { - return ({index + 1}); + return {index + 1}; } /** @@ -29,33 +29,32 @@ function InvNumberCellAccessor(row) { /** * Balance footer cell. */ -function BalanceFooterCell({ rows }) { +function BalanceFooterCell({ payload: { currencyCode }, rows }) { const total = safeSumBy(rows, 'original.amount'); - return { formattedAmount(total, 'USD') }; + return {formattedAmount(total, currencyCode)}; } /** * Due amount footer cell. */ -function DueAmountFooterCell({ rows }) { +function DueAmountFooterCell({ payload: { currencyCode }, rows }) { const totalDueAmount = safeSumBy(rows, 'original.due_amount'); - return { formattedAmount(totalDueAmount, 'USD') }; + return {formattedAmount(totalDueAmount, currencyCode)}; } /** * Payment amount footer cell. */ -function PaymentAmountFooterCell({ rows }) { +function PaymentAmountFooterCell({ payload: { currencyCode }, rows }) { const totalPaymentAmount = safeSumBy(rows, 'original.payment_amount'); - return { formattedAmount(totalPaymentAmount, 'USD') }; + return {formattedAmount(totalPaymentAmount, currencyCode)}; } - /** * Mobey table cell. */ -function MoneyTableCell({ value }) { - return +function MoneyTableCell({ row: { original }, value }) { + return ; } function DateFooterCell() { @@ -77,7 +76,7 @@ export const usePaymentReceiveEntriesColumns = () => { width: 40, disableResizing: true, disableSortBy: true, - className: 'index' + className: 'index', }, { Header: formatMessage({ id: 'Date' }), @@ -88,7 +87,7 @@ export const usePaymentReceiveEntriesColumns = () => { disableSortBy: true, disableResizing: true, width: 250, - className: 'date' + className: 'date', }, { Header: formatMessage({ id: 'invocie_number' }), @@ -125,5 +124,5 @@ export const usePaymentReceiveEntriesColumns = () => { }, ], [formatMessage], - ) -} \ No newline at end of file + ); +}; diff --git a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.js b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.js index 4a5ec4c4f..d9aea669a 100644 --- a/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.js +++ b/client/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.js @@ -50,6 +50,7 @@ export const transformInvoicesNewPageEntries = (invoices) => [ due_amount: invoice.due_amount, date: invoice.invoice_date, amount: invoice.balance, + currency_code:invoice.currency_code, payment_amount: '', invoice_no: invoice.invoice_no, total_payment_amount: invoice.payment_amount, diff --git a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptForm.js b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptForm.js index 4cce838b0..8c5623b9c 100644 --- a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptForm.js +++ b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptForm.js @@ -37,6 +37,7 @@ function ReceiptForm({ receiptNumberPrefix, receiptAutoIncrement, preferredDepositAccount, + baseCurrency, }) { const { formatMessage } = useIntl(); const history = useHistory(); @@ -67,6 +68,7 @@ function ReceiptForm({ }), deposit_account_id: parseInt(preferredDepositAccount), entries: orderingLinesIndexes(defaultReceipt.entries), + currency_code: baseCurrency, }), }), [receipt, preferredDepositAccount, nextReceiptNumber, receiptAutoIncrement], @@ -105,8 +107,9 @@ function ReceiptForm({ } const form = { ...omit(values, ['receipt_number_manually', 'receipt_number']), - ...(values.receipt_number_manually) && ({ + ...(values.receipt_number_manually && { receipt_number: values.receipt_number, + currency_code: baseCurrency, }), closed: submitPayload.status, entries: entries.map((entry) => ({ ...omit(entry, ['total']) })), @@ -182,10 +185,11 @@ function ReceiptForm({ export default compose( withDashboardActions, - withSettings(({ receiptSettings }) => ({ + withSettings(({ receiptSettings, organizationSettings }) => ({ receiptNextNumber: receiptSettings?.nextNumber, receiptNumberPrefix: receiptSettings?.numberPrefix, receiptAutoIncrement: receiptSettings?.autoIncrement, preferredDepositAccount: receiptSettings?.preferredDepositAccount, + baseCurrency: organizationSettings?.baseCurrency, })), )(ReceiptForm); diff --git a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptItemsEntriesEditor.js b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptItemsEntriesEditor.js index 8e152c2b7..581b7f4b0 100644 --- a/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptItemsEntriesEditor.js +++ b/client/src/containers/Sales/Receipts/ReceiptForm/ReceiptItemsEntriesEditor.js @@ -11,15 +11,20 @@ export default function ReceiptItemsEntriesEditor({ defaultReceipt }) { return (
- {({ form, field: { value }, meta: { error, touched } }) => ( + {({ + form: { values, setFieldValue }, + field: { value }, + meta: { error, touched }, + }) => ( { - form.setFieldValue('entries', entries); + setFieldValue('entries', entries); }} items={items} errors={error} linesNumber={4} + currencyCode={values.currency_code} /> )} diff --git a/client/src/containers/Vendors/VendorForm/VendorForm.js b/client/src/containers/Vendors/VendorForm/VendorForm.js index 08cb01299..0a89fdcc6 100644 --- a/client/src/containers/Vendors/VendorForm/VendorForm.js +++ b/client/src/containers/Vendors/VendorForm/VendorForm.js @@ -94,6 +94,7 @@ function VendorForm({ const initialValues = useMemo( () => ({ ...defaultInitialValues, + currency_code: baseCurrency, ...transformToForm(vendor, defaultInitialValues), ...transformToForm(contactDuplicate, defaultInitialValues), }), diff --git a/server/src/api/controllers/Items.ts b/server/src/api/controllers/Items.ts index b2ed1f784..44f782ce7 100644 --- a/server/src/api/controllers/Items.ts +++ b/server/src/api/controllers/Items.ts @@ -324,7 +324,9 @@ export default class ItemsController extends BaseController { try { const storedItem = await this.itemsService.getItem(tenantId, itemId); - return res.status(200).send({ item: storedItem }); + return res.status(200).send({ + item: this.transfromToResponse(storedItem) + }); } catch (error) { next(error); } @@ -356,7 +358,7 @@ export default class ItemsController extends BaseController { } = await this.itemsService.itemsList(tenantId, filter); return res.status(200).send({ - items, + items: this.transfromToResponse(items), pagination: this.transfromToResponse(pagination), filter_meta: this.transfromToResponse(filterMeta), }); @@ -390,7 +392,7 @@ export default class ItemsController extends BaseController { filter ); return res.status(200).send({ - items, + items: this.transfromToResponse(items), }); } catch (error) { next(error); diff --git a/server/src/database/migrations/20200105195823_create_manual_journals_table.js b/server/src/database/migrations/20200105195823_create_manual_journals_table.js index 426fa5536..8c2714648 100644 --- a/server/src/database/migrations/20200105195823_create_manual_journals_table.js +++ b/server/src/database/migrations/20200105195823_create_manual_journals_table.js @@ -6,6 +6,7 @@ exports.up = function(knex) { table.string('reference').index(); table.string('journal_type').index(); table.decimal('amount', 13, 3); + table.string('currency_code', 3); table.date('date').index(); table.string('description'); table.date('published_at').index(); diff --git a/server/src/interfaces/ManualJournal.ts b/server/src/interfaces/ManualJournal.ts index 7d47ae28f..2e18d61b5 100644 --- a/server/src/interfaces/ManualJournal.ts +++ b/server/src/interfaces/ManualJournal.ts @@ -9,6 +9,7 @@ export interface IManualJournal { journalType: string; reference: string; amount: number; + currencyCode: string; publishedAt: Date | null; description: string; userId: number; diff --git a/server/src/models/ManualJournal.js b/server/src/models/ManualJournal.js index a3330ef5f..3035101b9 100644 --- a/server/src/models/ManualJournal.js +++ b/server/src/models/ManualJournal.js @@ -1,6 +1,6 @@ import { Model } from 'objection'; import TenantModel from 'models/TenantModel'; -import { query } from 'winston'; +import { formatNumber } from 'utils'; export default class ManualJournal extends TenantModel { /** @@ -21,7 +21,14 @@ export default class ManualJournal extends TenantModel { * Virtual attributes. */ static get virtualAttributes() { - return ['isPublished']; + return ['isPublished', 'amountFormatted']; + } + + /** + * Retrieve the amount formatted value. + */ + get amountFormatted() { + return formatNumber(this.amount, { currencyCode: this.currencyCode }); } /** diff --git a/server/src/services/Items/ItemsService.ts b/server/src/services/Items/ItemsService.ts index 6673f34d5..4fb06bd14 100644 --- a/server/src/services/Items/ItemsService.ts +++ b/server/src/services/Items/ItemsService.ts @@ -22,6 +22,7 @@ import { ACCOUNT_TYPE, } from 'data/AccountTypes'; import { ERRORS } from './constants'; +import { formatNumber } from 'utils'; @Service() export default class ItemsService implements IItemsService { @@ -289,12 +290,12 @@ export default class ItemsService implements IItemsService { } /** - * Validate the item inventory account whether modified and item + * Validate the item inventory account whether modified and item * has assocaited inventory transactions. - * @param {numnber} tenantId - * @param {IItem} oldItem - * @param {IItemDTO} newItemDTO - * @returns + * @param {numnber} tenantId + * @param {IItem} oldItem + * @param {IItemDTO} newItemDTO + * @returns */ async validateItemInvnetoryAccountModified( tenantId: number, @@ -418,11 +419,7 @@ export default class ItemsService implements IItemsService { ); } - await this.validateItemInvnetoryAccountModified( - tenantId, - oldItem, - itemDTO - ); + await this.validateItemInvnetoryAccountModified(tenantId, oldItem, itemDTO); const newItem = await Item.query().patchAndFetchById(itemId, { ...itemModel, @@ -525,7 +522,7 @@ export default class ItemsService implements IItemsService { if (!item) { throw new ServiceError(ERRORS.NOT_FOUND); } - return item; + return this.transformItemToResponse(tenantId, item); } /** @@ -540,7 +537,7 @@ export default class ItemsService implements IItemsService { Item, itemsFilter ); - const { results, pagination } = await Item.query() + const { results: items, pagination } = await Item.query() .onBuild((builder) => { builder.withGraphFetched('inventoryAccount'); builder.withGraphFetched('sellAccount'); @@ -551,6 +548,10 @@ export default class ItemsService implements IItemsService { }) .pagination(itemsFilter.page - 1, itemsFilter.pageSize); + const results = items.map((item) => + this.transformItemToResponse(tenantId, item) + ); + return { items: results, pagination, @@ -583,7 +584,7 @@ export default class ItemsService implements IItemsService { builder.where('name', 'LIKE', `%${itemsFilter.keyword}%`); } }); - return items; + return items.map((item) => this.transformItemToResponse(tenantId, item)); } /** @@ -630,4 +631,24 @@ export default class ItemsService implements IItemsService { throw new ServiceError(ERRORS.ITEM_HAS_ASSOCIATED_INVENTORY_ADJUSTMENT); } } + + /** + * Transformes the item object to response. + * @param {number} tenantId - + * @param {IItem} item - + * @returns + */ + private transformItemToResponse(tenantId: number, item: IItem) { + // Settings tenant service. + const settings = this.tenancy.settings(tenantId); + const currencyCode = settings.get({ + group: 'organization', key: 'base_currency', + }); + + return { + ...item, + sellPriceFormatted: formatNumber(item.sellPrice, { currencyCode }), + costPriceFormatted: formatNumber(item.costPrice, { currencyCode }), + }; + } } diff --git a/server/src/services/ManualJournals/ManualJournalsService.ts b/server/src/services/ManualJournals/ManualJournalsService.ts index 1101b5403..180b27059 100644 --- a/server/src/services/ManualJournals/ManualJournalsService.ts +++ b/server/src/services/ManualJournals/ManualJournalsService.ts @@ -344,6 +344,11 @@ export default class ManualJournalsService implements IManualJournalsService { const journalNumber = manualJournalDTO.journalNumber || autoNextNumber; + // Settings tenant service. + const settings = this.tenancy.settings(tenantId); + const currencyCode = settings.get({ + group: 'organization', key: 'base_currency', + }); // Validate manual journal number require. this.validateJournalNoRequire(journalNumber); @@ -353,6 +358,7 @@ export default class ManualJournalsService implements IManualJournalsService { ? { publishedAt: moment().toMySqlDateTime() } : {}), amount, + currencyCode, date, journalNumber, userId: authorizedUser.id,