From ba84b00edebb5884fb68270ad8cf3e3f50883c55 Mon Sep 17 00:00:00 2001 From: Swangi Kumari <85639103+swangi-kumari@users.noreply.github.com> Date: Wed, 5 Mar 2025 16:59:05 +0530 Subject: [PATCH] feat(connector): [Moneris] Implement mandate for Moneris (#7322) --- .../src/connectors/moneris.rs | 11 ++- .../src/connectors/moneris/transformers.rs | 97 ++++++++++++++++--- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/crates/hyperswitch_connectors/src/connectors/moneris.rs b/crates/hyperswitch_connectors/src/connectors/moneris.rs index 46b0ee9472..c8f542c1ba 100644 --- a/crates/hyperswitch_connectors/src/connectors/moneris.rs +++ b/crates/hyperswitch_connectors/src/connectors/moneris.rs @@ -43,7 +43,7 @@ use transformers as moneris; use crate::{ constants::headers, types::ResponseRouterData, - utils::{self, RefundsRequestData}, + utils::{self, is_mandate_supported, PaymentMethodDataType, RefundsRequestData}, }; #[derive(Clone)] @@ -195,6 +195,15 @@ impl ConnectorValidation for Moneris { ), } } + + fn validate_mandate_payment( + &self, + pm_type: Option, + pm_data: hyperswitch_domain_models::payment_method_data::PaymentMethodData, + ) -> CustomResult<(), errors::ConnectorError> { + let mandate_supported_pmd = std::collections::HashSet::from([PaymentMethodDataType::Card]); + is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + } } impl ConnectorIntegration for Moneris { diff --git a/crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs b/crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs index b8fb3d0fc5..29b3a28a85 100644 --- a/crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/moneris/transformers.rs @@ -6,7 +6,7 @@ use hyperswitch_domain_models::{ router_data::{AccessToken, ConnectorAuthType, RouterData}, router_flow_types::refunds::{Execute, RSync}, router_request_types::ResponseId, - router_response_types::{PaymentsResponseData, RefundsResponseData}, + router_response_types::{MandateReference, PaymentsResponseData, RefundsResponseData}, types::{ PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, RefundsRouterData, @@ -18,10 +18,7 @@ use serde::{Deserialize, Serialize}; use crate::{ types::{RefreshTokenRouterData, RefundsResponseRouterData, ResponseRouterData}, - utils::{ - BrowserInformationData, CardData as _, PaymentsAuthorizeRequestData, - RouterData as OtherRouterData, - }, + utils::{CardData as _, PaymentsAuthorizeRequestData, RouterData as OtherRouterData}, }; const CLIENT_CREDENTIALS: &str = "client_credentials"; @@ -52,7 +49,6 @@ pub struct MonerisPaymentsRequest { amount: Amount, payment_method: PaymentMethod, automatic_capture: bool, - ipv4: Secret, } #[derive(Default, Debug, Serialize, PartialEq)] #[serde(rename_all = "camelCase")] @@ -63,15 +59,32 @@ pub struct Amount { #[derive(Debug, Serialize, PartialEq)] #[serde(rename_all = "camelCase")] -pub struct PaymentMethod { +#[serde(untagged)] +pub enum PaymentMethod { + Card(PaymentMethodCard), + PaymentMethodId(PaymentMethodId), +} + +#[derive(Debug, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct PaymentMethodCard { payment_method_source: PaymentMethodSource, card: MonerisCard, + store_payment_method: StorePaymentMethod, +} + +#[derive(Debug, Serialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct PaymentMethodId { + payment_method_source: PaymentMethodSource, + payment_method_id: Secret, } #[derive(Debug, Serialize, PartialEq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum PaymentMethodSource { Card, + PaymentMethodId, } #[derive(Default, Debug, Serialize, Eq, PartialEq)] @@ -83,6 +96,14 @@ pub struct MonerisCard { card_security_code: Secret, } +#[derive(Debug, Serialize, Eq, PartialEq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum StorePaymentMethod { + DoNotStore, + CardholderInitiated, + MerchantInitiated, +} + impl TryFrom<&MonerisRouterData<&PaymentsAuthorizeRouterData>> for MonerisPaymentsRequest { type Error = error_stack::Report; fn try_from( @@ -101,7 +122,7 @@ impl TryFrom<&MonerisRouterData<&PaymentsAuthorizeRouterData>> for MonerisPaymen currency: item.router_data.request.currency, amount: item.amount, }; - let payment_method = PaymentMethod { + let payment_method = PaymentMethod::Card(PaymentMethodCard { payment_method_source: PaymentMethodSource::Card, card: MonerisCard { card_number: req_card.card_number.clone(), @@ -121,18 +142,48 @@ impl TryFrom<&MonerisRouterData<&PaymentsAuthorizeRouterData>> for MonerisPaymen ), card_security_code: req_card.card_cvc.clone(), }, - }; + store_payment_method: if item + .router_data + .request + .is_customer_initiated_mandate_payment() + { + StorePaymentMethod::CardholderInitiated + } else { + StorePaymentMethod::DoNotStore + }, + }); let automatic_capture = item.router_data.request.is_auto_capture()?; - let browser_info = item.router_data.request.get_browser_info()?; - let ipv4 = browser_info.get_ip_address()?; - Ok(Self { idempotency_key, amount, payment_method, automatic_capture, - ipv4, + }) + } + PaymentMethodData::MandatePayment => { + let idempotency_key = uuid::Uuid::new_v4().to_string(); + let amount = Amount { + currency: item.router_data.request.currency, + amount: item.amount, + }; + let automatic_capture = item.router_data.request.is_auto_capture()?; + let payment_method = PaymentMethod::PaymentMethodId(PaymentMethodId { + payment_method_source: PaymentMethodSource::PaymentMethodId, + payment_method_id: item + .router_data + .request + .connector_mandate_id() + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "connector_mandate_id", + })? + .into(), + }); + Ok(Self { + idempotency_key, + amount, + payment_method, + automatic_capture, }) } _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()), @@ -240,6 +291,13 @@ impl From for common_enums::AttemptStatus { pub struct MonerisPaymentsResponse { payment_status: MonerisPaymentStatus, payment_id: String, + payment_method: MonerisPaymentMethodData, +} + +#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct MonerisPaymentMethodData { + payment_method_id: Secret, } impl TryFrom> @@ -254,7 +312,18 @@ impl TryFrom