feat(connector): [Moneris] Implement mandate for Moneris (#7322)

This commit is contained in:
Swangi Kumari
2025-03-05 16:59:05 +05:30
committed by GitHub
parent 00d69bd924
commit ba84b00ede
2 changed files with 93 additions and 15 deletions

View File

@ -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<enums::PaymentMethodType>,
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<Session, PaymentsSessionData, PaymentsResponseData> for Moneris {

View File

@ -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<String, common_utils::pii::IpAddress>,
}
#[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<String>,
}
#[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<String>,
}
#[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<errors::ConnectorError>;
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<MonerisPaymentStatus> 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<String>,
}
impl<F, T> TryFrom<ResponseRouterData<F, MonerisPaymentsResponse, T, PaymentsResponseData>>
@ -254,7 +312,18 @@ impl<F, T> TryFrom<ResponseRouterData<F, MonerisPaymentsResponse, T, PaymentsRes
response: Ok(PaymentsResponseData::TransactionResponse {
resource_id: ResponseId::ConnectorTransactionId(item.response.payment_id.clone()),
redirection_data: Box::new(None),
mandate_reference: Box::new(None),
mandate_reference: Box::new(Some(MandateReference {
connector_mandate_id: Some(
item.response
.payment_method
.payment_method_id
.peek()
.to_string(),
),
payment_method_id: None,
mandate_metadata: None,
connector_mandate_request_reference_id: None,
})),
connector_metadata: None,
network_txn_id: None,
connector_response_reference_id: Some(item.response.payment_id),