import OrderValidationError, { OrderValidationErrorMessage, OrderValidationErrorType } from '@errors/order-validation.errors'; const { logger } = require('@deliverysolutions/logger'); import { OrderEventController, OrderEventLogDto, TypeEnum } from '@deliverysolutions/event-logger'; import { Feature, saveCurrencyConversionMeteringData } from '@deliverysolutions/metering'; import { GenericObject } from '@interfaces/types'; import { LITERALS } from '@constants/rates.constant'; import { HttpService } from './http.service'; const orderEventController = new OrderEventController(); const CURRENCY_API_URL = process.env.CURRENCY_API_URL; const EXCHANGE_RATES_API_KEY = process.env.EXCHANGE_RATES_API_KEY; const EXTERNAL_SERVICE_TIMEOUT = process.env.EXTERNAL_SERVICE_TIMEOUT; const request = new HttpService(); export default class Currency { constructor() { } /** * * @method: This function is used to log exchangeRate usage in metering collection */ async meteringUsage({ base, to, tenantId, orderId, orderExternalId, isSuccess }: GenericObject) { try { saveCurrencyConversionMeteringData({ feature: Feature.RATE_CONVERSION, tenantId: tenantId || null, orderId: orderId || null, orderExternalId: orderExternalId || LITERALS.NA, status: isSuccess === true ? 'success' : 'failure', from: base || LITERALS.NA, to: to || LITERALS.NA, }); } catch (error) { logger.error(`Error occured while saving usage data in metering collection for orderId: ${orderId}, Error: ${error}`); } } async convertCurrencies({ base, to, val, tenantId, orderId, orderExternalId }: GenericObject) { base = base ? base.toUpperCase() : base; to = to ? to.toUpperCase() : to; let requestURL = `${CURRENCY_API_URL}latest?access_key=${EXCHANGE_RATES_API_KEY}&base=${base}`; let response: any; if (!val || base === to) { return val; } try { orderEventController.create({ orderId: orderId ? orderId : '', from: 'DS', to: 'Exchange Rate API', objective: 'Converting currencies', type: TypeEnum.API_REQUEST, orderStatus: 'ESTIMATES_RECEIVED', details: JSON.stringify({ base, to, amount: val }), } as OrderEventLogDto); response = await request.get(requestURL, request.optionsFactory(null, null, Number(EXTERNAL_SERVICE_TIMEOUT))); if (response['rates'][to]) { const exchangeRate = response['rates'][to]; response = val * exchangeRate; this.meteringUsage({ base, to, tenantId, orderId, orderExternalId, isSuccess: true }); orderEventController.create({ orderId: orderId ? orderId : '', from: 'Exchange Rate API', to: 'DS', objective: 'Currency Conversion Response', type: TypeEnum.API_RESPONSE_SUCCESS, orderStatus: 'ESTIMATES_RECEIVED', details: JSON.stringify({ from: base, to, exchangeRate, afterConversion: response }), } as OrderEventLogDto); return response; } else { //It is being handled in catch block with our standard approach throw new Error(); } } catch (exception) { this.meteringUsage({ base, to, tenantId, orderId, orderExternalId, isSuccess: false }); const err = new OrderValidationError( OrderValidationErrorType.INVALID_ORDER_DATA, OrderValidationErrorMessage.UNSUPPORTED_CURRENCY ); orderEventController.create({ orderId: orderId ? orderId : '', from: 'Exchange Rate API', to: 'DS', objective: 'Currency Conversion Request Failed', type: TypeEnum.API_RESPONSE_FAILURE, orderStatus: 'ESTIMATES_RECEIVED', details: JSON.stringify({ error: response ?? err }), } as OrderEventLogDto); throw err; } } }