diff --git a/packages/server/src/api/controllers/ExchangeRates.ts b/packages/server/src/api/controllers/ExchangeRates.ts index 5a935a173..63c476bf9 100644 --- a/packages/server/src/api/controllers/ExchangeRates.ts +++ b/packages/server/src/api/controllers/ExchangeRates.ts @@ -1,6 +1,6 @@ import { Service, Inject } from 'typedi'; import { Router, Request, Response, NextFunction } from 'express'; -import { query } from 'express-validator'; +import { query, oneOf } from 'express-validator'; import asyncMiddleware from '@/api/middleware/asyncMiddleware'; import BaseController from './BaseController'; import { ServiceError } from '@/exceptions'; @@ -20,7 +20,12 @@ export default class ExchangeRatesController extends BaseController { router.get( '/latest', - [query('to_currency').exists().isString()], + [ + oneOf([ + query('to_currency').exists().isString().isISO4217(), + query('from_currency').exists().isString().isISO4217(), + ]), + ], this.validationResult, asyncMiddleware(this.latestExchangeRate.bind(this)), this.handleServiceError diff --git a/packages/server/src/interfaces/ExchangeRate.ts b/packages/server/src/interfaces/ExchangeRate.ts index 757ca5f3d..45080fc0f 100644 --- a/packages/server/src/interfaces/ExchangeRate.ts +++ b/packages/server/src/interfaces/ExchangeRate.ts @@ -1,5 +1,6 @@ export interface ExchangeRateLatestDTO { toCurrency: string; + fromCurrency: string; } export interface EchangeRateLatestPOJO { diff --git a/packages/server/src/services/ExchangeRates/ExchangeRatesService.ts b/packages/server/src/services/ExchangeRates/ExchangeRatesService.ts index ae322cdff..4cde544ad 100644 --- a/packages/server/src/services/ExchangeRates/ExchangeRatesService.ts +++ b/packages/server/src/services/ExchangeRates/ExchangeRatesService.ts @@ -2,6 +2,7 @@ import { Service } from 'typedi'; import { ExchangeRate } from '@/lib/ExchangeRate/ExchangeRate'; import { ExchangeRateServiceType } from '@/lib/ExchangeRate/types'; import { EchangeRateLatestPOJO, ExchangeRateLatestDTO } from '@/interfaces'; +import { TenantMetadata } from '@/system/models'; @Service() export class ExchangeRatesService { @@ -15,14 +16,20 @@ export class ExchangeRatesService { tenantId: number, exchangeRateLatestDTO: ExchangeRateLatestDTO ): Promise { + const organization = await TenantMetadata.query().findOne({ tenantId }); + + // Assign the organization base currency as a default currency + // if no currency is provided + const fromCurrency = + exchangeRateLatestDTO.fromCurrency || organization.baseCurrency; + const toCurrency = + exchangeRateLatestDTO.toCurrency || organization.baseCurrency; + const exchange = new ExchangeRate(ExchangeRateServiceType.OpenExchangeRate); - const exchangeRate = await exchange.latest( - 'USD', - exchangeRateLatestDTO.toCurrency - ); + const exchangeRate = await exchange.latest(fromCurrency, toCurrency); return { - baseCurrency: 'USD', + baseCurrency: fromCurrency, toCurrency: exchangeRateLatestDTO.toCurrency, exchangeRate, }; diff --git a/packages/server/src/system/models/TenantMetadata.ts b/packages/server/src/system/models/TenantMetadata.ts index 4664cfd6d..7040a6a68 100644 --- a/packages/server/src/system/models/TenantMetadata.ts +++ b/packages/server/src/system/models/TenantMetadata.ts @@ -1,6 +1,8 @@ import BaseModel from 'models/Model'; export default class TenantMetadata extends BaseModel { + baseCurrency: string; + /** * Table name. */ diff --git a/packages/webapp/src/containers/Entries/AutoExchangeProvider.tsx b/packages/webapp/src/containers/Entries/AutoExchangeProvider.tsx index dcaf86283..c4b5ea1f9 100644 --- a/packages/webapp/src/containers/Entries/AutoExchangeProvider.tsx +++ b/packages/webapp/src/containers/Entries/AutoExchangeProvider.tsx @@ -20,13 +20,16 @@ function AutoExchangeRateProvider({ children }: AutoExchangeRateProviderProps) { // Retrieves the exchange rate. const { data: autoExchangeRate, isLoading: isAutoExchangeRateLoading } = - useLatestExchangeRate(autoExRateCurrency, { - enabled: Boolean(autoExRateCurrency), - refetchOnWindowFocus: false, - staleTime: 0, - cacheTime: 0, - retry: 0, - }); + useLatestExchangeRate( + { fromCurrency: autoExRateCurrency }, + { + enabled: Boolean(autoExRateCurrency), + refetchOnWindowFocus: false, + staleTime: 0, + cacheTime: 0, + retry: 0, + }, + ); const value = { autoExRateCurrency, diff --git a/packages/webapp/src/hooks/query/exchangeRates.tsx b/packages/webapp/src/hooks/query/exchangeRates.tsx index a0f58f7ac..36700276b 100644 --- a/packages/webapp/src/hooks/query/exchangeRates.tsx +++ b/packages/webapp/src/hooks/query/exchangeRates.tsx @@ -3,15 +3,23 @@ import { useQuery } from 'react-query'; import QUERY_TYPES from './types'; import useApiRequest from '../useRequest'; +interface LatestExchangeRateQuery { + fromCurrency?: string; + toCurrency?: string; +} + /** * Retrieves latest exchange rate. * @param {number} customerId - Customer id. */ -export function useLatestExchangeRate(toCurrency: string, props) { +export function useLatestExchangeRate( + { toCurrency, fromCurrency }: LatestExchangeRateQuery, + props, +) { const apiRequest = useApiRequest(); return useQuery( - [QUERY_TYPES.EXCHANGE_RATE, toCurrency], + [QUERY_TYPES.EXCHANGE_RATE, toCurrency, fromCurrency], () => apiRequest .http({ @@ -19,6 +27,7 @@ export function useLatestExchangeRate(toCurrency: string, props) { method: 'get', params: { to_currency: toCurrency, + from_currency: fromCurrency, }, }) .then((res) => res.data),