mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	refactor(connector): [Klarna] Refactor Authorize call and configs for prod (#4750)
Co-authored-by: Samraat Bansal <samraat.bansal@juspay.in>
This commit is contained in:
		| @ -195,7 +195,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url =  "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ gocardless.base_url = "https://api.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://iata-pay.iata.org/api/v1" | iatapay.base_url = "https://iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.klarna.com/" | ||||||
| mifinity.base_url = "https://secure.mifinity.com/" | mifinity.base_url = "https://secure.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
| @ -53,7 +53,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
| @ -197,7 +197,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
| @ -404,8 +404,6 @@ debit = { currency = "USD" } | |||||||
|  |  | ||||||
| [pm_filters.klarna] | [pm_filters.klarna] | ||||||
| klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,EUR,EUR,CAD,CZK,DKK,EUR,EUR,EUR,EUR,EUR,EUR,EUR,NZD,NOK,PLN,EUR,EUR,SEK,CHF,GBP,USD" } | klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,CH,GB,US", currency = "AUD,EUR,EUR,CAD,CZK,DKK,EUR,EUR,EUR,EUR,EUR,EUR,EUR,NZD,NOK,PLN,EUR,EUR,SEK,CHF,GBP,USD" } | ||||||
| credit = { not_available_flows = { capture_method = "manual" } } |  | ||||||
| debit = { not_available_flows = { capture_method = "manual" } } |  | ||||||
|  |  | ||||||
| [pm_filters.zen] | [pm_filters.zen] | ||||||
| credit = { not_available_flows = { capture_method = "manual" } } | credit = { not_available_flows = { capture_method = "manual" } } | ||||||
|  | |||||||
| @ -133,7 +133,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
| @ -97,6 +97,16 @@ pub struct ApiModelMetaData { | |||||||
|     pub three_ds_requestor_name: Option<String>, |     pub three_ds_requestor_name: Option<String>, | ||||||
|     pub three_ds_requestor_id: Option<String>, |     pub three_ds_requestor_id: Option<String>, | ||||||
|     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, |     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, | ||||||
|  |     pub klarna_region: Option<KlarnaEndpoint>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[serde_with::skip_serializing_none] | ||||||
|  | #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] | ||||||
|  |  | ||||||
|  | pub enum KlarnaEndpoint { | ||||||
|  |     Europe, | ||||||
|  |     NorthAmerica, | ||||||
|  |     Oceania, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[serde_with::skip_serializing_none] | #[serde_with::skip_serializing_none] | ||||||
| @ -199,4 +209,5 @@ pub struct DashboardMetaData { | |||||||
|     pub three_ds_requestor_name: Option<String>, |     pub three_ds_requestor_name: Option<String>, | ||||||
|     pub three_ds_requestor_id: Option<String>, |     pub three_ds_requestor_id: Option<String>, | ||||||
|     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, |     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, | ||||||
|  |     pub klarna_region: Option<KlarnaEndpoint>, | ||||||
| } | } | ||||||
|  | |||||||
| @ -71,6 +71,15 @@ pub enum ApplePayTomlConfig { | |||||||
|     Zen(ZenApplePay), |     Zen(ZenApplePay), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[serde_with::skip_serializing_none] | ||||||
|  | #[derive(Debug, Clone, serde::Serialize, Deserialize)] | ||||||
|  |  | ||||||
|  | pub enum KlarnaEndpoint { | ||||||
|  |     Europe, | ||||||
|  |     NorthAmerica, | ||||||
|  |     Oceania, | ||||||
|  | } | ||||||
|  |  | ||||||
| #[serde_with::skip_serializing_none] | #[serde_with::skip_serializing_none] | ||||||
| #[derive(Debug, Deserialize, serde::Serialize, Clone)] | #[derive(Debug, Deserialize, serde::Serialize, Clone)] | ||||||
| pub struct ConfigMetadata { | pub struct ConfigMetadata { | ||||||
| @ -91,6 +100,7 @@ pub struct ConfigMetadata { | |||||||
|     pub three_ds_requestor_name: Option<String>, |     pub three_ds_requestor_name: Option<String>, | ||||||
|     pub three_ds_requestor_id: Option<String>, |     pub three_ds_requestor_id: Option<String>, | ||||||
|     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, |     pub pull_mechanism_for_external_3ds_enabled: Option<bool>, | ||||||
|  |     pub klarna_region: Option<KlarnaEndpoint>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[serde_with::skip_serializing_none] | #[serde_with::skip_serializing_none] | ||||||
|  | |||||||
| @ -322,6 +322,7 @@ impl From<ApiModelMetaData> for DashboardMetaData { | |||||||
|             three_ds_requestor_id: api_model.three_ds_requestor_id, |             three_ds_requestor_id: api_model.three_ds_requestor_id, | ||||||
|             pull_mechanism_for_external_3ds_enabled: api_model |             pull_mechanism_for_external_3ds_enabled: api_model | ||||||
|                 .pull_mechanism_for_external_3ds_enabled, |                 .pull_mechanism_for_external_3ds_enabled, | ||||||
|  |             klarna_region: api_model.klarna_region, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -197,6 +197,7 @@ impl DashboardRequestPayload { | |||||||
|             three_ds_requestor_id: None, |             three_ds_requestor_id: None, | ||||||
|             pull_mechanism_for_external_3ds_enabled: None, |             pull_mechanism_for_external_3ds_enabled: None, | ||||||
|             paypal_sdk: None, |             paypal_sdk: None, | ||||||
|  |             klarna_region: None, | ||||||
|         }; |         }; | ||||||
|         let meta_data = match request.metadata { |         let meta_data = match request.metadata { | ||||||
|             Some(data) => data, |             Some(data) => data, | ||||||
| @ -221,6 +222,7 @@ impl DashboardRequestPayload { | |||||||
|         let three_ds_requestor_id = meta_data.three_ds_requestor_id; |         let three_ds_requestor_id = meta_data.three_ds_requestor_id; | ||||||
|         let pull_mechanism_for_external_3ds_enabled = |         let pull_mechanism_for_external_3ds_enabled = | ||||||
|             meta_data.pull_mechanism_for_external_3ds_enabled; |             meta_data.pull_mechanism_for_external_3ds_enabled; | ||||||
|  |         let klarna_region = meta_data.klarna_region; | ||||||
|  |  | ||||||
|         Some(ApiModelMetaData { |         Some(ApiModelMetaData { | ||||||
|             google_pay, |             google_pay, | ||||||
| @ -241,6 +243,7 @@ impl DashboardRequestPayload { | |||||||
|             three_ds_requestor_name, |             three_ds_requestor_name, | ||||||
|             three_ds_requestor_id, |             three_ds_requestor_id, | ||||||
|             pull_mechanism_for_external_3ds_enabled, |             pull_mechanism_for_external_3ds_enabled, | ||||||
|  |             klarna_region, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -1137,8 +1137,11 @@ merchant_secret="Source verification key" | |||||||
| [klarna] | [klarna] | ||||||
| [[klarna.pay_later]] | [[klarna.pay_later]] | ||||||
|   payment_method_type = "klarna" |   payment_method_type = "klarna" | ||||||
| [klarna.connector_auth.HeaderKey] | [klarna.connector_auth.BodyKey] | ||||||
| api_key="Klarna API Key" | key1="Klarna Merchant Username" | ||||||
|  | api_key="Klarna Merchant ID Password" | ||||||
|  | [klarna.metadata] | ||||||
|  | klarna_region="Region of your Klarna Merchant Account" | ||||||
| [klarna.connector_webhook_details] | [klarna.connector_webhook_details] | ||||||
| merchant_secret="Source verification key" | merchant_secret="Source verification key" | ||||||
|  |  | ||||||
|  | |||||||
| @ -954,8 +954,11 @@ merchant_secret="Source verification key" | |||||||
| [klarna] | [klarna] | ||||||
| [[klarna.pay_later]] | [[klarna.pay_later]] | ||||||
|   payment_method_type = "klarna" |   payment_method_type = "klarna" | ||||||
| [klarna.connector_auth.HeaderKey] | [klarna.connector_auth.BodyKey] | ||||||
| api_key="Klarna API Key" | key1="Klarna Merchant Username" | ||||||
|  | api_key="Klarna Merchant ID Password" | ||||||
|  | [klarna.metadata] | ||||||
|  | klarna_region="Region of your Klarna Merchant Account" | ||||||
| [klarna.connector_webhook_details] | [klarna.connector_webhook_details] | ||||||
| merchant_secret="Source verification key" | merchant_secret="Source verification key" | ||||||
|  |  | ||||||
|  | |||||||
| @ -1137,8 +1137,11 @@ merchant_secret="Source verification key" | |||||||
| [klarna] | [klarna] | ||||||
| [[klarna.pay_later]] | [[klarna.pay_later]] | ||||||
|   payment_method_type = "klarna" |   payment_method_type = "klarna" | ||||||
| [klarna.connector_auth.HeaderKey] | [klarna.connector_auth.BodyKey] | ||||||
| api_key="Klarna API Key" | key1="Klarna Merchant Username" | ||||||
|  | api_key="Klarna Merchant ID Password" | ||||||
|  | [klarna.metadata] | ||||||
|  | klarna_region="Region of your Klarna Merchant Account" | ||||||
| [klarna.connector_webhook_details] | [klarna.connector_webhook_details] | ||||||
| merchant_secret="Source verification key" | merchant_secret="Source verification key" | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,8 +1,11 @@ | |||||||
| pub mod transformers; | pub mod transformers; | ||||||
| use std::fmt::Debug; | use std::fmt::Debug; | ||||||
|  |  | ||||||
|  | use api_models::enums; | ||||||
|  | use base64::Engine; | ||||||
| use common_utils::request::RequestContent; | use common_utils::request::RequestContent; | ||||||
| use error_stack::{report, ResultExt}; | use error_stack::{report, ResultExt}; | ||||||
|  | use masking::PeekInterface; | ||||||
| use transformers as klarna; | use transformers as klarna; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
| @ -51,9 +54,14 @@ impl ConnectorCommon for Klarna { | |||||||
|     ) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> { |     ) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> { | ||||||
|         let auth = klarna::KlarnaAuthType::try_from(auth_type) |         let auth = klarna::KlarnaAuthType::try_from(auth_type) | ||||||
|             .change_context(errors::ConnectorError::FailedToObtainAuthType)?; |             .change_context(errors::ConnectorError::FailedToObtainAuthType)?; | ||||||
|  |         let encoded_api_key = consts::BASE64_ENGINE.encode(format!( | ||||||
|  |             "{}:{}", | ||||||
|  |             auth.username.peek(), | ||||||
|  |             auth.password.peek() | ||||||
|  |         )); | ||||||
|         Ok(vec![( |         Ok(vec![( | ||||||
|             headers::AUTHORIZATION.to_string(), |             headers::AUTHORIZATION.to_string(), | ||||||
|             auth.basic_token.into_masked(), |             format!("Basic {encoded_api_key}").into_masked(), | ||||||
|         )]) |         )]) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -74,11 +82,13 @@ impl ConnectorCommon for Klarna { | |||||||
|         let reason = response |         let reason = response | ||||||
|             .error_messages |             .error_messages | ||||||
|             .map(|messages| messages.join(" & ")) |             .map(|messages| messages.join(" & ")) | ||||||
|             .or(response.error_message); |             .or(response.error_message.clone()); | ||||||
|         Ok(types::ErrorResponse { |         Ok(types::ErrorResponse { | ||||||
|             status_code: res.status_code, |             status_code: res.status_code, | ||||||
|             code: response.error_code, |             code: response.error_code, | ||||||
|             message: consts::NO_ERROR_MESSAGE.to_string(), |             message: response | ||||||
|  |                 .error_message | ||||||
|  |                 .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), | ||||||
|             reason, |             reason, | ||||||
|             attempt_status: None, |             attempt_status: None, | ||||||
|             connector_transaction_id: None, |             connector_transaction_id: None, | ||||||
| @ -86,7 +96,21 @@ impl ConnectorCommon for Klarna { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl ConnectorValidation for Klarna {} | impl ConnectorValidation for Klarna { | ||||||
|  |     fn validate_capture_method( | ||||||
|  |         &self, | ||||||
|  |         capture_method: Option<enums::CaptureMethod>, | ||||||
|  |         _pmt: Option<enums::PaymentMethodType>, | ||||||
|  |     ) -> CustomResult<(), errors::ConnectorError> { | ||||||
|  |         let capture_method = capture_method.unwrap_or_default(); | ||||||
|  |         match capture_method { | ||||||
|  |             enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), | ||||||
|  |             enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( | ||||||
|  |                 connector_utils::construct_not_supported_error_report(capture_method, self.id()), | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| impl api::Payment for Klarna {} | impl api::Payment for Klarna {} | ||||||
|  |  | ||||||
| @ -118,6 +142,22 @@ impl | |||||||
|     // Not Implemented (R) |     // Not Implemented (R) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn build_region_specific_endpoint( | ||||||
|  |     base_url: &str, | ||||||
|  |     connector_metadata: &Option<common_utils::pii::SecretSerdeValue>, | ||||||
|  | ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|  |     let klarna_metadata_object = | ||||||
|  |         transformers::KlarnaConnectorMetadataObject::try_from(connector_metadata)?; | ||||||
|  |     let region_based_endpoint = klarna_metadata_object | ||||||
|  |         .klarna_region | ||||||
|  |         .ok_or(errors::ConnectorError::InvalidConnectorConfig { | ||||||
|  |             config: "merchant_connector_account.metadata.region_based_endpoint", | ||||||
|  |         }) | ||||||
|  |         .map(String::from)?; | ||||||
|  |  | ||||||
|  |     Ok(base_url.replace("{{region_based_endpoint}}", ®ion_based_endpoint)) | ||||||
|  | } | ||||||
|  |  | ||||||
| impl | impl | ||||||
|     services::ConnectorIntegration< |     services::ConnectorIntegration< | ||||||
|         api::Session, |         api::Session, | ||||||
| @ -147,14 +187,13 @@ impl | |||||||
|  |  | ||||||
|     fn get_url( |     fn get_url( | ||||||
|         &self, |         &self, | ||||||
|         _req: &types::PaymentsSessionRouterData, |         req: &types::PaymentsSessionRouterData, | ||||||
|         connectors: &settings::Connectors, |         connectors: &settings::Connectors, | ||||||
|     ) -> CustomResult<String, errors::ConnectorError> { |     ) -> CustomResult<String, errors::ConnectorError> { | ||||||
|         Ok(format!( |         let endpoint = | ||||||
|             "{}{}", |             build_region_specific_endpoint(self.base_url(connectors), &req.connector_meta_data)?; | ||||||
|             self.base_url(connectors), |  | ||||||
|             "payments/v1/sessions" |         Ok(format!("{}{}", endpoint, "payments/v1/sessions")) | ||||||
|         )) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn get_request_body( |     fn get_request_body( | ||||||
| @ -162,7 +201,14 @@ impl | |||||||
|         req: &types::PaymentsSessionRouterData, |         req: &types::PaymentsSessionRouterData, | ||||||
|         _connectors: &settings::Connectors, |         _connectors: &settings::Connectors, | ||||||
|     ) -> CustomResult<RequestContent, errors::ConnectorError> { |     ) -> CustomResult<RequestContent, errors::ConnectorError> { | ||||||
|         let connector_req = klarna::KlarnaSessionRequest::try_from(req)?; |         let connector_router_data = klarna::KlarnaRouterData::try_from(( | ||||||
|  |             &self.get_currency_unit(), | ||||||
|  |             req.request.currency, | ||||||
|  |             req.request.amount, | ||||||
|  |             req, | ||||||
|  |         ))?; | ||||||
|  |  | ||||||
|  |         let connector_req = klarna::KlarnaSessionRequest::try_from(&connector_router_data)?; | ||||||
|         // encode only for for urlencoded things. |         // encode only for for urlencoded things. | ||||||
|         Ok(RequestContent::Json(Box::new(connector_req))) |         Ok(RequestContent::Json(Box::new(connector_req))) | ||||||
|     } |     } | ||||||
| @ -304,6 +350,8 @@ impl | |||||||
|             .payment_method_type |             .payment_method_type | ||||||
|             .as_ref() |             .as_ref() | ||||||
|             .ok_or_else(connector_utils::missing_field_err("payment_method_type"))?; |             .ok_or_else(connector_utils::missing_field_err("payment_method_type"))?; | ||||||
|  |         let endpoint = | ||||||
|  |             build_region_specific_endpoint(self.base_url(connectors), &req.connector_meta_data)?; | ||||||
|  |  | ||||||
|         match payment_method_data { |         match payment_method_data { | ||||||
|             domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaSdk { token }) => { |             domain::PaymentMethodData::PayLater(domain::PayLaterData::KlarnaSdk { token }) => { | ||||||
| @ -313,8 +361,7 @@ impl | |||||||
|                         common_enums::PaymentMethodType::Klarna, |                         common_enums::PaymentMethodType::Klarna, | ||||||
|                     ) => Ok(format!( |                     ) => Ok(format!( | ||||||
|                         "{}payments/v1/authorizations/{}/order", |                         "{}payments/v1/authorizations/{}/order", | ||||||
|                         self.base_url(connectors), |                         endpoint, token | ||||||
|                         token |  | ||||||
|                     )), |                     )), | ||||||
|                     ( |                     ( | ||||||
|                         common_enums::PaymentExperience::DisplayQrCode |                         common_enums::PaymentExperience::DisplayQrCode | ||||||
| @ -430,9 +477,13 @@ impl | |||||||
|             | domain::PaymentMethodData::Upi(_) |             | domain::PaymentMethodData::Upi(_) | ||||||
|             | domain::PaymentMethodData::Voucher(_) |             | domain::PaymentMethodData::Voucher(_) | ||||||
|             | domain::PaymentMethodData::GiftCard(_) |             | domain::PaymentMethodData::GiftCard(_) | ||||||
|             | domain::PaymentMethodData::CardToken(_) => Err(error_stack::report!( |             | domain::PaymentMethodData::CardToken(_) => { | ||||||
|                 errors::ConnectorError::MismatchedPaymentData |                 Err(report!(errors::ConnectorError::NotImplemented( | ||||||
|             )), |                     connector_utils::get_unimplemented_payment_method_error_message( | ||||||
|  |                         req.connector.as_str(), | ||||||
|  |                     ), | ||||||
|  |                 ))) | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -1,11 +1,13 @@ | |||||||
| use api_models::payments; | use api_models::payments; | ||||||
| use error_stack::report; | use common_utils::pii; | ||||||
|  | use error_stack::{report, ResultExt}; | ||||||
| use masking::{ExposeInterface, Secret}; | use masking::{ExposeInterface, Secret}; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     connector::utils::{self, PaymentsAuthorizeRequestData, RouterData}, | ||||||
|     core::errors, |     core::errors, | ||||||
|     types::{self, storage::enums}, |     types::{self, storage::enums, transformers::ForeignFrom}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize)] | #[derive(Debug, Serialize)] | ||||||
| @ -32,16 +34,50 @@ impl<T> TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for Klarna | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Default, Debug, Serialize)] | #[derive(Debug, Serialize, Deserialize)] | ||||||
| pub struct KlarnaPaymentsRequest { | pub struct KlarnaConnectorMetadataObject { | ||||||
|     order_lines: Vec<OrderLines>, |     pub klarna_region: Option<KlarnaEndpoint>, | ||||||
|     order_amount: i64, |  | ||||||
|     purchase_country: String, |  | ||||||
|     purchase_currency: enums::Currency, |  | ||||||
|     merchant_reference1: String, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Default, Debug, Deserialize, Serialize)] | #[derive(Debug, Serialize, Deserialize)] | ||||||
|  | pub enum KlarnaEndpoint { | ||||||
|  |     Europe, | ||||||
|  |     NorthAmerica, | ||||||
|  |     Oceania, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl From<KlarnaEndpoint> for String { | ||||||
|  |     fn from(endpoint: KlarnaEndpoint) -> Self { | ||||||
|  |         Self::from(match endpoint { | ||||||
|  |             KlarnaEndpoint::Europe => "", | ||||||
|  |             KlarnaEndpoint::NorthAmerica => "-na", | ||||||
|  |             KlarnaEndpoint::Oceania => "-oc", | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl TryFrom<&Option<pii::SecretSerdeValue>> for KlarnaConnectorMetadataObject { | ||||||
|  |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|  |     fn try_from(meta_data: &Option<pii::SecretSerdeValue>) -> Result<Self, Self::Error> { | ||||||
|  |         let metadata: Self = utils::to_connector_meta_from_secret::<Self>(meta_data.clone()) | ||||||
|  |             .change_context(errors::ConnectorError::InvalidConnectorConfig { | ||||||
|  |                 config: "metadata", | ||||||
|  |             })?; | ||||||
|  |         Ok(metadata) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Default, Debug, Serialize)] | ||||||
|  | pub struct KlarnaPaymentsRequest { | ||||||
|  |     auto_capture: bool, | ||||||
|  |     order_lines: Vec<OrderLines>, | ||||||
|  |     order_amount: i64, | ||||||
|  |     purchase_country: enums::CountryAlpha2, | ||||||
|  |     purchase_currency: enums::Currency, | ||||||
|  |     merchant_reference1: Option<String>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Deserialize, Serialize)] | ||||||
| pub struct KlarnaPaymentsResponse { | pub struct KlarnaPaymentsResponse { | ||||||
|     order_id: String, |     order_id: String, | ||||||
|     fraud_status: KlarnaFraudStatus, |     fraud_status: KlarnaFraudStatus, | ||||||
| @ -50,9 +86,8 @@ pub struct KlarnaPaymentsResponse { | |||||||
| #[derive(Debug, Serialize)] | #[derive(Debug, Serialize)] | ||||||
| pub struct KlarnaSessionRequest { | pub struct KlarnaSessionRequest { | ||||||
|     intent: KlarnaSessionIntent, |     intent: KlarnaSessionIntent, | ||||||
|     purchase_country: String, |     purchase_country: enums::CountryAlpha2, | ||||||
|     purchase_currency: enums::Currency, |     purchase_currency: enums::Currency, | ||||||
|     locale: String, |  | ||||||
|     order_amount: i64, |     order_amount: i64, | ||||||
|     order_lines: Vec<OrderLines>, |     order_lines: Vec<OrderLines>, | ||||||
| } | } | ||||||
| @ -60,20 +95,25 @@ pub struct KlarnaSessionRequest { | |||||||
| #[derive(Deserialize, Serialize, Debug)] | #[derive(Deserialize, Serialize, Debug)] | ||||||
| pub struct KlarnaSessionResponse { | pub struct KlarnaSessionResponse { | ||||||
|     pub client_token: Secret<String>, |     pub client_token: Secret<String>, | ||||||
|     pub session_id: Secret<String>, |     pub session_id: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<&types::PaymentsSessionRouterData> for KlarnaSessionRequest { | impl TryFrom<&KlarnaRouterData<&types::PaymentsSessionRouterData>> for KlarnaSessionRequest { | ||||||
|     type Error = error_stack::Report<errors::ConnectorError>; |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|     fn try_from(item: &types::PaymentsSessionRouterData) -> Result<Self, Self::Error> { |     fn try_from( | ||||||
|         let request = &item.request; |         item: &KlarnaRouterData<&types::PaymentsSessionRouterData>, | ||||||
|  |     ) -> Result<Self, Self::Error> { | ||||||
|  |         let request = &item.router_data.request; | ||||||
|         match request.order_details.clone() { |         match request.order_details.clone() { | ||||||
|             Some(order_details) => Ok(Self { |             Some(order_details) => Ok(Self { | ||||||
|                 intent: KlarnaSessionIntent::Buy, |                 intent: KlarnaSessionIntent::Buy, | ||||||
|                 purchase_country: "US".to_string(), |                 purchase_country: request.country.ok_or( | ||||||
|  |                     errors::ConnectorError::MissingRequiredField { | ||||||
|  |                         field_name: "billing.address.country", | ||||||
|  |                     }, | ||||||
|  |                 )?, | ||||||
|                 purchase_currency: request.currency, |                 purchase_currency: request.currency, | ||||||
|                 order_amount: request.amount, |                 order_amount: item.amount, | ||||||
|                 locale: "en-US".to_string(), |  | ||||||
|                 order_lines: order_details |                 order_lines: order_details | ||||||
|                     .iter() |                     .iter() | ||||||
|                     .map(|data| OrderLines { |                     .map(|data| OrderLines { | ||||||
| @ -85,7 +125,7 @@ impl TryFrom<&types::PaymentsSessionRouterData> for KlarnaSessionRequest { | |||||||
|                     .collect(), |                     .collect(), | ||||||
|             }), |             }), | ||||||
|             None => Err(report!(errors::ConnectorError::MissingRequiredField { |             None => Err(report!(errors::ConnectorError::MissingRequiredField { | ||||||
|                 field_name: "product_name", |                 field_name: "order_details", | ||||||
|             })), |             })), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -104,7 +144,7 @@ impl TryFrom<types::PaymentsSessionResponseRouterData<KlarnaSessionResponse>> | |||||||
|                 session_token: types::api::SessionToken::Klarna(Box::new( |                 session_token: types::api::SessionToken::Klarna(Box::new( | ||||||
|                     payments::KlarnaSessionTokenResponse { |                     payments::KlarnaSessionTokenResponse { | ||||||
|                         session_token: response.client_token.clone().expose(), |                         session_token: response.client_token.clone().expose(), | ||||||
|                         session_id: response.session_id.clone().expose(), |                         session_id: response.session_id.clone(), | ||||||
|                     }, |                     }, | ||||||
|                 )), |                 )), | ||||||
|             }), |             }), | ||||||
| @ -122,9 +162,9 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP | |||||||
|         let request = &item.router_data.request; |         let request = &item.router_data.request; | ||||||
|         match request.order_details.clone() { |         match request.order_details.clone() { | ||||||
|             Some(order_details) => Ok(Self { |             Some(order_details) => Ok(Self { | ||||||
|                 purchase_country: "US".to_string(), |                 purchase_country: item.router_data.get_billing_country()?, | ||||||
|                 purchase_currency: request.currency, |                 purchase_currency: request.currency, | ||||||
|                 order_amount: request.amount, |                 order_amount: item.amount, | ||||||
|                 order_lines: order_details |                 order_lines: order_details | ||||||
|                     .iter() |                     .iter() | ||||||
|                     .map(|data| OrderLines { |                     .map(|data| OrderLines { | ||||||
| @ -134,10 +174,11 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP | |||||||
|                         total_amount: i64::from(data.quantity) * (data.amount), |                         total_amount: i64::from(data.quantity) * (data.amount), | ||||||
|                     }) |                     }) | ||||||
|                     .collect(), |                     .collect(), | ||||||
|                 merchant_reference1: item.router_data.connector_request_reference_id.clone(), |                 merchant_reference1: Some(item.router_data.connector_request_reference_id.clone()), | ||||||
|  |                 auto_capture: request.is_auto_capture()?, | ||||||
|             }), |             }), | ||||||
|             None => Err(report!(errors::ConnectorError::MissingRequiredField { |             None => Err(report!(errors::ConnectorError::MissingRequiredField { | ||||||
|                 field_name: "product_name" |                 field_name: "order_details" | ||||||
|             })), |             })), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -163,11 +204,15 @@ impl TryFrom<types::PaymentsResponseRouterData<KlarnaPaymentsResponse>> | |||||||
|                 incremental_authorization_allowed: None, |                 incremental_authorization_allowed: None, | ||||||
|                 charge_id: None, |                 charge_id: None, | ||||||
|             }), |             }), | ||||||
|             status: item.response.fraud_status.into(), |             status: enums::AttemptStatus::foreign_from(( | ||||||
|  |                 item.response.fraud_status, | ||||||
|  |                 item.data.request.is_auto_capture()?, | ||||||
|  |             )), | ||||||
|             ..item.data |             ..item.data | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Serialize)] | #[derive(Debug, Serialize)] | ||||||
| pub struct OrderLines { | pub struct OrderLines { | ||||||
|     name: String, |     name: String, | ||||||
| @ -186,15 +231,17 @@ pub enum KlarnaSessionIntent { | |||||||
| } | } | ||||||
|  |  | ||||||
| pub struct KlarnaAuthType { | pub struct KlarnaAuthType { | ||||||
|     pub basic_token: Secret<String>, |     pub username: Secret<String>, | ||||||
|  |     pub password: Secret<String>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl TryFrom<&types::ConnectorAuthType> for KlarnaAuthType { | impl TryFrom<&types::ConnectorAuthType> for KlarnaAuthType { | ||||||
|     type Error = error_stack::Report<errors::ConnectorError>; |     type Error = error_stack::Report<errors::ConnectorError>; | ||||||
|     fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> { |     fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> { | ||||||
|         if let types::ConnectorAuthType::HeaderKey { api_key } = auth_type { |         if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type { | ||||||
|             Ok(Self { |             Ok(Self { | ||||||
|                 basic_token: api_key.to_owned(), |                 username: key1.to_owned(), | ||||||
|  |                 password: api_key.to_owned(), | ||||||
|             }) |             }) | ||||||
|         } else { |         } else { | ||||||
|             Err(errors::ConnectorError::FailedToObtainAuthType.into()) |             Err(errors::ConnectorError::FailedToObtainAuthType.into()) | ||||||
| @ -202,19 +249,26 @@ impl TryFrom<&types::ConnectorAuthType> for KlarnaAuthType { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Clone, Default, Serialize, Deserialize)] | #[derive(Debug, Clone, Serialize, Deserialize)] | ||||||
| #[serde(rename_all = "UPPERCASE")] | #[serde(rename_all = "UPPERCASE")] | ||||||
| pub enum KlarnaFraudStatus { | pub enum KlarnaFraudStatus { | ||||||
|     Accepted, |     Accepted, | ||||||
|     #[default] |  | ||||||
|     Pending, |     Pending, | ||||||
|  |     Rejected, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<KlarnaFraudStatus> for enums::AttemptStatus { | impl ForeignFrom<(KlarnaFraudStatus, bool)> for enums::AttemptStatus { | ||||||
|     fn from(item: KlarnaFraudStatus) -> Self { |     fn foreign_from((klarna_status, is_auto_capture): (KlarnaFraudStatus, bool)) -> Self { | ||||||
|         match item { |         match klarna_status { | ||||||
|             KlarnaFraudStatus::Accepted => Self::Charged, |             KlarnaFraudStatus::Accepted => { | ||||||
|  |                 if is_auto_capture { | ||||||
|  |                     Self::Charged | ||||||
|  |                 } else { | ||||||
|  |                     Self::Authorized | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             KlarnaFraudStatus::Pending => Self::Authorizing, |             KlarnaFraudStatus::Pending => Self::Authorizing, | ||||||
|  |             KlarnaFraudStatus::Rejected => Self::Failure, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1947,6 +1947,7 @@ pub(crate) fn validate_auth_and_metadata_type( | |||||||
|         } |         } | ||||||
|         api_enums::Connector::Klarna => { |         api_enums::Connector::Klarna => { | ||||||
|             klarna::transformers::KlarnaAuthType::try_from(val)?; |             klarna::transformers::KlarnaAuthType::try_from(val)?; | ||||||
|  |             klarna::transformers::KlarnaConnectorMetadataObject::try_from(connector_meta_data)?; | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         } |         } | ||||||
|         api_enums::Connector::Mollie => { |         api_enums::Connector::Mollie => { | ||||||
|  | |||||||
| @ -100,7 +100,7 @@ gocardless.base_url = "https://api-sandbox.gocardless.com" | |||||||
| gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | gpayments.base_url = "https://{{merchant_endpoint_prefix}}-test.api.as1.gpayments.net" | ||||||
| helcim.base_url = "https://api.helcim.com/" | helcim.base_url = "https://api.helcim.com/" | ||||||
| iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | iatapay.base_url = "https://sandbox.iata-pay.iata.org/api/v1" | ||||||
| klarna.base_url = "https://api-na.playground.klarna.com/" | klarna.base_url = "https://api{{region_based_endpoint}}.playground.klarna.com/" | ||||||
| mifinity.base_url = "https://demo.mifinity.com/" | mifinity.base_url = "https://demo.mifinity.com/" | ||||||
| mollie.base_url = "https://api.mollie.com/v2/" | mollie.base_url = "https://api.mollie.com/v2/" | ||||||
| mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | mollie.secondary_base_url = "https://api.cc.mollie.com/v1/" | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Swangi Kumari
					Swangi Kumari