From 3e88319222ebaae0c59d68f0b045d9e4381df204 Mon Sep 17 00:00:00 2001 From: SamraatBansal <55536657+SamraatBansal@users.noreply.github.com> Date: Wed, 1 Mar 2023 23:53:10 +0530 Subject: [PATCH] fix(connector): convert cents to dollar before sending to connector (#699) Co-authored-by: Jagan Elavarasan Co-authored-by: Arjun Karthik Co-authored-by: Arun Raj M --- .../src/connector/airwallex/transformers.rs | 28 ++++--- .../src/connector/applepay/transformers.rs | 7 +- .../src/connector/bluesnap/transformers.rs | 22 ++++-- .../src/connector/braintree/transformers.rs | 3 +- .../src/connector/nuvei/transformers.rs | 74 ++++++++++++------- crates/router/src/connector/utils.rs | 32 ++++++++ 6 files changed, 121 insertions(+), 45 deletions(-) diff --git a/crates/router/src/connector/airwallex/transformers.rs b/crates/router/src/connector/airwallex/transformers.rs index f4757ce340..b33a8383dd 100644 --- a/crates/router/src/connector/airwallex/transformers.rs +++ b/crates/router/src/connector/airwallex/transformers.rs @@ -4,6 +4,7 @@ use url::Url; use uuid::Uuid; use crate::{ + connector::utils, core::errors, pii::{self, Secret}, services, @@ -14,7 +15,7 @@ use crate::{ pub struct AirwallexIntentRequest { // Unique ID to be sent for each transaction/operation request to the connector request_id: String, - amount: i64, + amount: String, currency: enums::Currency, //ID created in merchant's order system that corresponds to this PaymentIntent. merchant_order_id: String, @@ -26,7 +27,7 @@ impl TryFrom<&types::PaymentsAuthorizeSessionTokenRouterData> for AirwallexInten ) -> Result { Ok(Self { request_id: Uuid::new_v4().to_string(), - amount: item.request.amount, + amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?, currency: item.request.currency, merchant_order_id: item.payment_id.clone(), }) @@ -145,7 +146,7 @@ impl TryFrom, + amount: Option, } impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequest { @@ -153,7 +154,13 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequ fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { Ok(Self { request_id: Uuid::new_v4().to_string(), - amount: item.request.amount_to_capture, + amount: match item.request.amount_to_capture { + Some(_a) => Some(utils::to_currency_base_unit( + item.request.amount, + item.request.currency, + )?), + _ => None, + }, }) } } @@ -224,7 +231,7 @@ pub struct AirwallexPaymentsResponse { status: AirwallexPaymentStatus, //Unique identifier for the PaymentIntent id: String, - amount: Option, + amount: Option, //ID of the PaymentConsent related to this PaymentIntent payment_consent_id: Option, next_action: Option, @@ -277,18 +284,21 @@ impl pub struct AirwallexRefundRequest { // Unique ID to be sent for each transaction/operation request to the connector request_id: String, - amount: Option, + amount: Option, reason: Option, //Identifier for the PaymentIntent for which Refund is requested payment_intent_id: String, } impl TryFrom<&types::RefundsRouterData> for AirwallexRefundRequest { - type Error = error_stack::Report; + type Error = error_stack::Report; fn try_from(item: &types::RefundsRouterData) -> Result { Ok(Self { request_id: Uuid::new_v4().to_string(), - amount: Some(item.request.refund_amount), + amount: Some(utils::to_currency_base_unit( + item.request.refund_amount, + item.request.currency, + )?), reason: item.request.reason.clone(), payment_intent_id: item.request.connector_transaction_id.clone(), }) @@ -320,7 +330,7 @@ impl From for enums::RefundStatus { pub struct RefundResponse { //A unique number that tags a credit or debit card transaction when it goes from the merchant's bank through to the cardholder's bank. acquirer_reference_number: String, - amount: i64, + amount: f32, //Unique identifier for the Refund id: String, status: RefundStatus, diff --git a/crates/router/src/connector/applepay/transformers.rs b/crates/router/src/connector/applepay/transformers.rs index 4bdfdac287..948a0e9f89 100644 --- a/crates/router/src/connector/applepay/transformers.rs +++ b/crates/router/src/connector/applepay/transformers.rs @@ -3,7 +3,7 @@ use common_utils::ext_traits::ValueExt; use error_stack::ResultExt; use masking::{Deserialize, Serialize}; -use crate::{core::errors, types, utils::OptionExt}; +use crate::{connector::utils, core::errors, types, utils::OptionExt}; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -134,7 +134,10 @@ impl let amount_info = AmountInfo { label: metadata.payment_request_data.label, label_type: "final".to_string(), - amount: (item.data.request.amount / 100).to_string(), + amount: utils::to_currency_base_unit( + item.data.request.amount, + item.data.request.currency, + )?, }; let payment_request = PaymentRequest { diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index c0a93e4c66..f614e2b66c 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::{ + connector::utils, core::errors, pii::{self, Secret}, types::{self, api, storage::enums, transformers::ForeignTryFrom}, @@ -9,11 +10,10 @@ use crate::{ #[derive(Debug, Serialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct BluesnapPaymentsRequest { - amount: i64, + amount: String, #[serde(flatten)] payment_method: PaymentMethodDetails, currency: enums::Currency, - soft_descriptor: Option, card_transaction_type: BluesnapTxnType, } @@ -51,10 +51,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { )), }?; Ok(Self { - amount: item.request.amount, + amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?, payment_method, currency: item.request.currency, - soft_descriptor: item.description.clone(), card_transaction_type: auth_mode, }) } @@ -84,7 +83,7 @@ impl TryFrom<&types::PaymentsCancelRouterData> for BluesnapVoidRequest { pub struct BluesnapCaptureRequest { card_transaction_type: BluesnapTxnType, transaction_id: String, - amount: Option, + amount: Option, } impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest { @@ -92,10 +91,14 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest { fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { let card_transaction_type = BluesnapTxnType::Capture; let transaction_id = item.request.connector_transaction_id.to_string(); + let amount = utils::to_currency_base_unit_from_optional_amount( + item.request.amount_to_capture, + item.request.currency, + )?; Ok(Self { card_transaction_type, transaction_id, - amount: item.request.amount_to_capture, + amount: Some(amount), }) } } @@ -232,7 +235,7 @@ impl #[derive(Default, Debug, Eq, PartialEq, Serialize)] pub struct BluesnapRefundRequest { - amount: Option, + amount: Option, reason: Option, } @@ -241,7 +244,10 @@ impl TryFrom<&types::RefundsRouterData> for BluesnapRefundRequest { fn try_from(item: &types::RefundsRouterData) -> Result { Ok(Self { reason: item.request.reason.clone(), - amount: Some(item.request.refund_amount), + amount: Some(utils::to_currency_base_unit( + item.request.refund_amount, + item.request.currency, + )?), }) } } diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs index 59d25a146d..c2ab2b9a5c 100644 --- a/crates/router/src/connector/braintree/transformers.rs +++ b/crates/router/src/connector/braintree/transformers.rs @@ -4,6 +4,7 @@ use masking::Secret; use serde::{Deserialize, Serialize}; use crate::{ + connector::utils, consts, core::errors, types::{self, api, storage::enums}, @@ -91,7 +92,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest { Some(enums::CaptureMethod::Automatic) | None ); - let amount = item.request.amount.to_string(); + let amount = utils::to_currency_base_unit(item.request.amount, item.request.currency)?; let device_data = DeviceData {}; let options = PaymentOptions { submit_for_settlement, diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index bcff824151..50cf95e13c 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -596,30 +596,42 @@ impl TryFrom, ) -> Result { - let refund_status = item - .response + let response = item.response; + let http_code = item.http_code; + let refund_status = response .transaction_status .clone() .map(|a| a.into()) - .unwrap_or_else(|| enums::RefundStatus::Failure); - let refund_response = match item.response.status { + .unwrap_or(enums::RefundStatus::Failure); + let refund_response = match response.status { NuveiPaymentStatus::Error => Err(types::ErrorResponse { - code: item - .response + code: response .err_code .map(|c| c.to_string()) .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), - message: item - .response + message: response .reason .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), reason: None, - status_code: item.http_code, - }), - _ => Ok(types::RefundsResponseData { - connector_refund_id: item.response.transaction_id.ok_or(errors::ParsingError)?, - refund_status, + status_code: http_code, }), + _ => match response.transaction_status { + Some(NuveiTransactionStatus::Error) => Err(types::ErrorResponse { + code: response + .gw_error_code + .map(|c| c.to_string()) + .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), + message: response + .gw_error_reason + .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + reason: None, + status_code: http_code, + }), + _ => Ok(types::RefundsResponseData { + connector_refund_id: response.transaction_id.ok_or(errors::ParsingError)?, + refund_status, + }), + }, }; Ok(Self { response: refund_response, @@ -635,30 +647,42 @@ impl TryFrom fn try_from( item: types::RefundsResponseRouterData, ) -> Result { - let refund_status = item - .response + let response = item.response; + let http_code = item.http_code; + let refund_status = response .transaction_status .clone() .map(|a| a.into()) .unwrap_or(enums::RefundStatus::Failure); - let refund_response = match item.response.status { + let refund_response = match response.status { NuveiPaymentStatus::Error => Err(types::ErrorResponse { - code: item - .response + code: response .err_code .map(|c| c.to_string()) .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), - message: item - .response + message: response .reason .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), reason: None, - status_code: item.http_code, - }), - _ => Ok(types::RefundsResponseData { - connector_refund_id: item.response.transaction_id.ok_or(errors::ParsingError)?, - refund_status, + status_code: http_code, }), + _ => match response.transaction_status { + Some(NuveiTransactionStatus::Error) => Err(types::ErrorResponse { + code: response + .gw_error_code + .map(|c| c.to_string()) + .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), + message: response + .gw_error_reason + .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + reason: None, + status_code: http_code, + }), + _ => Ok(types::RefundsResponseData { + connector_refund_id: response.transaction_id.ok_or(errors::ParsingError)?, + refund_status, + }), + }, }; Ok(Self { response: refund_response, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index f4bc2d1cdb..40f52b6cc1 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -323,3 +323,35 @@ pub fn get_header_key_value<'a>( errors::ConnectorError::WebhookSourceVerificationFailed ))? } + +pub fn to_currency_base_unit_from_optional_amount( + amount: Option, + currency: storage_models::enums::Currency, +) -> Result> { + match amount { + Some(a) => to_currency_base_unit(a, currency), + _ => Err(errors::ConnectorError::MissingRequiredField { + field_name: "amount", + } + .into()), + } +} + +pub fn to_currency_base_unit( + amount: i64, + currency: storage_models::enums::Currency, +) -> Result> { + let amount_u32 = u32::try_from(amount) + .into_report() + .change_context(errors::ConnectorError::RequestEncodingFailed)?; + match currency { + storage_models::enums::Currency::JPY | storage_models::enums::Currency::KRW => { + Ok(amount.to_string()) + } + storage_models::enums::Currency::BHD + | storage_models::enums::Currency::JOD + | storage_models::enums::Currency::KWD + | storage_models::enums::Currency::OMR => Ok((f64::from(amount_u32) / 1000.0).to_string()), + _ => Ok((f64::from(amount_u32) / 100.0).to_string()), + } +}