From 5a10f504ed489a74d69f81de3b8f39f750eba354 Mon Sep 17 00:00:00 2001 From: swangi-kumari Date: Wed, 4 Oct 2023 16:29:33 +0530 Subject: [PATCH 01/14] feat: add support for both auth_type bodykey and signaturekey --- crates/router/src/connector/paypal.rs | 112 +++++++++++++----- .../src/connector/paypal/transformers.rs | 57 +++++++-- 2 files changed, 132 insertions(+), 37 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 4aa50bb2d676..d1691ed6b496 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -5,10 +5,10 @@ use base64::Engine; use common_utils::ext_traits::ByteSliceExt; use diesel_models::enums; use error_stack::{IntoReport, ResultExt}; -use masking::PeekInterface; +use masking::{ExposeInterface, PeekInterface}; use transformers as paypal; -use self::transformers::PaypalMeta; +use self::transformers::{auth_headers, PaypalMeta}; use crate::{ configs::settings, connector::{ @@ -29,7 +29,7 @@ use crate::{ types::{ self, api::{self, CompleteAuthorize, ConnectorCommon, ConnectorCommonExt, VerifyWebhookSource}, - ErrorResponse, Response, + ConnectorAuthType, ErrorResponse, Response, }, utils::{self, BytesExt}, }; @@ -107,25 +107,77 @@ where .clone() .ok_or(errors::ConnectorError::FailedToObtainAuthType)?; let key = &req.attempt_id; - - Ok(vec![ - ( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - ), - ( - headers::AUTHORIZATION.to_string(), - format!("Bearer {}", access_token.token.peek()).into_masked(), - ), - ( - "Prefer".to_string(), - "return=representation".to_string().into(), - ), - ( - "PayPal-Request-Id".to_string(), - key.to_string().into_masked(), - ), - ]) + let auth: paypal::PaypalAuthType = match req.connector_auth_type { + ConnectorAuthType::BodyKey { .. } => (&req.connector_auth_type) + .try_into() + .change_context(errors::ConnectorError::FailedToObtainAuthType)?, + ConnectorAuthType::SignatureKey { .. } => (&req.connector_auth_type) + .try_into() + .change_context(errors::ConnectorError::FailedToObtainAuthType)?, + _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, + }; + let headers = if auth.payer_id.is_none() { + let result = vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", access_token.token.peek()).into_masked(), + ), + ( + auth_headers::PREFER.to_string(), + "return=representation".to_string().into(), + ), + ( + auth_headers::PAYPAL_REQUEST_ID.to_string(), + key.to_string().into_masked(), + ), + ]; + result + } else { + let auth_header1 = consts::BASE64_ENGINE + .encode("{\"alg\":\"none\"}") + .to_string(); + let keys = format!( + "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}", + auth.client_id.clone().expose(), + auth.payer_id + .clone() + .ok_or(errors::ConnectorError::FailedToObtainAuthType)? + .expose() + ); + let encode = consts::BASE64_ENGINE.encode(keys).to_string(); + let auth_headers = format!("{}.{}.", auth_header1, encode); + vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", access_token.token.peek()).into_masked(), + ), + ( + auth_headers::PREFER.to_string(), + "return=representation".to_string().into(), + ), + ( + auth_headers::PAYPAL_REQUEST_ID.to_string(), + key.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), + auth_headers.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchlegacy_Ecom".to_string().into(), + ), + ] + }; + Ok(headers) } } @@ -148,14 +200,14 @@ impl ConnectorCommon for Paypal { fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, + auth_type: &ConnectorAuthType, ) -> CustomResult)>, errors::ConnectorError> { let auth: paypal::PaypalAuthType = auth_type .try_into() .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( headers::AUTHORIZATION.to_string(), - auth.api_key.into_masked(), + auth.client_secret.into_masked(), )]) } @@ -235,9 +287,9 @@ impl ConnectorIntegration, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct Payee { + merchant_id: Secret, } #[derive(Debug, Serialize)] @@ -226,11 +239,27 @@ fn get_payment_source( } } +fn get_payee(auth_type: &PaypalAuthType) -> Option { + match auth_type { + PaypalAuthType { + payer_id: Some(merchant_id), + .. + } => Some(Payee { + merchant_id: merchant_id.clone(), + }), + + PaypalAuthType { payer_id: None, .. } => None, + } +} + impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalPaymentsRequest { type Error = error_stack::Report; fn try_from( item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { + let paypal_auth: PaypalAuthType = + PaypalAuthType::try_from(&item.router_data.connector_auth_type)?; // Assuming you have implemented TryInto for ConnectorAuthType to PaypalAuthType + let payee = get_payee(&paypal_auth); match item.router_data.request.payment_method_data { api_models::payments::PaymentMethodData::Card(ref ccard) => { let intent = if item.router_data.request.is_auto_capture()? { @@ -247,6 +276,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let purchase_units = vec![PurchaseUnitRequest { reference_id, amount, + payee, }]; let card = item.router_data.request.get_card()?; let expiry = Some(card.get_expiry_date_as_yyyymm("-")); @@ -280,6 +310,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let purchase_units = vec![PurchaseUnitRequest { reference_id, amount, + payee, }]; let payment_source = Some(PaymentSourceItem::Paypal(PaypalRedirectionRequest { @@ -343,6 +374,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let purchase_units = vec![PurchaseUnitRequest { reference_id, amount, + payee, }]; let payment_source = Some(get_payment_source(item.router_data, bank_redirection_data)?); @@ -561,17 +593,28 @@ impl TryFrom, - pub(super) key1: Secret, + pub(super) client_id: Secret, + pub(super) client_secret: Secret, + pub(super) payer_id: Option>, } -impl TryFrom<&types::ConnectorAuthType> for PaypalAuthType { +impl TryFrom<&ConnectorAuthType> for PaypalAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { - api_key: api_key.to_owned(), - key1: key1.to_owned(), + client_id: key1.to_owned(), + client_secret: api_key.to_owned(), + payer_id: None, + }), + types::ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } => Ok(Self { + client_id: key1.to_owned(), + client_secret: api_key.to_owned(), + payer_id: Some(api_secret.to_owned()), }), _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, } From b224f21882512fded69707f3552b39c13959eed0 Mon Sep 17 00:00:00 2001 From: swangi-kumari Date: Wed, 18 Oct 2023 19:40:41 +0530 Subject: [PATCH 02/14] fix: resolve conflicts --- crates/router/src/connector/paypal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index b716fb03a9bd..be5c028ea916 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -8,7 +8,7 @@ use error_stack::{IntoReport, ResultExt}; use masking::{ExposeInterface, PeekInterface}; use transformers as paypal; -use self::transformers::{PaypalAuthResponse, auth_headers, PaypalMeta, PaypalWebhookEventType}; +use self::transformers::{auth_headers, PaypalAuthResponse, PaypalMeta, PaypalWebhookEventType}; use super::utils::PaymentsCompleteAuthorizeRequestData; use crate::{ configs::settings, From 1ef5961c011969d18be387a6807c779cb4b0558f Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Thu, 2 Nov 2023 12:00:16 +0530 Subject: [PATCH 03/14] refactor: add more fields in orders request --- crates/router/src/connector/paypal.rs | 6 +- .../src/connector/paypal/transformers.rs | 198 ++++++++++++++++-- 2 files changed, 181 insertions(+), 23 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 6623b57dc755..6ae42123f04b 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -136,6 +136,10 @@ where auth_headers::PAYPAL_REQUEST_ID.to_string(), key.to_string().into_masked(), ), + ( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchlegacy_Ecom".to_string().into(), + ), ]; result } else { @@ -175,7 +179,7 @@ where ), ( auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), - "HyperSwitchlegacy_Ecom".to_string().into(), + "HyperSwitchPPCP_SP".to_string().into(), ), ] }; diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 040a8647f1b2..f66770381638 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -26,12 +26,12 @@ pub struct PaypalRouterData { } impl - TryFrom<( - &types::api::CurrencyUnit, - types::storage::enums::Currency, - i64, - T, - )> for PaypalRouterData +TryFrom<( + &types::api::CurrencyUnit, + types::storage::enums::Currency, + i64, + T, +)> for PaypalRouterData { type Error = error_stack::Report; fn try_from( @@ -73,9 +73,21 @@ pub enum PaypalPaymentIntent { } #[derive(Default, Debug, Clone, Serialize, Eq, PartialEq, Deserialize)] +pub struct Amount { + currency_code: storage_enums::Currency, + value: String, +} + +#[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct OrderAmount { pub currency_code: storage_enums::Currency, pub value: String, + pub breakdown: AmountBreakdown, +} + +#[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub struct AmountBreakdown { + item_total: Amount, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -86,6 +98,8 @@ pub struct PurchaseUnitRequest { amount: OrderAmount, #[serde(skip_serializing_if = "Option::is_none")] payee: Option, + shipping: Option, + items: Vec, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -93,11 +107,30 @@ pub struct Payee { merchant_id: Secret, } -#[derive(Debug, Serialize)] +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ItemDetails { + name: String, + quantity: u16, + unit_amount: Amount, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct Address { address_line_1: Option>, postal_code: Option>, country_code: api_models::enums::CountryAlpha2, + admin_area_2: Option, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ShippingAddress { + address: Option
, + name: Option, +} + +#[derive(Default, Debug, Serialize, Eq, PartialEq)] +pub struct ShippingName { + full_name: Option>, } #[derive(Debug, Serialize)] @@ -137,6 +170,16 @@ pub struct RedirectRequest { pub struct ContextStruct { return_url: Option, cancel_url: Option, + user_action: Option, + shipping_preference: ShippingPreference, +} + +#[derive(Debug, Serialize)] +pub enum ShippingPreference { + #[serde(rename = "SET_PROVIDED_ADDRESS")] + SetProvidedAddress, + #[serde(rename = "GET_FROM_FILE")] + GetFromFile, } #[derive(Debug, Serialize)] @@ -171,6 +214,7 @@ fn get_address_info( country_code: address.get_country()?.to_owned(), address_line_1: address.line1.clone(), postal_code: address.zip.clone(), + admin_area_2: address.city.clone(), }), None => None, }; @@ -193,6 +237,12 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), + shipping_preference: if item.address.shipping.is_some() { + ShippingPreference::SetProvidedAddress + } else { + ShippingPreference::GetFromFile + }, + user_action: Some("PAY_NOW".to_string()), }, })), BankRedirectData::Giropay { @@ -207,6 +257,12 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), + shipping_preference: if item.address.shipping.is_some() { + ShippingPreference::SetProvidedAddress + } else { + ShippingPreference::GetFromFile + }, + user_action: Some("PAY_NOW".to_string()), }, })), BankRedirectData::Ideal { @@ -221,6 +277,12 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), + shipping_preference: if item.address.shipping.is_some() { + ShippingPreference::SetProvidedAddress + } else { + ShippingPreference::GetFromFile + }, + user_action: Some("PAY_NOW".to_string()), }, })), BankRedirectData::Sofort { @@ -233,6 +295,12 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), + shipping_preference: if item.address.shipping.is_some() { + ShippingPreference::SetProvidedAddress + } else { + ShippingPreference::GetFromFile + }, + user_action: Some("PAY_NOW".to_string()), }, })), BankRedirectData::BancontactCard { .. } @@ -240,7 +308,7 @@ fn get_payment_source( | BankRedirectData::Przelewy24 { .. } => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Paypal"), ) - .into()), + .into()), BankRedirectData::Bizum {} | BankRedirectData::Interac { .. } | BankRedirectData::OnlineBankingCzechRepublic { .. } @@ -255,7 +323,7 @@ fn get_payment_source( message: utils::SELECTED_PAYMENT_METHOD.to_string(), connector: "Paypal", } - .into()) + .into()) } } } @@ -291,9 +359,35 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let amount = OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), + breakdown: AmountBreakdown { + item_total: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_owned(), + }, + }, }; let connector_request_reference_id = item.router_data.connector_request_reference_id.clone(); + let shipping_address = ShippingAddress { + address: get_address_info(item.router_data.address.shipping.as_ref())?, + name: Some(ShippingName { + full_name: item + .router_data + .address + .shipping + .as_ref() + .and_then(|inner_data| inner_data.address.as_ref()) + .and_then(|inner_data| inner_data.first_name.clone()), + }), + }; + let item_details = vec![ItemDetails { + name: format!("Payment for invoice {}", connector_request_reference_id), + quantity: 1, + unit_amount: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_string(), + }, + }]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_request_reference_id.clone()), @@ -301,6 +395,8 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP invoice_id: Some(connector_request_reference_id), amount, payee, + shipping: Some(shipping_address), + items: item_details, }]; let card = item.router_data.request.get_card()?; let expiry = Some(card.get_expiry_date_as_yyyymm("-")); @@ -339,10 +435,36 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let amount = OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), + breakdown: AmountBreakdown { + item_total: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_owned(), + }, + }, }; let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); + let shipping_address = ShippingAddress { + address: get_address_info(item.router_data.address.shipping.as_ref())?, + name: Some(ShippingName { + full_name: item + .router_data + .address + .shipping + .as_ref() + .and_then(|inner_data| inner_data.address.as_ref()) + .and_then(|inner_data| inner_data.first_name.clone()), + }), + }; + let item_details = vec![ItemDetails { + name: format!("Payment for invoice {}", connector_req_reference_id), + quantity: 1, + unit_amount: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_string(), + }, + }]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_req_reference_id.clone()), @@ -350,12 +472,16 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP invoice_id: Some(connector_req_reference_id), amount, payee, + shipping: Some(shipping_address), + items: item_details, }]; let payment_source = Some(PaymentSourceItem::Paypal(PaypalRedirectionRequest { experience_context: ContextStruct { return_url: item.router_data.request.complete_authorize_url.clone(), cancel_url: item.router_data.request.complete_authorize_url.clone(), + shipping_preference: ShippingPreference::SetProvidedAddress, + user_action: Some("PAY_NOW".to_string()), }, })); @@ -408,9 +534,35 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let amount = OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), + breakdown: AmountBreakdown { + item_total: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_owned(), + }, + }, }; let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); + let shipping_address = ShippingAddress { + address: get_address_info(item.router_data.address.shipping.as_ref())?, + name: Some(ShippingName { + full_name: item + .router_data + .address + .shipping + .as_ref() + .and_then(|inner_data| inner_data.address.as_ref()) + .and_then(|inner_data| inner_data.first_name.clone()), + }), + }; + let item_details = vec![ItemDetails { + name: format!("Payment for invoice {}", connector_req_reference_id), + quantity: 1, + unit_amount: Amount { + currency_code: item.router_data.request.currency, + value: item.amount.to_string(), + }, + }]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_req_reference_id.clone()), @@ -418,6 +570,8 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP invoice_id: Some(connector_req_reference_id), amount, payee, + shipping: Some(shipping_address), + items: item_details, }]; let payment_source = Some(get_payment_source(item.router_data, bank_redirection_data)?); @@ -698,7 +852,7 @@ impl ForeignFrom<(PaypalOrderStatus, PaypalPaymentIntent)> for storage_enums::At #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PaymentsCollectionItem { - amount: OrderAmount, + amount: Amount, expiration_time: Option, id: String, final_capture: Option, @@ -776,7 +930,7 @@ pub enum PaypalSyncResponse { pub struct PaypalPaymentsSyncResponse { id: String, status: PaypalPaymentStatus, - amount: OrderAmount, + amount: Amount, invoice_id: Option, supplementary_data: PaypalSupplementaryData, } @@ -1170,7 +1324,7 @@ impl #[derive(Debug, Serialize)] pub struct PaypalPaymentsCaptureRequest { - amount: OrderAmount, + amount: Amount, final_capture: bool, } @@ -1181,7 +1335,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsCaptureRouterData>> fn try_from( item: &PaypalRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - let amount = OrderAmount { + let amount = Amount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), }; @@ -1212,7 +1366,7 @@ pub enum PaypalPaymentStatus { pub struct PaypalCaptureResponse { id: String, status: PaypalPaymentStatus, - amount: Option, + amount: Option, invoice_id: Option, final_capture: bool, } @@ -1280,7 +1434,7 @@ pub enum PaypalCancelStatus { pub struct PaypalPaymentsCancelResponse { id: String, status: PaypalCancelStatus, - amount: Option, + amount: Option, invoice_id: Option, } @@ -1321,7 +1475,7 @@ impl #[derive(Default, Debug, Serialize)] pub struct PaypalRefundRequest { - pub amount: OrderAmount, + pub amount: Amount, } impl TryFrom<&PaypalRouterData<&types::RefundsRouterData>> for PaypalRefundRequest { @@ -1330,7 +1484,7 @@ impl TryFrom<&PaypalRouterData<&types::RefundsRouterData>> for PaypalRefun item: &PaypalRouterData<&types::RefundsRouterData>, ) -> Result { Ok(Self { - amount: OrderAmount { + amount: Amount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), }, @@ -1362,7 +1516,7 @@ impl From for storage_enums::RefundStatus { pub struct RefundResponse { id: String, status: RefundStatus, - amount: Option, + amount: Option, } impl TryFrom> @@ -1548,19 +1702,19 @@ pub enum OutcomeCode { #[derive(Deserialize, Debug, Serialize)] pub struct PaypalRefundWebhooks { pub id: String, - pub amount: OrderAmount, + pub amount: Amount, pub seller_payable_breakdown: PaypalSellerPayableBreakdown, } #[derive(Deserialize, Debug, Serialize)] pub struct PaypalSellerPayableBreakdown { - pub total_refunded_amount: OrderAmount, + pub total_refunded_amount: Amount, } #[derive(Deserialize, Debug, Serialize)] pub struct PaypalCardWebhooks { pub supplementary_data: PaypalSupplementaryData, - pub amount: OrderAmount, + pub amount: Amount, pub invoice_id: Option, } @@ -1575,7 +1729,7 @@ pub struct PaypalRedirectsWebhooks { #[derive(Deserialize, Debug, Serialize)] pub struct PaypalWebhooksPurchaseUnits { pub reference_id: String, - pub amount: OrderAmount, + pub amount: Amount, } #[derive(Deserialize, Debug, Serialize)] From 578c81d1c1f1a74953b5307722da5d6d626c2458 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 08:37:10 +0000 Subject: [PATCH 04/14] chore: run formatter --- .../router/src/connector/paypal/transformers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index f66770381638..9052bdadb479 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -26,12 +26,12 @@ pub struct PaypalRouterData { } impl -TryFrom<( - &types::api::CurrencyUnit, - types::storage::enums::Currency, - i64, - T, -)> for PaypalRouterData + TryFrom<( + &types::api::CurrencyUnit, + types::storage::enums::Currency, + i64, + T, + )> for PaypalRouterData { type Error = error_stack::Report; fn try_from( @@ -308,7 +308,7 @@ fn get_payment_source( | BankRedirectData::Przelewy24 { .. } => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Paypal"), ) - .into()), + .into()), BankRedirectData::Bizum {} | BankRedirectData::Interac { .. } | BankRedirectData::OnlineBankingCzechRepublic { .. } @@ -323,7 +323,7 @@ fn get_payment_source( message: utils::SELECTED_PAYMENT_METHOD.to_string(), connector: "Paypal", } - .into()) + .into()) } } } From 87c802ffa3930e79b40cc73cffc01202b544a3c0 Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 14 Nov 2023 08:47:29 +0530 Subject: [PATCH 05/14] feat: Add support for temporary auth --- crates/router/src/connector/paypal.rs | 169 +++++++++--------- .../src/connector/paypal/transformers.rs | 57 ++++-- crates/router/src/core/errors.rs | 2 + crates/router/src/core/errors/utils.rs | 5 +- crates/router/src/types.rs | 8 + crates/router/src/types/api.rs | 2 +- 6 files changed, 135 insertions(+), 108 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index d398fc5be137..ac0730c14259 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -110,79 +110,74 @@ where .clone() .ok_or(errors::ConnectorError::FailedToObtainAuthType)?; let key = &req.attempt_id; - let auth: paypal::PaypalAuthType = match req.connector_auth_type { - ConnectorAuthType::BodyKey { .. } => (&req.connector_auth_type) - .try_into() - .change_context(errors::ConnectorError::FailedToObtainAuthType)?, - ConnectorAuthType::SignatureKey { .. } => (&req.connector_auth_type) - .try_into() - .change_context(errors::ConnectorError::FailedToObtainAuthType)?, - _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, - }; - let headers = if auth.payer_id.is_none() { - let result = vec![ - ( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - ), - ( - headers::AUTHORIZATION.to_string(), - format!("Bearer {}", access_token.token.peek()).into_masked(), - ), - ( - auth_headers::PREFER.to_string(), - "return=representation".to_string().into(), - ), - ( - auth_headers::PAYPAL_REQUEST_ID.to_string(), - key.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), - "HyperSwitchlegacy_Ecom".to_string().into(), - ), - ]; - result - } else { - let auth_header1 = consts::BASE64_ENGINE - .encode("{\"alg\":\"none\"}") - .to_string(); - let keys = format!( - "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}", - auth.client_id.clone().expose(), - auth.payer_id - .clone() - .ok_or(errors::ConnectorError::FailedToObtainAuthType)? - .expose() - ); - let encode = consts::BASE64_ENGINE.encode(keys).to_string(); - let auth_headers = format!("{}.{}.", auth_header1, encode); - vec![ - ( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - ), - ( - headers::AUTHORIZATION.to_string(), - format!("Bearer {}", access_token.token.peek()).into_masked(), - ), - ( - auth_headers::PREFER.to_string(), - "return=representation".to_string().into(), - ), - ( - auth_headers::PAYPAL_REQUEST_ID.to_string(), - key.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), - auth_headers.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), - "HyperSwitchPPCP_SP".to_string().into(), - ), - ] + let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; + let headers = match auth { + paypal::PaypalAuthType::AuthWithDetails(paypal::PaypalConnectorCredentials { + payer_id: Some(payer_id), + client_id, + .. + }) => { + let auth_header1 = consts::BASE64_ENGINE + .encode("{\"alg\":\"none\"}") + .to_string(); + let keys = format!( + "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}", + client_id.clone().expose(), + payer_id.expose() + ); + let encode = consts::BASE64_ENGINE.encode(keys).to_string(); + let auth_headers = format!("{}.{}.", auth_header1, encode); + vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", access_token.token.peek()).into_masked(), + ), + ( + auth_headers::PREFER.to_string(), + "return=representation".to_string().into(), + ), + ( + auth_headers::PAYPAL_REQUEST_ID.to_string(), + key.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), + auth_headers.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchPPCP_SP".to_string().into(), + ), + ] + } + _ => { + vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", access_token.token.peek()).into_masked(), + ), + ( + auth_headers::PREFER.to_string(), + "return=representation".to_string().into(), + ), + ( + auth_headers::PAYPAL_REQUEST_ID.to_string(), + key.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchlegacy_Ecom".to_string().into(), + ), + ] + } }; Ok(headers) } @@ -209,12 +204,12 @@ impl ConnectorCommon for Paypal { &self, auth_type: &ConnectorAuthType, ) -> CustomResult)>, errors::ConnectorError> { - let auth: paypal::PaypalAuthType = auth_type - .try_into() - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let auth = paypal::PaypalAuthType::try_from(auth_type)?; + let credentials = auth.get_credentails()?; + Ok(vec![( headers::AUTHORIZATION.to_string(), - auth.client_secret.into_masked(), + credentials.client_secret.clone().into_masked(), )]) } @@ -316,13 +311,13 @@ impl ConnectorIntegration CustomResult)>, errors::ConnectorError> { - let auth: paypal::PaypalAuthType = (&req.connector_auth_type) - .try_into() - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; + let credentails = auth.get_credentails()?; - let auth_id = auth + let auth_id = credentails .client_id - .zip(auth.client_secret) + .clone() + .zip(credentails.client_secret.clone()) .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); @@ -1054,13 +1049,13 @@ impl >, _connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { - let auth: paypal::PaypalAuthType = (&req.connector_auth_type) - .try_into() - .change_context(errors::ConnectorError::FailedToObtainAuthType)?; + let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; + let credentails = auth.get_credentails()?; - let auth_id = auth + let auth_id = credentails .client_id - .zip(auth.client_secret) + .clone() + .zip(credentails.client_secret.clone()) .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 5fbaa597512e..9714b54a2ce9 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -329,16 +329,15 @@ fn get_payment_source( } fn get_payee(auth_type: &PaypalAuthType) -> Option { - match auth_type { - PaypalAuthType { - payer_id: Some(merchant_id), - .. - } => Some(Payee { - merchant_id: merchant_id.clone(), - }), - - PaypalAuthType { payer_id: None, .. } => None, - } + auth_type + .get_credentails() + .ok() + .and_then(|credentials| credentials.payer_id.to_owned()) + .and_then(|payer_id| { + Some(Payee { + merchant_id: payer_id, + }) + }) } impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalPaymentsRequest { @@ -790,30 +789,52 @@ impl TryFrom, pub(super) client_secret: Secret, pub(super) payer_id: Option>, } +impl PaypalAuthType { + pub fn get_credentails( + &self, + ) -> CustomResult<&PaypalConnectorCredentials, errors::ConnectorError> { + match self { + Self::TemporaryAuth => { + Err(errors::ConnectorError::TemporaryConnectorCredentails.into()) + } + Self::AuthWithDetails(credentials) => Ok(credentials), + } + } +} + impl TryFrom<&ConnectorAuthType> for PaypalAuthType { type Error = error_stack::Report; fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { - client_id: key1.to_owned(), - client_secret: api_key.to_owned(), - payer_id: None, - }), + types::ConnectorAuthType::BodyKey { api_key, key1 } => { + Ok(Self::AuthWithDetails(PaypalConnectorCredentials { + client_id: key1.to_owned(), + client_secret: api_key.to_owned(), + payer_id: None, + })) + } types::ConnectorAuthType::SignatureKey { api_key, key1, api_secret, - } => Ok(Self { + } => Ok(Self::AuthWithDetails(PaypalConnectorCredentials { client_id: key1.to_owned(), client_secret: api_key.to_owned(), payer_id: Some(api_secret.to_owned()), - }), + })), + types::ConnectorAuthType::TemporaryAuth => Ok(Self::TemporaryAuth), _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, } } diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 810c079987eb..09967a481b2c 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -184,6 +184,8 @@ pub enum ConnectorError { }, #[error("Invalid Configuration")] InvalidConnectorConfig { config: &'static str }, + #[error("Temporary Credentails")] + TemporaryConnectorCredentails, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index c3cdf95b87bd..b6e9905f8cc2 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -205,7 +205,7 @@ impl ConnectorErrorExt for error_stack::Result 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::ConnectorError::FailedToObtainAuthType => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, + errors::ConnectorError::FailedToObtainAuthType | errors::ConnectorError::TemporaryConnectorCredentails => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, errors::ConnectorError::InvalidConnectorConfig { config } => errors::ApiErrorResponse::InvalidConnectorConfiguration { config: config.to_string() }, errors::ConnectorError::FailedToObtainIntegrationUrl | errors::ConnectorError::RequestEncodingFailed | @@ -276,7 +276,8 @@ impl ConnectorErrorExt for error_stack::Result errors::ConnectorError::MissingRequiredField { field_name } => { errors::ApiErrorResponse::MissingRequiredField { field_name } } - errors::ConnectorError::FailedToObtainIntegrationUrl => { + errors::ConnectorError::FailedToObtainIntegrationUrl + | errors::ConnectorError::TemporaryConnectorCredentails => { errors::ApiErrorResponse::InvalidConnectorConfiguration { config: "connector_account_details".to_string(), } diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index ceeb93f69763..bd3a35229bea 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -782,6 +782,14 @@ pub enum VerifyWebhookStatus { SourceNotVerified, } +#[derive(Debug, Clone)] +pub struct SyncConnectorRequestData; + +#[derive(Debug, Clone)] +pub struct SyncConnectorResponseData { + pub referral_url: String, +} + #[derive(Default, Debug, Clone)] pub struct AcceptDisputeRequestData { pub dispute_id: String, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index dc615c4e41fa..02ba1b2e6d2d 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -165,7 +165,7 @@ impl< + FileUpload + ConnectorTransactionId + Payouts - + ConnectorVerifyWebhookSource, + + ConnectorVerifyWebhookSource > Connector for T { } From dd6938f1b4f7ad7c4540caadfb871b43a1c9d857 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 10:09:44 +0000 Subject: [PATCH 06/14] chore: run formatter --- crates/router/src/types/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 02ba1b2e6d2d..dc615c4e41fa 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -165,7 +165,7 @@ impl< + FileUpload + ConnectorTransactionId + Payouts - + ConnectorVerifyWebhookSource + + ConnectorVerifyWebhookSource, > Connector for T { } From 781ddb03dab5a29e793564da59f6d5be4f8a8c38 Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Mon, 20 Nov 2023 16:25:07 +0530 Subject: [PATCH 07/14] refactor: remove unnecessary code and improve build_headers --- crates/router/src/connector/paypal.rs | 129 ++++++++---------- .../src/connector/paypal/transformers.rs | 2 +- crates/router/src/types.rs | 8 -- 3 files changed, 61 insertions(+), 78 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index ac0730c14259..9617a4045b73 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -5,7 +5,7 @@ use base64::Engine; use common_utils::ext_traits::ByteSliceExt; use diesel_models::enums; use error_stack::{IntoReport, ResultExt}; -use masking::{ExposeInterface, PeekInterface}; +use masking::{ExposeInterface, PeekInterface, Secret}; use transformers as paypal; use self::transformers::{auth_headers, PaypalAuthResponse, PaypalMeta, PaypalWebhookEventType}; @@ -111,78 +111,69 @@ where .ok_or(errors::ConnectorError::FailedToObtainAuthType)?; let key = &req.attempt_id; let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; - let headers = match auth { - paypal::PaypalAuthType::AuthWithDetails(paypal::PaypalConnectorCredentials { - payer_id: Some(payer_id), - client_id, - .. - }) => { - let auth_header1 = consts::BASE64_ENGINE - .encode("{\"alg\":\"none\"}") - .to_string(); - let keys = format!( - "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}", - client_id.clone().expose(), - payer_id.expose() - ); - let encode = consts::BASE64_ENGINE.encode(keys).to_string(); - let auth_headers = format!("{}.{}.", auth_header1, encode); - vec![ - ( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - ), - ( - headers::AUTHORIZATION.to_string(), - format!("Bearer {}", access_token.token.peek()).into_masked(), - ), - ( - auth_headers::PREFER.to_string(), - "return=representation".to_string().into(), - ), - ( - auth_headers::PAYPAL_REQUEST_ID.to_string(), - key.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), - auth_headers.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), - "HyperSwitchPPCP_SP".to_string().into(), - ), - ] - } - _ => { - vec![ - ( - headers::CONTENT_TYPE.to_string(), - self.get_content_type().to_string().into(), - ), - ( - headers::AUTHORIZATION.to_string(), - format!("Bearer {}", access_token.token.peek()).into_masked(), - ), - ( - auth_headers::PREFER.to_string(), - "return=representation".to_string().into(), - ), - ( - auth_headers::PAYPAL_REQUEST_ID.to_string(), - key.to_string().into_masked(), - ), - ( - auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), - "HyperSwitchlegacy_Ecom".to_string().into(), - ), - ] - } - }; + let mut headers = vec![ + ( + headers::CONTENT_TYPE.to_string(), + self.get_content_type().to_string().into(), + ), + ( + headers::AUTHORIZATION.to_string(), + format!("Bearer {}", access_token.token.peek()).into_masked(), + ), + ( + auth_headers::PREFER.to_string(), + "return=representation".to_string().into(), + ), + ( + auth_headers::PAYPAL_REQUEST_ID.to_string(), + key.to_string().into_masked(), + ), + ]; + if let Ok(paypal::PaypalConnectorCredentials { + payer_id: Some(payer_id), + client_id, + .. + }) = auth.get_credentails() + { + let auth_assertion_header = construct_auth_assertion_header(payer_id, client_id); + headers.extend(vec![ + ( + auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), + auth_assertion_header.to_string().into_masked(), + ), + ( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchPPCP_SP".to_string().into(), + ), + ]) + } else { + headers.extend(vec![( + auth_headers::PAYPAL_PARTNER_ATTRIBUTION_ID.to_string(), + "HyperSwitchlegacy_Ecom".to_string().into(), + )]) + } Ok(headers) } } +fn construct_auth_assertion_header( + payer_id: &Secret, + client_id: &Secret, +) -> String { + let algorithm = consts::BASE64_ENGINE + .encode("{\"alg\":\"none\"}") + .to_string(); + let merchant_credentials = format!( + "{{\"iss\":\"{}\",\"payer_id\":\"{}\"}}", + client_id.clone().expose(), + payer_id.clone().expose() + ); + let encoded_credentials = consts::BASE64_ENGINE + .encode(merchant_credentials) + .to_string(); + return format!("{}.{}.", algorithm, encoded_credentials); +} + impl ConnectorCommon for Paypal { fn id(&self) -> &'static str { "paypal" diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 9714b54a2ce9..dac287d45389 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -346,7 +346,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { let paypal_auth: PaypalAuthType = - PaypalAuthType::try_from(&item.router_data.connector_auth_type)?; // Assuming you have implemented TryInto for ConnectorAuthType to PaypalAuthType + PaypalAuthType::try_from(&item.router_data.connector_auth_type)?; let payee = get_payee(&paypal_auth); match item.router_data.request.payment_method_data { api_models::payments::PaymentMethodData::Card(ref ccard) => { diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index bd3a35229bea..ceeb93f69763 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -782,14 +782,6 @@ pub enum VerifyWebhookStatus { SourceNotVerified, } -#[derive(Debug, Clone)] -pub struct SyncConnectorRequestData; - -#[derive(Debug, Clone)] -pub struct SyncConnectorResponseData { - pub referral_url: String, -} - #[derive(Default, Debug, Clone)] pub struct AcceptDisputeRequestData { pub dispute_id: String, From 5621a088923ca2d223ecd552d067e96ce383f94f Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 11:31:56 +0530 Subject: [PATCH 08/14] fix: typos --- crates/router/src/connector/paypal.rs | 16 ++++++++-------- .../router/src/connector/paypal/transformers.rs | 6 +++--- crates/router/src/core/errors.rs | 4 ++-- crates/router/src/core/errors/utils.rs | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 9617a4045b73..55048385c2ac 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -133,7 +133,7 @@ where payer_id: Some(payer_id), client_id, .. - }) = auth.get_credentails() + }) = auth.get_credentials() { let auth_assertion_header = construct_auth_assertion_header(payer_id, client_id); headers.extend(vec![ @@ -196,7 +196,7 @@ impl ConnectorCommon for Paypal { auth_type: &ConnectorAuthType, ) -> CustomResult)>, errors::ConnectorError> { let auth = paypal::PaypalAuthType::try_from(auth_type)?; - let credentials = auth.get_credentails()?; + let credentials = auth.get_credentials()?; Ok(vec![( headers::AUTHORIZATION.to_string(), @@ -303,12 +303,12 @@ impl ConnectorIntegration CustomResult)>, errors::ConnectorError> { let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; - let credentails = auth.get_credentails()?; + let credentials = auth.get_credentials()?; - let auth_id = credentails + let auth_id = credentials .client_id .clone() - .zip(credentails.client_secret.clone()) + .zip(credentials.client_secret.clone()) .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); @@ -1041,12 +1041,12 @@ impl _connectors: &settings::Connectors, ) -> CustomResult)>, errors::ConnectorError> { let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; - let credentails = auth.get_credentails()?; + let credentials = auth.get_credentials()?; - let auth_id = credentails + let auth_id = credentials .client_id .clone() - .zip(credentails.client_secret.clone()) + .zip(credentials.client_secret.clone()) .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index dac287d45389..6cac0e82748b 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -330,7 +330,7 @@ fn get_payment_source( fn get_payee(auth_type: &PaypalAuthType) -> Option { auth_type - .get_credentails() + .get_credentials() .ok() .and_then(|credentials| credentials.payer_id.to_owned()) .and_then(|payer_id| { @@ -802,12 +802,12 @@ pub struct PaypalConnectorCredentials { } impl PaypalAuthType { - pub fn get_credentails( + pub fn get_credentials( &self, ) -> CustomResult<&PaypalConnectorCredentials, errors::ConnectorError> { match self { Self::TemporaryAuth => { - Err(errors::ConnectorError::TemporaryConnectorCredentails.into()) + Err(errors::ConnectorError::TemporaryConnectorCredentials.into()) } Self::AuthWithDetails(credentials) => Ok(credentials), } diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 09967a481b2c..fbf6063fba3f 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -184,8 +184,8 @@ pub enum ConnectorError { }, #[error("Invalid Configuration")] InvalidConnectorConfig { config: &'static str }, - #[error("Temporary Credentails")] - TemporaryConnectorCredentails, + #[error("Temporary Credentials")] + TemporaryConnectorCredentials, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index b6e9905f8cc2..b741ec4a7a46 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -205,7 +205,7 @@ impl ConnectorErrorExt for error_stack::Result 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::ConnectorError::FailedToObtainAuthType | errors::ConnectorError::TemporaryConnectorCredentails => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, + errors::ConnectorError::FailedToObtainAuthType | errors::ConnectorError::TemporaryConnectorCredentials => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, errors::ConnectorError::InvalidConnectorConfig { config } => errors::ApiErrorResponse::InvalidConnectorConfiguration { config: config.to_string() }, errors::ConnectorError::FailedToObtainIntegrationUrl | errors::ConnectorError::RequestEncodingFailed | @@ -277,7 +277,7 @@ impl ConnectorErrorExt for error_stack::Result errors::ApiErrorResponse::MissingRequiredField { field_name } } errors::ConnectorError::FailedToObtainIntegrationUrl - | errors::ConnectorError::TemporaryConnectorCredentails => { + | errors::ConnectorError::TemporaryConnectorCredentials => { errors::ApiErrorResponse::InvalidConnectorConfiguration { config: "connector_account_details".to_string(), } From 8a757bcf289c480c08b0e3bd82a13afcb8b46920 Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 11:34:34 +0530 Subject: [PATCH 09/14] fix: clippy lints --- crates/router/src/connector/paypal.rs | 2 +- crates/router/src/connector/paypal/transformers.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 55048385c2ac..8be9d186b037 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -171,7 +171,7 @@ fn construct_auth_assertion_header( let encoded_credentials = consts::BASE64_ENGINE .encode(merchant_credentials) .to_string(); - return format!("{}.{}.", algorithm, encoded_credentials); + format!("{}.{}.", algorithm, encoded_credentials) } impl ConnectorCommon for Paypal { diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 6cac0e82748b..fc7b33b1a1cd 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -333,10 +333,8 @@ fn get_payee(auth_type: &PaypalAuthType) -> Option { .get_credentials() .ok() .and_then(|credentials| credentials.payer_id.to_owned()) - .and_then(|payer_id| { - Some(Payee { - merchant_id: payer_id, - }) + .map(|payer_id| Payee { + merchant_id: payer_id, }) } From 8475298a17a8d19c3446f05ca8b333f0cf80cf00 Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 14:23:25 +0530 Subject: [PATCH 10/14] refactor: resolve comments --- crates/router/src/connector/paypal.rs | 30 +-- .../src/connector/paypal/transformers.rs | 250 ++++++++++-------- crates/router/src/core/errors.rs | 2 - crates/router/src/core/errors/utils.rs | 5 +- 4 files changed, 150 insertions(+), 137 deletions(-) diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 8be9d186b037..0e8cff8c0569 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -129,13 +129,11 @@ where key.to_string().into_masked(), ), ]; - if let Ok(paypal::PaypalConnectorCredentials { - payer_id: Some(payer_id), - client_id, - .. - }) = auth.get_credentials() + if let Ok(paypal::PaypalConnectorCredentials::PartnerIntegration(credentials)) = + auth.get_credentials() { - let auth_assertion_header = construct_auth_assertion_header(payer_id, client_id); + let auth_assertion_header = + construct_auth_assertion_header(&credentials.payer_id, &credentials.client_id); headers.extend(vec![ ( auth_headers::PAYPAL_AUTH_ASSERTION.to_string(), @@ -171,7 +169,7 @@ fn construct_auth_assertion_header( let encoded_credentials = consts::BASE64_ENGINE .encode(merchant_credentials) .to_string(); - format!("{}.{}.", algorithm, encoded_credentials) + format!("{algorithm}.{encoded_credentials}.") } impl ConnectorCommon for Paypal { @@ -200,7 +198,7 @@ impl ConnectorCommon for Paypal { Ok(vec![( headers::AUTHORIZATION.to_string(), - credentials.client_secret.clone().into_masked(), + credentials.get_client_secret().into_masked(), )]) } @@ -304,13 +302,7 @@ impl ConnectorIntegration CustomResult)>, errors::ConnectorError> { let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; let credentials = auth.get_credentials()?; - - let auth_id = credentials - .client_id - .clone() - .zip(credentials.client_secret.clone()) - .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); - let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); + let auth_val = credentials.generate_authorization_value(); Ok(vec![ ( @@ -1042,13 +1034,7 @@ impl ) -> CustomResult)>, errors::ConnectorError> { let auth = paypal::PaypalAuthType::try_from(&req.connector_auth_type)?; let credentials = auth.get_credentials()?; - - let auth_id = credentials - .client_id - .clone() - .zip(credentials.client_secret.clone()) - .map(|(client_id, client_secret)| format!("{}:{}", client_id, client_secret)); - let auth_val = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id.peek())); + let auth_val = credentials.generate_authorization_value(); Ok(vec![ ( diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index fc7b33b1a1cd..49c2f1c208b6 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1,7 +1,8 @@ use api_models::{enums, payments::BankRedirectData}; +use base64::Engine; use common_utils::errors::CustomResult; use error_stack::{IntoReport, ResultExt}; -use masking::Secret; +use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use url::Url; @@ -11,6 +12,7 @@ use crate::{ self, to_connector_meta, AccessTokenRequestInfo, AddressDetailsData, BankRedirectBillingData, CardData, PaymentsAuthorizeRequestData, }, + consts, core::errors, services, types::{ @@ -73,21 +75,36 @@ pub enum PaypalPaymentIntent { } #[derive(Default, Debug, Clone, Serialize, Eq, PartialEq, Deserialize)] -pub struct Amount { +pub struct OrderAmount { currency_code: storage_enums::Currency, value: String, } #[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq)] -pub struct OrderAmount { +pub struct OrderRequestAmount { pub currency_code: storage_enums::Currency, pub value: String, pub breakdown: AmountBreakdown, } +impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for OrderRequestAmount { + fn from(item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>) -> Self { + Self { + currency_code: item.router_data.request.currency, + value: item.amount.to_owned(), + breakdown: AmountBreakdown { + item_total: OrderAmount { + currency_code: item.router_data.request.currency, + value: item.amount.to_owned(), + }, + }, + } + } +} + #[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq)] pub struct AmountBreakdown { - item_total: Amount, + item_total: OrderAmount, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -95,7 +112,7 @@ pub struct PurchaseUnitRequest { reference_id: Option, //reference for an item in purchase_units invoice_id: Option, //The API caller-provided external invoice number for this order. Appears in both the payer's transaction history and the emails that the payer receives. custom_id: Option, //Used to reconcile client transactions with PayPal transactions. - amount: OrderAmount, + amount: OrderRequestAmount, #[serde(skip_serializing_if = "Option::is_none")] payee: Option, shipping: Option, @@ -111,7 +128,7 @@ pub struct Payee { pub struct ItemDetails { name: String, quantity: u16, - unit_amount: Amount, + unit_amount: OrderAmount, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -128,6 +145,27 @@ pub struct ShippingAddress { name: Option, } +impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ShippingAddress { + type Error = error_stack::Report; + + fn try_from( + item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>, + ) -> Result { + Ok(Self { + address: get_address_info(item.router_data.address.shipping.as_ref())?, + name: Some(ShippingName { + full_name: item + .router_data + .address + .shipping + .as_ref() + .and_then(|inner_data| inner_data.address.as_ref()) + .and_then(|inner_data| inner_data.first_name.clone()), + }), + }) + } +} + #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct ShippingName { full_name: Option>, @@ -170,10 +208,16 @@ pub struct RedirectRequest { pub struct ContextStruct { return_url: Option, cancel_url: Option, - user_action: Option, + user_action: Option, shipping_preference: ShippingPreference, } +#[derive(Debug, Serialize)] +pub enum UserAction { + #[serde(rename = "PAY_NOW")] + PayNow, +} + #[derive(Debug, Serialize)] pub enum ShippingPreference { #[serde(rename = "SET_PROVIDED_ADDRESS")] @@ -242,7 +286,7 @@ fn get_payment_source( } else { ShippingPreference::GetFromFile }, - user_action: Some("PAY_NOW".to_string()), + user_action: Some(UserAction::PayNow), }, })), BankRedirectData::Giropay { @@ -262,7 +306,7 @@ fn get_payment_source( } else { ShippingPreference::GetFromFile }, - user_action: Some("PAY_NOW".to_string()), + user_action: Some(UserAction::PayNow), }, })), BankRedirectData::Ideal { @@ -282,7 +326,7 @@ fn get_payment_source( } else { ShippingPreference::GetFromFile }, - user_action: Some("PAY_NOW".to_string()), + user_action: Some(UserAction::PayNow), }, })), BankRedirectData::Sofort { @@ -300,7 +344,7 @@ fn get_payment_source( } else { ShippingPreference::GetFromFile }, - user_action: Some("PAY_NOW".to_string()), + user_action: Some(UserAction::PayNow), }, })), BankRedirectData::BancontactCard { .. } @@ -332,7 +376,7 @@ fn get_payee(auth_type: &PaypalAuthType) -> Option { auth_type .get_credentials() .ok() - .and_then(|credentials| credentials.payer_id.to_owned()) + .and_then(|credentials| credentials.get_payer_id()) .map(|payer_id| Payee { merchant_id: payer_id, }) @@ -353,34 +397,14 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP } else { PaypalPaymentIntent::Authorize }; - let amount = OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - breakdown: AmountBreakdown { - item_total: Amount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - }, - }, - }; + let amount = OrderRequestAmount::from(item); let connector_request_reference_id = item.router_data.connector_request_reference_id.clone(); - let shipping_address = ShippingAddress { - address: get_address_info(item.router_data.address.shipping.as_ref())?, - name: Some(ShippingName { - full_name: item - .router_data - .address - .shipping - .as_ref() - .and_then(|inner_data| inner_data.address.as_ref()) - .and_then(|inner_data| inner_data.first_name.clone()), - }), - }; + let shipping_address = ShippingAddress::try_from(item)?; let item_details = vec![ItemDetails { name: format!("Payment for invoice {}", connector_request_reference_id), quantity: 1, - unit_amount: Amount { + unit_amount: OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_string(), }, @@ -429,35 +453,15 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP } else { PaypalPaymentIntent::Authorize }; - let amount = OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - breakdown: AmountBreakdown { - item_total: Amount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - }, - }, - }; + let amount = OrderRequestAmount::from(item); let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); - let shipping_address = ShippingAddress { - address: get_address_info(item.router_data.address.shipping.as_ref())?, - name: Some(ShippingName { - full_name: item - .router_data - .address - .shipping - .as_ref() - .and_then(|inner_data| inner_data.address.as_ref()) - .and_then(|inner_data| inner_data.first_name.clone()), - }), - }; + let shipping_address = ShippingAddress::try_from(item)?; let item_details = vec![ItemDetails { name: format!("Payment for invoice {}", connector_req_reference_id), quantity: 1, - unit_amount: Amount { + unit_amount: OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_string(), }, @@ -478,7 +482,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP return_url: item.router_data.request.complete_authorize_url.clone(), cancel_url: item.router_data.request.complete_authorize_url.clone(), shipping_preference: ShippingPreference::SetProvidedAddress, - user_action: Some("PAY_NOW".to_string()), + user_action: Some(UserAction::PayNow), }, })); @@ -528,34 +532,14 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP connector: "Paypal".to_string(), })? }; - let amount = OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - breakdown: AmountBreakdown { - item_total: Amount { - currency_code: item.router_data.request.currency, - value: item.amount.to_owned(), - }, - }, - }; + let amount = OrderRequestAmount::from(item); let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); - let shipping_address = ShippingAddress { - address: get_address_info(item.router_data.address.shipping.as_ref())?, - name: Some(ShippingName { - full_name: item - .router_data - .address - .shipping - .as_ref() - .and_then(|inner_data| inner_data.address.as_ref()) - .and_then(|inner_data| inner_data.first_name.clone()), - }), - }; + let shipping_address = ShippingAddress::try_from(item)?; let item_details = vec![ItemDetails { name: format!("Payment for invoice {}", connector_req_reference_id), quantity: 1, - unit_amount: Amount { + unit_amount: OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_string(), }, @@ -793,10 +777,54 @@ pub enum PaypalAuthType { } #[derive(Debug)] -pub struct PaypalConnectorCredentials { +pub enum PaypalConnectorCredentials { + StandardIntegration(StandardFlowCredentials), + PartnerIntegration(PartnerFlowCredentails), +} + +impl PaypalConnectorCredentials { + pub fn get_client_id(&self) -> Secret { + match self { + PaypalConnectorCredentials::StandardIntegration(item) => item.client_id.clone(), + PaypalConnectorCredentials::PartnerIntegration(item) => item.client_id.clone(), + } + } + + pub fn get_client_secret(&self) -> Secret { + match self { + PaypalConnectorCredentials::StandardIntegration(item) => item.client_secret.clone(), + PaypalConnectorCredentials::PartnerIntegration(item) => item.client_secret.clone(), + } + } + + pub fn get_payer_id(&self) -> Option> { + match self { + PaypalConnectorCredentials::StandardIntegration(_) => None, + PaypalConnectorCredentials::PartnerIntegration(item) => Some(item.payer_id.clone()), + } + } + + pub fn generate_authorization_value(&self) -> String { + let auth_id = format!( + "{}:{}", + self.get_client_id().expose(), + self.get_client_secret().expose(), + ); + format!("Basic {}", consts::BASE64_ENGINE.encode(auth_id)) + } +} + +#[derive(Debug)] +pub struct StandardFlowCredentials { pub(super) client_id: Secret, pub(super) client_secret: Secret, - pub(super) payer_id: Option>, +} + +#[derive(Debug)] +pub struct PartnerFlowCredentails { + pub(super) client_id: Secret, + pub(super) client_secret: Secret, + pub(super) payer_id: Secret, } impl PaypalAuthType { @@ -804,9 +832,10 @@ impl PaypalAuthType { &self, ) -> CustomResult<&PaypalConnectorCredentials, errors::ConnectorError> { match self { - Self::TemporaryAuth => { - Err(errors::ConnectorError::TemporaryConnectorCredentials.into()) + Self::TemporaryAuth => Err(errors::ConnectorError::InvalidConnectorConfig { + config: "TemporaryAuth found in connector_account_details", } + .into()), Self::AuthWithDetails(credentials) => Ok(credentials), } } @@ -816,22 +845,23 @@ impl TryFrom<&ConnectorAuthType> for PaypalAuthType { type Error = error_stack::Report; fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::BodyKey { api_key, key1 } => { - Ok(Self::AuthWithDetails(PaypalConnectorCredentials { + types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self::AuthWithDetails( + PaypalConnectorCredentials::StandardIntegration(StandardFlowCredentials { client_id: key1.to_owned(), client_secret: api_key.to_owned(), - payer_id: None, - })) - } + }), + )), types::ConnectorAuthType::SignatureKey { api_key, key1, api_secret, - } => Ok(Self::AuthWithDetails(PaypalConnectorCredentials { - client_id: key1.to_owned(), - client_secret: api_key.to_owned(), - payer_id: Some(api_secret.to_owned()), - })), + } => Ok(Self::AuthWithDetails( + PaypalConnectorCredentials::PartnerIntegration(PartnerFlowCredentails { + client_id: key1.to_owned(), + client_secret: api_key.to_owned(), + payer_id: api_secret.to_owned(), + }), + )), types::ConnectorAuthType::TemporaryAuth => Ok(Self::TemporaryAuth), _ => Err(errors::ConnectorError::FailedToObtainAuthType)?, } @@ -872,7 +902,7 @@ impl ForeignFrom<(PaypalOrderStatus, PaypalPaymentIntent)> for storage_enums::At #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PaymentsCollectionItem { - amount: Amount, + amount: OrderAmount, expiration_time: Option, id: String, final_capture: Option, @@ -950,7 +980,7 @@ pub enum PaypalSyncResponse { pub struct PaypalPaymentsSyncResponse { id: String, status: PaypalPaymentStatus, - amount: Amount, + amount: OrderAmount, invoice_id: Option, supplementary_data: PaypalSupplementaryData, } @@ -1344,7 +1374,7 @@ impl #[derive(Debug, Serialize)] pub struct PaypalPaymentsCaptureRequest { - amount: Amount, + amount: OrderAmount, final_capture: bool, } @@ -1355,7 +1385,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsCaptureRouterData>> fn try_from( item: &PaypalRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - let amount = Amount { + let amount = OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), }; @@ -1386,7 +1416,7 @@ pub enum PaypalPaymentStatus { pub struct PaypalCaptureResponse { id: String, status: PaypalPaymentStatus, - amount: Option, + amount: Option, invoice_id: Option, final_capture: bool, } @@ -1454,7 +1484,7 @@ pub enum PaypalCancelStatus { pub struct PaypalPaymentsCancelResponse { id: String, status: PaypalCancelStatus, - amount: Option, + amount: Option, invoice_id: Option, } @@ -1495,7 +1525,7 @@ impl #[derive(Default, Debug, Serialize)] pub struct PaypalRefundRequest { - pub amount: Amount, + pub amount: OrderAmount, } impl TryFrom<&PaypalRouterData<&types::RefundsRouterData>> for PaypalRefundRequest { @@ -1504,7 +1534,7 @@ impl TryFrom<&PaypalRouterData<&types::RefundsRouterData>> for PaypalRefun item: &PaypalRouterData<&types::RefundsRouterData>, ) -> Result { Ok(Self { - amount: Amount { + amount: OrderAmount { currency_code: item.router_data.request.currency, value: item.amount.to_owned(), }, @@ -1536,7 +1566,7 @@ impl From for storage_enums::RefundStatus { pub struct RefundResponse { id: String, status: RefundStatus, - amount: Option, + amount: Option, } impl TryFrom> @@ -1666,7 +1696,7 @@ pub enum PaypalResource { pub struct PaypalDisputeWebhooks { pub dispute_id: String, pub dispute_transactions: Vec, - pub dispute_amount: OrderAmount, + pub dispute_amount: OrderRequestAmount, pub dispute_outcome: DisputeOutcome, pub dispute_life_cycle_stage: DisputeLifeCycleStage, pub status: DisputeStatus, @@ -1722,19 +1752,19 @@ pub enum OutcomeCode { #[derive(Deserialize, Debug, Serialize)] pub struct PaypalRefundWebhooks { pub id: String, - pub amount: Amount, + pub amount: OrderAmount, pub seller_payable_breakdown: PaypalSellerPayableBreakdown, } #[derive(Deserialize, Debug, Serialize)] pub struct PaypalSellerPayableBreakdown { - pub total_refunded_amount: Amount, + pub total_refunded_amount: OrderAmount, } #[derive(Deserialize, Debug, Serialize)] pub struct PaypalCardWebhooks { pub supplementary_data: PaypalSupplementaryData, - pub amount: Amount, + pub amount: OrderAmount, pub invoice_id: Option, } @@ -1749,7 +1779,7 @@ pub struct PaypalRedirectsWebhooks { #[derive(Deserialize, Debug, Serialize)] pub struct PaypalWebhooksPurchaseUnits { pub reference_id: String, - pub amount: Amount, + pub amount: OrderAmount, } #[derive(Deserialize, Debug, Serialize)] diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 2180b748f3d8..03bb9a41b5b5 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -184,8 +184,6 @@ pub enum ConnectorError { }, #[error("Invalid Configuration")] InvalidConnectorConfig { config: &'static str }, - #[error("Temporary Credentials")] - TemporaryConnectorCredentials, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index 7102a5b4b665..869a5b6bde95 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -205,7 +205,7 @@ impl ConnectorErrorExt for error_stack::Result 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::ConnectorError::FailedToObtainAuthType | errors::ConnectorError::TemporaryConnectorCredentials => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, + errors::ConnectorError::FailedToObtainAuthType => errors::ApiErrorResponse::InvalidConnectorConfiguration {config: "connector_account_details".to_string()}, errors::ConnectorError::InvalidConnectorConfig { config } => errors::ApiErrorResponse::InvalidConnectorConfiguration { config: config.to_string() }, errors::ConnectorError::FailedToObtainIntegrationUrl | errors::ConnectorError::RequestEncodingFailed | @@ -276,8 +276,7 @@ impl ConnectorErrorExt for error_stack::Result errors::ConnectorError::MissingRequiredField { field_name } => { errors::ApiErrorResponse::MissingRequiredField { field_name } } - errors::ConnectorError::FailedToObtainIntegrationUrl - | errors::ConnectorError::TemporaryConnectorCredentials => { + errors::ConnectorError::FailedToObtainIntegrationUrl => { errors::ApiErrorResponse::InvalidConnectorConfiguration { config: "connector_account_details".to_string(), } From eca262e05a0b35edf7740413c8d60ee70719491e Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 14:26:14 +0530 Subject: [PATCH 11/14] fix: use old amount struct in disputes --- crates/router/src/connector/paypal/transformers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 49c2f1c208b6..fe297d89bf92 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1696,7 +1696,7 @@ pub enum PaypalResource { pub struct PaypalDisputeWebhooks { pub dispute_id: String, pub dispute_transactions: Vec, - pub dispute_amount: OrderRequestAmount, + pub dispute_amount: OrderAmount, pub dispute_outcome: DisputeOutcome, pub dispute_life_cycle_stage: DisputeLifeCycleStage, pub status: DisputeStatus, From 7e7fce5c265feb81518af0c975b4d395e4eccc3c Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 14:40:45 +0530 Subject: [PATCH 12/14] fix: typos --- crates/router/src/connector/paypal/transformers.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index fe297d89bf92..8cdb220382c7 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -779,7 +779,7 @@ pub enum PaypalAuthType { #[derive(Debug)] pub enum PaypalConnectorCredentials { StandardIntegration(StandardFlowCredentials), - PartnerIntegration(PartnerFlowCredentails), + PartnerIntegration(PartnerFlowCredentials), } impl PaypalConnectorCredentials { @@ -821,7 +821,7 @@ pub struct StandardFlowCredentials { } #[derive(Debug)] -pub struct PartnerFlowCredentails { +pub struct PartnerFlowCredentials { pub(super) client_id: Secret, pub(super) client_secret: Secret, pub(super) payer_id: Secret, @@ -856,7 +856,7 @@ impl TryFrom<&ConnectorAuthType> for PaypalAuthType { key1, api_secret, } => Ok(Self::AuthWithDetails( - PaypalConnectorCredentials::PartnerIntegration(PartnerFlowCredentails { + PaypalConnectorCredentials::PartnerIntegration(PartnerFlowCredentials { client_id: key1.to_owned(), client_secret: api_key.to_owned(), payer_id: api_secret.to_owned(), From 0840fdfb4e48bf1eb7faa87a508335bf31deee5c Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 15:03:40 +0530 Subject: [PATCH 13/14] refactor: impl from for ItemDetails --- .../src/connector/paypal/transformers.rs | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 8cdb220382c7..3d2424e6d794 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -76,8 +76,8 @@ pub enum PaypalPaymentIntent { #[derive(Default, Debug, Clone, Serialize, Eq, PartialEq, Deserialize)] pub struct OrderAmount { - currency_code: storage_enums::Currency, - value: String, + pub currency_code: storage_enums::Currency, + pub value: String, } #[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq)] @@ -131,6 +131,22 @@ pub struct ItemDetails { unit_amount: OrderAmount, } +impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ItemDetails { + fn from(item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>) -> Self { + Self { + name: format!( + "Payment for invoice {}", + item.router_data.connector_request_reference_id + ), + quantity: 1, + unit_amount: OrderAmount { + currency_code: item.router_data.request.currency, + value: item.amount.to_string(), + }, + } + } +} + #[derive(Default, Debug, Serialize, Eq, PartialEq)] pub struct Address { address_line_1: Option>, @@ -401,14 +417,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let connector_request_reference_id = item.router_data.connector_request_reference_id.clone(); let shipping_address = ShippingAddress::try_from(item)?; - let item_details = vec![ItemDetails { - name: format!("Payment for invoice {}", connector_request_reference_id), - quantity: 1, - unit_amount: OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_string(), - }, - }]; + let item_details = vec![ItemDetails::from(item)]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_request_reference_id.clone()), @@ -458,14 +467,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); let shipping_address = ShippingAddress::try_from(item)?; - let item_details = vec![ItemDetails { - name: format!("Payment for invoice {}", connector_req_reference_id), - quantity: 1, - unit_amount: OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_string(), - }, - }]; + let item_details = vec![ItemDetails::from(item)]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_req_reference_id.clone()), @@ -536,14 +538,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let connector_req_reference_id = item.router_data.connector_request_reference_id.clone(); let shipping_address = ShippingAddress::try_from(item)?; - let item_details = vec![ItemDetails { - name: format!("Payment for invoice {}", connector_req_reference_id), - quantity: 1, - unit_amount: OrderAmount { - currency_code: item.router_data.request.currency, - value: item.amount.to_string(), - }, - }]; + let item_details = vec![ItemDetails::from(item)]; let purchase_units = vec![PurchaseUnitRequest { reference_id: Some(connector_req_reference_id.clone()), From 8df40dd962e3f9e695f394666a6cab191c61dcc5 Mon Sep 17 00:00:00 2001 From: Mani Chandra Dulam Date: Tue, 21 Nov 2023 15:28:49 +0530 Subject: [PATCH 14/14] fix: clippy lints --- crates/router/src/connector/paypal/transformers.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 3d2424e6d794..d023077ff008 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -780,22 +780,22 @@ pub enum PaypalConnectorCredentials { impl PaypalConnectorCredentials { pub fn get_client_id(&self) -> Secret { match self { - PaypalConnectorCredentials::StandardIntegration(item) => item.client_id.clone(), - PaypalConnectorCredentials::PartnerIntegration(item) => item.client_id.clone(), + Self::StandardIntegration(item) => item.client_id.clone(), + Self::PartnerIntegration(item) => item.client_id.clone(), } } pub fn get_client_secret(&self) -> Secret { match self { - PaypalConnectorCredentials::StandardIntegration(item) => item.client_secret.clone(), - PaypalConnectorCredentials::PartnerIntegration(item) => item.client_secret.clone(), + Self::StandardIntegration(item) => item.client_secret.clone(), + Self::PartnerIntegration(item) => item.client_secret.clone(), } } pub fn get_payer_id(&self) -> Option> { match self { - PaypalConnectorCredentials::StandardIntegration(_) => None, - PaypalConnectorCredentials::PartnerIntegration(item) => Some(item.payer_id.clone()), + Self::StandardIntegration(_) => None, + Self::PartnerIntegration(item) => Some(item.payer_id.clone()), } }