-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(currency_conversion): add currency conversion feature (#2948)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
- Loading branch information
1 parent
0e66b1b
commit c0116db
Showing
27 changed files
with
1,501 additions
and
10 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use common_utils::events::ApiEventMetric; | ||
|
||
/// QueryParams to be send to convert the amount -> from_currency -> to_currency | ||
#[derive(Debug, serde::Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub struct CurrencyConversionParams { | ||
pub amount: i64, | ||
pub to_currency: String, | ||
pub from_currency: String, | ||
} | ||
|
||
/// Response to be send for convert currency route | ||
#[derive(Debug, serde::Serialize, serde::Deserialize)] | ||
#[serde(rename_all = "snake_case")] | ||
pub struct CurrencyConversionResponse { | ||
pub converted_amount: String, | ||
pub currency: String, | ||
} | ||
|
||
impl ApiEventMetric for CurrencyConversionResponse {} | ||
impl ApiEventMetric for CurrencyConversionParams {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "currency_conversion" | ||
description = "Currency conversion for cost based routing" | ||
version = "0.1.0" | ||
edition.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
[dependencies] | ||
# First party crates | ||
common_enums = { version = "0.1.0", path = "../common_enums", package = "common_enums" } | ||
|
||
# Third party crates | ||
rust_decimal = "1.29" | ||
rusty-money = { version = "0.4.0", features = ["iso", "crypto"] } | ||
serde = { version = "1.0.163", features = ["derive"] } | ||
thiserror = "1.0.43" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
use common_enums::Currency; | ||
use rust_decimal::Decimal; | ||
use rusty_money::Money; | ||
|
||
use crate::{ | ||
error::CurrencyConversionError, | ||
types::{currency_match, ExchangeRates}, | ||
}; | ||
|
||
pub fn convert( | ||
ex_rates: &ExchangeRates, | ||
from_currency: Currency, | ||
to_currency: Currency, | ||
amount: i64, | ||
) -> Result<Decimal, CurrencyConversionError> { | ||
let money_minor = Money::from_minor(amount, currency_match(from_currency)); | ||
let base_currency = ex_rates.base_currency; | ||
if to_currency == base_currency { | ||
ex_rates.forward_conversion(*money_minor.amount(), from_currency) | ||
} else if from_currency == base_currency { | ||
ex_rates.backward_conversion(*money_minor.amount(), to_currency) | ||
} else { | ||
let base_conversion_amt = | ||
ex_rates.forward_conversion(*money_minor.amount(), from_currency)?; | ||
ex_rates.backward_conversion(base_conversion_amt, to_currency) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
#![allow(clippy::expect_used)] | ||
use std::collections::HashMap; | ||
|
||
use crate::types::CurrencyFactors; | ||
#[test] | ||
fn currency_to_currency_conversion() { | ||
use super::*; | ||
let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new(); | ||
let inr_conversion_rates = | ||
CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5)); | ||
let szl_conversion_rates = | ||
CurrencyFactors::new(Decimal::new(194423, 4), Decimal::new(514, 4)); | ||
let convert_from = Currency::SZL; | ||
let convert_to = Currency::INR; | ||
let amount = 2000; | ||
let base_currency = Currency::USD; | ||
conversion.insert(convert_from, inr_conversion_rates); | ||
conversion.insert(convert_to, szl_conversion_rates); | ||
let sample_rate = ExchangeRates::new(base_currency, conversion); | ||
let res = | ||
convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency"); | ||
println!( | ||
"The conversion from {} {} to {} is {:?}", | ||
amount, convert_from, convert_to, res | ||
); | ||
} | ||
|
||
#[test] | ||
fn currency_to_base_conversion() { | ||
use super::*; | ||
let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new(); | ||
let inr_conversion_rates = | ||
CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5)); | ||
let usd_conversion_rates = CurrencyFactors::new(Decimal::new(1, 0), Decimal::new(1, 0)); | ||
let convert_from = Currency::INR; | ||
let convert_to = Currency::USD; | ||
let amount = 2000; | ||
let base_currency = Currency::USD; | ||
conversion.insert(convert_from, inr_conversion_rates); | ||
conversion.insert(convert_to, usd_conversion_rates); | ||
let sample_rate = ExchangeRates::new(base_currency, conversion); | ||
let res = | ||
convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency"); | ||
println!( | ||
"The conversion from {} {} to {} is {:?}", | ||
amount, convert_from, convert_to, res | ||
); | ||
} | ||
|
||
#[test] | ||
fn base_to_currency_conversion() { | ||
use super::*; | ||
let mut conversion: HashMap<Currency, CurrencyFactors> = HashMap::new(); | ||
let inr_conversion_rates = | ||
CurrencyFactors::new(Decimal::new(823173, 4), Decimal::new(1214, 5)); | ||
let usd_conversion_rates = CurrencyFactors::new(Decimal::new(1, 0), Decimal::new(1, 0)); | ||
let convert_from = Currency::USD; | ||
let convert_to = Currency::INR; | ||
let amount = 2000; | ||
let base_currency = Currency::USD; | ||
conversion.insert(convert_from, usd_conversion_rates); | ||
conversion.insert(convert_to, inr_conversion_rates); | ||
let sample_rate = ExchangeRates::new(base_currency, conversion); | ||
let res = | ||
convert(&sample_rate, convert_from, convert_to, amount).expect("converted_currency"); | ||
println!( | ||
"The conversion from {} {} to {} is {:?}", | ||
amount, convert_from, convert_to, res | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#[derive(Debug, thiserror::Error, serde::Serialize)] | ||
#[serde(tag = "type", content = "info", rename_all = "snake_case")] | ||
pub enum CurrencyConversionError { | ||
#[error("Currency Conversion isn't possible")] | ||
DecimalMultiplicationFailed, | ||
#[error("Currency not supported: '{0}'")] | ||
ConversionNotSupported(String), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub mod conversion; | ||
pub mod error; | ||
pub mod types; |
Oops, something went wrong.