mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
fix(connector): convert cents to dollar before sending to connector (#699)
Co-authored-by: Jagan Elavarasan <jaganelavarasan@gmail.com> Co-authored-by: Arjun Karthik <m.arjunkarthik@gmail.com> Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
@ -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<Self, Self::Error> {
|
||||
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<F, T> TryFrom<types::ResponseRouterData<F, AirwallexAuthUpdateResponse, T,
|
||||
pub struct AirwallexPaymentsCaptureRequest {
|
||||
// Unique ID to be sent for each transaction/operation request to the connector
|
||||
request_id: String,
|
||||
amount: Option<i64>,
|
||||
amount: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequest {
|
||||
@ -153,7 +154,13 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for AirwallexPaymentsCaptureRequ
|
||||
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
|
||||
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<i64>,
|
||||
amount: Option<f32>,
|
||||
//ID of the PaymentConsent related to this PaymentIntent
|
||||
payment_consent_id: Option<String>,
|
||||
next_action: Option<AirwallexPaymentsNextAction>,
|
||||
@ -277,18 +284,21 @@ impl<F, T>
|
||||
pub struct AirwallexRefundRequest {
|
||||
// Unique ID to be sent for each transaction/operation request to the connector
|
||||
request_id: String,
|
||||
amount: Option<i64>,
|
||||
amount: Option<String>,
|
||||
reason: Option<String>,
|
||||
//Identifier for the PaymentIntent for which Refund is requested
|
||||
payment_intent_id: String,
|
||||
}
|
||||
|
||||
impl<F> TryFrom<&types::RefundsRouterData<F>> for AirwallexRefundRequest {
|
||||
type Error = error_stack::Report<errors::ParsingError>;
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||
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<RefundStatus> 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,
|
||||
|
||||
@ -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<F>
|
||||
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 {
|
||||
|
||||
@ -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<String>,
|
||||
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<i64>,
|
||||
amount: Option<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest {
|
||||
@ -92,10 +91,14 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for BluesnapCaptureRequest {
|
||||
fn try_from(item: &types::PaymentsCaptureRouterData) -> Result<Self, Self::Error> {
|
||||
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<F, T>
|
||||
|
||||
#[derive(Default, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct BluesnapRefundRequest {
|
||||
amount: Option<i64>,
|
||||
amount: Option<String>,
|
||||
reason: Option<String>,
|
||||
}
|
||||
|
||||
@ -241,7 +244,10 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for BluesnapRefundRequest {
|
||||
fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
|
||||
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,
|
||||
)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -596,30 +596,42 @@ impl TryFrom<types::RefundsResponseRouterData<api::Execute, NuveiPaymentsRespons
|
||||
fn try_from(
|
||||
item: types::RefundsResponseRouterData<api::Execute, NuveiPaymentsResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
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<types::RefundsResponseRouterData<api::RSync, NuveiPaymentsResponse>
|
||||
fn try_from(
|
||||
item: types::RefundsResponseRouterData<api::RSync, NuveiPaymentsResponse>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
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,
|
||||
|
||||
@ -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<i64>,
|
||||
currency: storage_models::enums::Currency,
|
||||
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
|
||||
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<String, error_stack::Report<errors::ConnectorError>> {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user