diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index c65f30150a..33e9579d7b 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -776,7 +776,7 @@ pub enum PaymentMethodData { BankTransfer(Box), Crypto(CryptoData), MandatePayment, - Reward(RewardData), + Reward, Upi(UpiData), Voucher(VoucherData), GiftCard(Box), diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs index e22122138e..9be092a672 100644 --- a/crates/router/src/compatibility/stripe/errors.rs +++ b/crates/router/src/compatibility/stripe/errors.rs @@ -225,6 +225,8 @@ pub enum StripeErrorCode { PaymentMethodUnactivated, #[error(error_type = StripeErrorType::HyperswitchError, code = "", message = "{entity} expired or invalid")] HyperswitchUnprocessableEntity { entity: String }, + #[error(error_type = StripeErrorType::InvalidRequestError, code = "", message = "{message}")] + CurrencyNotSupported { message: String }, // [#216]: https://github.com/juspay/hyperswitch/issues/216 // Implement the remaining stripe error codes @@ -553,6 +555,9 @@ impl From for StripeErrorCode { Self::MerchantConnectorAccountDisabled } errors::ApiErrorResponse::NotSupported { .. } => Self::InternalServerError, + errors::ApiErrorResponse::CurrencyNotSupported { message } => { + Self::CurrencyNotSupported { message } + } errors::ApiErrorResponse::FileProviderNotSupported { .. } => { Self::FileProviderNotSupported } @@ -628,6 +633,7 @@ impl actix_web::ResponseError for StripeErrorCode { | Self::FileNotFound | Self::FileNotAvailable | Self::FileProviderNotSupported + | Self::CurrencyNotSupported { .. } | Self::PaymentMethodUnactivated => StatusCode::BAD_REQUEST, Self::RefundFailed | Self::PayoutFailed diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index a1685d5c19..30ed9f5d8d 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -369,7 +369,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AciPaymentsRequest { api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::BankDebit(_) | api::PaymentMethodData::BankTransfer(_) - | api::PaymentMethodData::Reward(_) + | api::PaymentMethodData::Reward | api::PaymentMethodData::GiftCard(_) | api::PaymentMethodData::CardRedirect(_) | api::PaymentMethodData::Upi(_) diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index e50e7a6470..a1e494d4b5 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -299,7 +299,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BluesnapPaymentsRequest { | payments::PaymentMethodData::BankTransfer(_) | payments::PaymentMethodData::Crypto(_) | payments::PaymentMethodData::MandatePayment - | payments::PaymentMethodData::Reward(_) + | payments::PaymentMethodData::Reward | payments::PaymentMethodData::Upi(_) | payments::PaymentMethodData::CardRedirect(_) | payments::PaymentMethodData::Voucher(_) diff --git a/crates/router/src/connector/braintree/braintree_graphql_transformers.rs b/crates/router/src/connector/braintree/braintree_graphql_transformers.rs index b1730fe1b5..2783f948a7 100644 --- a/crates/router/src/connector/braintree/braintree_graphql_transformers.rs +++ b/crates/router/src/connector/braintree/braintree_graphql_transformers.rs @@ -88,7 +88,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BraintreePaymentsRequest { | api_models::payments::PaymentMethodData::BankTransfer(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::GiftCard(_) => { @@ -149,9 +149,7 @@ impl Ok(Self { status: enums::AttemptStatus::from(transaction_data.status.clone()), response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - transaction_data.id.clone(), - ), + resource_id: types::ResponseId::ConnectorTransactionId(transaction_data.id), redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -616,7 +614,7 @@ impl TryFrom<&types::TokenizationRouterData> for BraintreeTokenRequest { | api_models::payments::PaymentMethodData::BankTransfer(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::GiftCard(_) => { diff --git a/crates/router/src/connector/cashtocode.rs b/crates/router/src/connector/cashtocode.rs index cdba0ca6c4..cf417fafe3 100644 --- a/crates/router/src/connector/cashtocode.rs +++ b/crates/router/src/connector/cashtocode.rs @@ -2,13 +2,14 @@ pub mod transformers; use std::fmt::Debug; +use base64::Engine; use diesel_models::enums; use error_stack::{IntoReport, ResultExt}; -use masking::PeekInterface; +use masking::{PeekInterface, Secret}; use transformers as cashtocode; use crate::{ - configs::settings, + configs::settings::{self}, connector::{utils as connector_utils, utils as conn_utils}, core::errors::{self, CustomResult}, db::StorageInterface, @@ -42,33 +43,40 @@ impl api::Refund for Cashtocode {} impl api::RefundExecute for Cashtocode {} impl api::RefundSync for Cashtocode {} -fn get_auth_cashtocode( +fn get_b64_auth_cashtocode( payment_method_type: &Option, - auth_type: &types::ConnectorAuthType, + auth_type: &transformers::CashtocodeAuth, ) -> CustomResult)>, errors::ConnectorError> { - match (*payment_method_type).ok_or_else(conn_utils::missing_field_err("payment_method_type")) { - Ok(reward_type) => match reward_type { - storage::enums::PaymentMethodType::ClassicReward => match auth_type { - types::ConnectorAuthType::BodyKey { api_key, .. } => Ok(vec![( - headers::AUTHORIZATION.to_string(), - format!("Basic {}", api_key.peek()).into_masked(), - )]), - _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), - }, - storage::enums::PaymentMethodType::Evoucher => match auth_type { - types::ConnectorAuthType::BodyKey { key1, .. } => Ok(vec![( - headers::AUTHORIZATION.to_string(), - format!("Basic {}", key1.peek()).into_masked(), - )]), - _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), - }, - _ => Err(error_stack::report!(errors::ConnectorError::NotSupported { - message: reward_type.to_string(), - connector: "cashtocode", - })), - }, - Err(_) => Err(errors::ConnectorError::FailedToObtainAuthType.into()), + fn construct_basic_auth( + username: Option>, + password: Option>, + ) -> Result, errors::ConnectorError> { + let username = username.ok_or(errors::ConnectorError::FailedToObtainAuthType)?; + let password = password.ok_or(errors::ConnectorError::FailedToObtainAuthType)?; + Ok(format!( + "Basic {}", + base64::engine::general_purpose::STANDARD.encode(format!( + "{}:{}", + username.peek(), + password.peek() + )) + ) + .into_masked()) } + + let auth_header = match payment_method_type { + Some(storage::enums::PaymentMethodType::ClassicReward) => construct_basic_auth( + auth_type.username_classic.to_owned(), + auth_type.password_classic.to_owned(), + ), + Some(storage::enums::PaymentMethodType::Evoucher) => construct_basic_auth( + auth_type.username_evoucher.to_owned(), + auth_type.password_evoucher.to_owned(), + ), + _ => return Err(errors::ConnectorError::MissingPaymentMethodType)?, + }?; + + Ok(vec![(headers::AUTHORIZATION.to_string(), auth_header)]) } impl @@ -99,18 +107,6 @@ impl ConnectorCommon for Cashtocode { connectors.cashtocode.base_url.as_ref() } - fn get_auth_header( - &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { - let auth = cashtocode::CashtocodeAuthType::try_from(auth_type) - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; - Ok(vec![( - headers::AUTHORIZATION.to_string(), - auth.api_key.into_masked(), - )]) - } - fn build_error_response( &self, res: Response, @@ -173,13 +169,14 @@ impl ConnectorIntegration auth_type, - Err(err) => return Err(err), - }; + let auth_type = transformers::CashtocodeAuth::try_from(( + &req.connector_auth_type, + &req.request.currency, + ))?; + + let mut api_key = get_b64_auth_cashtocode(&req.request.payment_method_type, &auth_type)?; + header.append(&mut api_key); Ok(header) } diff --git a/crates/router/src/connector/cashtocode/transformers.rs b/crates/router/src/connector/cashtocode/transformers.rs index 69c5c98339..4db1bef7e3 100644 --- a/crates/router/src/connector/cashtocode/transformers.rs +++ b/crates/router/src/connector/cashtocode/transformers.rs @@ -1,4 +1,7 @@ -use common_utils::pii::Email; +use std::collections::HashMap; + +use common_utils::{ext_traits::ValueExt, pii::Email}; +use error_stack::{IntoReport, ResultExt}; use masking::Secret; use serde::{Deserialize, Serialize}; @@ -6,7 +9,7 @@ use crate::{ connector::utils::{self, PaymentsAuthorizeRequestData, RouterData}, core::errors, services, - types::{self, api, storage::enums}, + types::{self, storage::enums}, }; #[derive(Default, Debug, Serialize)] @@ -22,47 +25,39 @@ pub struct CashtocodePaymentsRequest { requested_url: String, cancel_url: String, email: Option, - mid: String, -} - -pub struct CashToCodeMandatoryParams { - pub user_id: Secret, - pub user_alias: Secret, - pub requested_url: String, - pub cancel_url: String, + mid: Secret, } fn get_mid( - payment_method_data: &api::payments::PaymentMethodData, -) -> Result { - match payment_method_data { - api_models::payments::PaymentMethodData::Reward(reward_data) => { - Ok(reward_data.merchant_id.to_string()) - } - _ => Err(errors::ConnectorError::NotImplemented( - "Payment methods".to_string(), - )), + connector_auth_type: &types::ConnectorAuthType, + payment_method_type: Option, + currency: enums::Currency, +) -> Result, errors::ConnectorError> { + match CashtocodeAuth::try_from((connector_auth_type, ¤cy)) { + Ok(cashtocode_auth) => match payment_method_type { + Some(enums::PaymentMethodType::ClassicReward) => Ok(cashtocode_auth + .merchant_id_classic + .ok_or(errors::ConnectorError::FailedToObtainAuthType)?), + Some(enums::PaymentMethodType::Evoucher) => Ok(cashtocode_auth + .merchant_id_evoucher + .ok_or(errors::ConnectorError::FailedToObtainAuthType)?), + _ => Err(errors::ConnectorError::FailedToObtainAuthType), + }, + Err(_) => Err(errors::ConnectorError::FailedToObtainAuthType)?, } } -fn get_mandatory_params( - item: &types::PaymentsAuthorizeRouterData, -) -> Result> { - let customer_id = item.get_customer_id()?; - let url = item.request.get_router_return_url()?; - Ok(CashToCodeMandatoryParams { - user_id: Secret::new(customer_id.to_owned()), - user_alias: Secret::new(customer_id), - requested_url: url.to_owned(), - cancel_url: url, - }) -} - impl TryFrom<&types::PaymentsAuthorizeRouterData> for CashtocodePaymentsRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { - let params: CashToCodeMandatoryParams = get_mandatory_params(item)?; - let mid = get_mid(&item.request.payment_method_data)?; + let customer_id = item.get_customer_id()?; + let url = item.request.get_router_return_url()?; + let mid = get_mid( + &item.connector_auth_type, + item.request.payment_method_type, + item.request.currency, + ) + .into_report()?; match item.payment_method { diesel_models::enums::PaymentMethod::Reward => Ok(Self { amount: utils::to_currency_base_unit_asf64( @@ -71,12 +66,12 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for CashtocodePaymentsRequest )?, transaction_id: item.attempt_id.clone(), currency: item.request.currency, - user_id: params.user_id, + user_id: Secret::new(customer_id.to_owned()), first_name: None, last_name: None, - user_alias: params.user_alias, - requested_url: params.requested_url, - cancel_url: params.cancel_url, + user_alias: Secret::new(customer_id), + requested_url: url.to_owned(), + cancel_url: url, email: item.request.email.clone(), mid, }), @@ -85,23 +80,77 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for CashtocodePaymentsRequest } } +#[derive(Default, Debug, Deserialize)] pub struct CashtocodeAuthType { - pub(super) api_key: Secret, + pub auths: HashMap, +} + +#[derive(Default, Debug, Deserialize)] +pub struct CashtocodeAuth { + pub password_classic: Option>, + pub password_evoucher: Option>, + pub username_classic: Option>, + pub username_evoucher: Option>, + pub merchant_id_classic: Option>, + pub merchant_id_evoucher: Option>, } impl TryFrom<&types::ConnectorAuthType> for CashtocodeAuthType { - type Error = error_stack::Report; + type Error = error_stack::Report; // Assuming ErrorStack is the appropriate error type + fn try_from(auth_type: &types::ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self { - api_key: api_key.to_owned(), - }), + types::ConnectorAuthType::CurrencyAuthKey { auth_key_map } => { + let transformed_auths = auth_key_map + .iter() + .map(|(currency, identity_auth_key)| { + let cashtocode_auth = identity_auth_key + .to_owned() + .parse_value::("CashtocodeAuth") + .change_context(errors::ConnectorError::InvalidDataFormat { + field_name: "auth_key_map", + })?; + + Ok((currency.to_owned(), cashtocode_auth)) + }) + .collect::>()?; + + Ok(Self { + auths: transformed_auths, + }) + } _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()), } } } -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +impl TryFrom<(&types::ConnectorAuthType, &enums::Currency)> for CashtocodeAuth { + type Error = error_stack::Report; + + fn try_from(value: (&types::ConnectorAuthType, &enums::Currency)) -> Result { + let (auth_type, currency) = value; + + if let types::ConnectorAuthType::CurrencyAuthKey { auth_key_map } = auth_type { + if let Some(identity_auth_key) = auth_key_map.get(currency) { + let cashtocode_auth: Self = identity_auth_key + .to_owned() + .parse_value("CashtocodeAuth") + .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + Ok(cashtocode_auth) + } else { + Err(errors::ConnectorError::CurrencyNotSupported { + message: currency.to_string(), + connector: "CashToCode", + } + .into()) + } + } else { + Err(errors::ConnectorError::FailedToObtainAuthType.into()) + } + } +} + +#[derive(Debug, Default, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum CashtocodePaymentStatus { Succeeded, @@ -239,7 +288,7 @@ impl #[derive(Debug, Deserialize)] pub struct CashtocodeErrorResponse { - pub error: u32, + pub error: String, pub error_description: String, pub errors: Option>, } diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index d518222205..a8b521daa9 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -97,7 +97,7 @@ impl TryFrom<&types::TokenizationRouterData> for TokenRequest { | api_models::payments::PaymentMethodData::BankTransfer(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::CardRedirect(_) @@ -273,7 +273,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest { | api_models::payments::PaymentMethodData::BankTransfer(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::CardRedirect(_) @@ -797,7 +797,6 @@ impl From for enums::AttemptStatus { fn from(item: CheckoutRedirectResponseStatus) -> Self { match item { CheckoutRedirectResponseStatus::Success => Self::AuthenticationSuccessful, - CheckoutRedirectResponseStatus::Failure => Self::Failure, } } diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index b1ad8c398a..b8c5caf178 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -721,7 +721,7 @@ impl | payments::PaymentMethodData::BankTransfer(_) | payments::PaymentMethodData::Crypto(_) | payments::PaymentMethodData::MandatePayment - | payments::PaymentMethodData::Reward(_) + | payments::PaymentMethodData::Reward | payments::PaymentMethodData::Upi(_) | payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::CardRedirect(_) @@ -895,7 +895,7 @@ impl TryFrom<(&types::PaymentsCompleteAuthorizeRouterData, String)> for NuveiPay | Some(api::PaymentMethodData::GiftCard(..)) | Some(api::PaymentMethodData::Voucher(..)) | Some(api::PaymentMethodData::CardRedirect(..)) - | Some(api::PaymentMethodData::Reward(..)) + | Some(api::PaymentMethodData::Reward) | Some(api::PaymentMethodData::Upi(..)) | None => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("nuvei"), diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index eee87c7d9e..da2f98d333 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -267,7 +267,7 @@ impl TryFrom<&PaymentMethodData> for SalePaymentMethod { | PaymentMethodData::BankTransfer(_) | PaymentMethodData::Crypto(_) | PaymentMethodData::MandatePayment - | PaymentMethodData::Reward(_) + | PaymentMethodData::Reward | PaymentMethodData::GiftCard(_) | PaymentMethodData::CardRedirect(_) | PaymentMethodData::Upi(_) diff --git a/crates/router/src/connector/stax/transformers.rs b/crates/router/src/connector/stax/transformers.rs index c1f16162fa..a731c3eb57 100644 --- a/crates/router/src/connector/stax/transformers.rs +++ b/crates/router/src/connector/stax/transformers.rs @@ -196,7 +196,7 @@ impl TryFrom<&types::TokenizationRouterData> for StaxTokenRequest { | api::PaymentMethodData::BankTransfer(_) | api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::MandatePayment - | api::PaymentMethodData::Reward(_) + | api::PaymentMethodData::Reward | api::PaymentMethodData::Voucher(_) | api::PaymentMethodData::GiftCard(_) | api::PaymentMethodData::CardRedirect(_) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 1685b8068c..8a566e72d8 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1434,7 +1434,7 @@ fn create_stripe_payment_method( } payments::PaymentMethodData::Crypto(_) | payments::PaymentMethodData::MandatePayment - | payments::PaymentMethodData::Reward(_) + | payments::PaymentMethodData::Reward | payments::PaymentMethodData::Upi(_) | payments::PaymentMethodData::CardRedirect(_) | payments::PaymentMethodData::Voucher(_) @@ -2722,7 +2722,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSo | Some(payments::PaymentMethodData::BankRedirect(..)) | Some(payments::PaymentMethodData::PayLater(..)) | Some(payments::PaymentMethodData::Crypto(..)) - | Some(payments::PaymentMethodData::Reward(..)) + | Some(payments::PaymentMethodData::Reward) | Some(payments::PaymentMethodData::MandatePayment) | Some(payments::PaymentMethodData::Upi(..)) | Some(payments::PaymentMethodData::GiftCard(..)) @@ -3210,7 +3210,7 @@ impl } api::PaymentMethodData::MandatePayment | api::PaymentMethodData::Crypto(_) - | api::PaymentMethodData::Reward(_) + | api::PaymentMethodData::Reward | api::PaymentMethodData::GiftCard(_) | api::PaymentMethodData::Upi(_) | api::PaymentMethodData::CardRedirect(_) diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index 4342b06409..3d467f4198 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -87,7 +87,7 @@ fn fetch_payment_instrument( | api_models::payments::PaymentMethodData::BankTransfer(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::Voucher(_) | api_models::payments::PaymentMethodData::CardRedirect(_) diff --git a/crates/router/src/connector/zen/transformers.rs b/crates/router/src/connector/zen/transformers.rs index 7f8c3d4cd0..851fb2754f 100644 --- a/crates/router/src/connector/zen/transformers.rs +++ b/crates/router/src/connector/zen/transformers.rs @@ -655,7 +655,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for ZenPaymentsRequest { | api_models::payments::PaymentMethodData::BankDebit(_) | api_models::payments::PaymentMethodData::Crypto(_) | api_models::payments::PaymentMethodData::MandatePayment - | api_models::payments::PaymentMethodData::Reward(_) + | api_models::payments::PaymentMethodData::Reward | api_models::payments::PaymentMethodData::Upi(_) | api_models::payments::PaymentMethodData::CardRedirect(_) | api_models::payments::PaymentMethodData::GiftCard(_) => { diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 18191545ae..fcf01e8ac3 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -382,6 +382,11 @@ pub enum ConnectorError { InSufficientBalanceInPaymentMethod, #[error("Server responded with Request Timeout")] RequestTimeoutReceived, + #[error("The given currency method is not configured with the given connector")] + CurrencyNotSupported { + message: String, + connector: &'static str, + }, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/api_error_response.rs b/crates/router/src/core/errors/api_error_response.rs index e0da78cf0d..6546c26e61 100644 --- a/crates/router/src/core/errors/api_error_response.rs +++ b/crates/router/src/core/errors/api_error_response.rs @@ -223,6 +223,8 @@ pub enum ApiErrorResponse { IncorrectPaymentMethodConfiguration, #[error(error_type = ErrorType::InvalidRequestError, code = "WE_05", message = "Unable to process the webhook body")] WebhookUnprocessableEntity, + #[error(error_type = ErrorType::InvalidRequestError, code = "IR_19", message = "{message}")] + CurrencyNotSupported { message: String }, } #[derive(Clone)] diff --git a/crates/router/src/core/errors/transformers.rs b/crates/router/src/core/errors/transformers.rs index d91879ac47..a139261da9 100644 --- a/crates/router/src/core/errors/transformers.rs +++ b/crates/router/src/core/errors/transformers.rs @@ -54,6 +54,9 @@ impl ErrorSwitch for ApiErrorRespon Self::ClientSecretInvalid => { AER::BadRequest(ApiError::new("IR", 9, "The client_secret provided does not match the client_secret associated with the Payment", None)) } + Self::CurrencyNotSupported { message } => { + AER::BadRequest(ApiError::new("IR", 9, message, None)) + } Self::MandateActive => { AER::BadRequest(ApiError::new("IR", 10, "Customer has active mandate/subsciption", None)) } diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index 4f50655e71..f6a7bd60b1 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -173,6 +173,7 @@ impl ConnectorErrorExt for error_stack::Result errors::ConnectorError::InvalidDataFormat { field_name } => { errors::ApiErrorResponse::InvalidDataValue { field_name } }, + errors::ConnectorError::CurrencyNotSupported { message, connector} => errors::ApiErrorResponse::CurrencyNotSupported { message: format!("Credentials for the currency {message} are not configured with the connector {connector}/hyperswitch") }, _ => errors::ApiErrorResponse::InternalServerError, }; err.change_context(error) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index f203aeb646..2e462e4e38 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1301,7 +1301,7 @@ pub async fn make_pm_data<'a, F: Clone, R>( (pm @ Some(api::PaymentMethodData::BankDebit(_)), _) => Ok(pm.to_owned()), (pm @ Some(api::PaymentMethodData::Upi(_)), _) => Ok(pm.to_owned()), (pm @ Some(api::PaymentMethodData::Voucher(_)), _) => Ok(pm.to_owned()), - (pm @ Some(api::PaymentMethodData::Reward(_)), _) => Ok(pm.to_owned()), + (pm @ Some(api::PaymentMethodData::Reward), _) => Ok(pm.to_owned()), (pm @ Some(api::PaymentMethodData::CardRedirect(_)), _) => Ok(pm.to_owned()), (pm @ Some(api::PaymentMethodData::GiftCard(_)), _) => Ok(pm.to_owned()), (pm_opt @ Some(pm @ api::PaymentMethodData::BankTransfer(_)), _) => { @@ -2948,7 +2948,7 @@ pub async fn get_additional_payment_data( api_models::payments::PaymentMethodData::MandatePayment => { api_models::payments::AdditionalPaymentData::MandatePayment {} } - api_models::payments::PaymentMethodData::Reward(_) => { + api_models::payments::PaymentMethodData::Reward => { api_models::payments::AdditionalPaymentData::Reward {} } api_models::payments::PaymentMethodData::Upi(_) => { diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 4b8d880156..324f99700a 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -781,6 +781,9 @@ pub enum ConnectorAuthType { api_secret: Secret, key2: Secret, }, + CurrencyAuthKey { + auth_key_map: HashMap, + }, #[default] NoKey, } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index bfe4450fa6..b04241f599 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -310,7 +310,7 @@ impl ForeignTryFrom for api_enums::Paym api_models::payments::PaymentMethodData::BankDebit(..) => Ok(Self::BankDebit), api_models::payments::PaymentMethodData::BankTransfer(..) => Ok(Self::BankTransfer), api_models::payments::PaymentMethodData::Crypto(..) => Ok(Self::Crypto), - api_models::payments::PaymentMethodData::Reward(..) => Ok(Self::Reward), + api_models::payments::PaymentMethodData::Reward => Ok(Self::Reward), api_models::payments::PaymentMethodData::Upi(..) => Ok(Self::Upi), api_models::payments::PaymentMethodData::Voucher(..) => Ok(Self::Voucher), api_models::payments::PaymentMethodData::GiftCard(..) => Ok(Self::GiftCard), diff --git a/crates/router/tests/connectors/cashtocode.rs b/crates/router/tests/connectors/cashtocode.rs index c78134a1d6..141aee4ff4 100644 --- a/crates/router/tests/connectors/cashtocode.rs +++ b/crates/router/tests/connectors/cashtocode.rs @@ -41,8 +41,8 @@ impl CashtocodeTest { payment_method_data: types::api::PaymentMethodData, ) -> Option { Some(types::PaymentsAuthorizeData { - amount: 3500, - currency: enums::Currency::USD, + amount: 1000, + currency: enums::Currency::EUR, payment_method_data, confirm: true, statement_descriptor_suffix: None, @@ -61,7 +61,7 @@ impl CashtocodeTest { session_token: None, enrolled_for_3ds: false, related_transaction_id: None, - router_return_url: Some(String::from("http://localhost:8080")), + router_return_url: Some(String::from("https://google.com")), webhook_url: None, complete_authorize_url: None, customer_id: Some("John Doe".to_owned()), @@ -86,16 +86,14 @@ impl CashtocodeTest { } } -//fetch payurl for payment's create +//fetch payurl for payment create #[actix_web::test] async fn should_fetch_pay_url_classic() { let authorize_response = CONNECTOR .make_payment( CashtocodeTest::get_payment_authorize_data( Some(enums::PaymentMethodType::ClassicReward), - api_models::payments::PaymentMethodData::Reward(api_models::payments::RewardData { - merchant_id: "1bc20b0a".to_owned(), - }), + api_models::payments::PaymentMethodData::Reward, ), CashtocodeTest::get_payment_info(), ) @@ -113,9 +111,7 @@ async fn should_fetch_pay_url_evoucher() { .make_payment( CashtocodeTest::get_payment_authorize_data( Some(enums::PaymentMethodType::Evoucher), - api_models::payments::PaymentMethodData::Reward(api_models::payments::RewardData { - merchant_id: "befb46ee".to_owned(), - }), + api_models::payments::PaymentMethodData::Reward, ), CashtocodeTest::get_payment_info(), ) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index f9618b98b8..1fcda76183 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7902,15 +7902,10 @@ ] }, { - "type": "object", - "required": [ + "type": "string", + "enum": [ "reward" - ], - "properties": { - "reward": { - "$ref": "#/components/schemas/RewardData" - } - } + ] }, { "type": "object",