mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 17:19:15 +08:00
feat(connector): [ACI] implement Card Mandates for ACI (#1174)
This commit is contained in:
@ -5,6 +5,7 @@ use std::fmt::Debug;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use transformers as aci;
|
||||
|
||||
use super::utils::PaymentsAuthorizeRequestData;
|
||||
use crate::{
|
||||
configs::settings,
|
||||
core::errors::{self, CustomResult},
|
||||
@ -245,10 +246,17 @@ impl
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &types::PaymentsAuthorizeRouterData,
|
||||
req: &types::PaymentsAuthorizeRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
Ok(format!("{}{}", self.base_url(connectors), "v1/payments"))
|
||||
match req.request.connector_mandate_id() {
|
||||
Some(mandate_id) => Ok(format!(
|
||||
"{}v1/registrations/{}/payments",
|
||||
self.base_url(connectors),
|
||||
mandate_id
|
||||
)),
|
||||
_ => Ok(format!("{}{}", self.base_url(connectors), "v1/payments")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use api_models::enums::BankNames;
|
||||
use common_utils::pii::Email;
|
||||
use error_stack::report;
|
||||
use masking::Secret;
|
||||
@ -8,12 +9,14 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::result_codes::{FAILURE_CODES, PENDING_CODES, SUCCESSFUL_CODES};
|
||||
use crate::{
|
||||
connector::utils,
|
||||
connector::utils::{self, RouterData},
|
||||
core::errors,
|
||||
services,
|
||||
types::{self, api, storage::enums},
|
||||
};
|
||||
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
pub struct AciAuthType {
|
||||
pub api_key: String,
|
||||
pub entity_id: String,
|
||||
@ -36,12 +39,22 @@ impl TryFrom<&types::ConnectorAuthType> for AciAuthType {
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AciPaymentsRequest {
|
||||
#[serde(flatten)]
|
||||
pub txn_details: TransactionDetails,
|
||||
#[serde(flatten)]
|
||||
pub payment_method: PaymentDetails,
|
||||
#[serde(flatten)]
|
||||
pub instruction: Option<Instruction>,
|
||||
pub shopper_result_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionDetails {
|
||||
pub entity_id: String,
|
||||
pub amount: String,
|
||||
pub currency: String,
|
||||
pub payment_type: AciPaymentType,
|
||||
#[serde(flatten)]
|
||||
pub payment_method: PaymentDetails,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
@ -59,6 +72,160 @@ pub enum PaymentDetails {
|
||||
BankRedirect(Box<BankRedirectionPMData>),
|
||||
Wallet(Box<WalletPMData>),
|
||||
Klarna,
|
||||
Mandate,
|
||||
}
|
||||
|
||||
impl TryFrom<&api_models::payments::WalletData> for PaymentDetails {
|
||||
type Error = Error;
|
||||
fn try_from(wallet_data: &api_models::payments::WalletData) -> Result<Self, Self::Error> {
|
||||
let payment_data = match wallet_data {
|
||||
api_models::payments::WalletData::MbWayRedirect(data) => {
|
||||
Self::Wallet(Box::new(WalletPMData {
|
||||
payment_brand: PaymentBrand::Mbway,
|
||||
account_id: Some(data.telephone_number.clone()),
|
||||
}))
|
||||
}
|
||||
api_models::payments::WalletData::AliPayRedirect { .. } => {
|
||||
Self::Wallet(Box::new(WalletPMData {
|
||||
payment_brand: PaymentBrand::AliPay,
|
||||
account_id: None,
|
||||
}))
|
||||
}
|
||||
_ => Err(errors::ConnectorError::NotImplemented(
|
||||
"Payment method".to_string(),
|
||||
))?,
|
||||
};
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::BankRedirectData,
|
||||
)> for PaymentDetails
|
||||
{
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::BankRedirectData,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, bank_redirect_data) = value;
|
||||
let payment_data = match bank_redirect_data {
|
||||
api_models::payments::BankRedirectData::Eps { .. } => {
|
||||
Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Eps,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::AT),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Giropay {
|
||||
bank_account_bic,
|
||||
bank_account_iban,
|
||||
..
|
||||
} => Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Giropay,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::DE),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: bank_account_bic.clone(),
|
||||
bank_account_iban: bank_account_iban.clone(),
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
})),
|
||||
api_models::payments::BankRedirectData::Ideal { bank_name, .. } => {
|
||||
Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Ideal,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::NL),
|
||||
bank_account_bank_name: bank_name.to_owned(),
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Sofort { country, .. } => {
|
||||
Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Sofortueberweisung,
|
||||
bank_account_country: Some(country.to_owned()),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Przelewy24 {
|
||||
billing_details, ..
|
||||
} => Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Przelewy,
|
||||
bank_account_country: None,
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: billing_details.email.to_owned(),
|
||||
})),
|
||||
api_models::payments::BankRedirectData::Interac { email, country } => {
|
||||
Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::InteracOnline,
|
||||
bank_account_country: Some(country.to_owned()),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: Some(email.to_owned()),
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Trustly { country } => {
|
||||
Self::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Trustly,
|
||||
bank_account_country: None,
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: Some(country.to_owned()),
|
||||
merchant_customer_id: Some(Secret::new(item.get_customer_id()?)),
|
||||
merchant_transaction_id: Some(Secret::new(item.payment_id.clone())),
|
||||
customer_email: None,
|
||||
}))
|
||||
}
|
||||
_ => Err(errors::ConnectorError::NotImplemented(
|
||||
"Payment method".to_string(),
|
||||
))?,
|
||||
};
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<api_models::payments::Card> for PaymentDetails {
|
||||
type Error = Error;
|
||||
fn try_from(card_data: api_models::payments::Card) -> Result<Self, Self::Error> {
|
||||
Ok(Self::AciCard(Box::new(CardDetails {
|
||||
card_number: card_data.card_number,
|
||||
card_holder: card_data.card_holder_name,
|
||||
card_expiry_month: card_data.card_exp_month,
|
||||
card_expiry_year: card_data.card_exp_year,
|
||||
card_cvv: card_data.card_cvc,
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
@ -68,7 +235,7 @@ pub struct BankRedirectionPMData {
|
||||
#[serde(rename = "bankAccount.country")]
|
||||
bank_account_country: Option<api_models::enums::CountryAlpha2>,
|
||||
#[serde(rename = "bankAccount.bankName")]
|
||||
bank_account_bank_name: Option<String>,
|
||||
bank_account_bank_name: Option<BankNames>,
|
||||
#[serde(rename = "bankAccount.bic")]
|
||||
bank_account_bic: Option<Secret<String>>,
|
||||
#[serde(rename = "bankAccount.iban")]
|
||||
@ -80,7 +247,6 @@ pub struct BankRedirectionPMData {
|
||||
#[serde(rename = "customer.merchantCustomerId")]
|
||||
merchant_customer_id: Option<Secret<String>>,
|
||||
merchant_transaction_id: Option<Secret<String>>,
|
||||
shopper_result_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
@ -89,7 +255,6 @@ pub struct WalletPMData {
|
||||
payment_brand: PaymentBrand,
|
||||
#[serde(rename = "virtualAccount.accountId")]
|
||||
account_id: Option<Secret<String>>,
|
||||
shopper_result_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@ -121,6 +286,43 @@ pub struct CardDetails {
|
||||
pub card_cvv: Secret<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum InstructionMode {
|
||||
Initial,
|
||||
Repeated,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum InstructionType {
|
||||
Unscheduled,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum InstructionSource {
|
||||
// Cardholder initiated transaction
|
||||
Cit,
|
||||
// Merchant initiated transaction
|
||||
Mit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Instruction {
|
||||
#[serde(rename = "standingInstruction.mode")]
|
||||
mode: InstructionMode,
|
||||
|
||||
#[serde(rename = "standingInstruction.type")]
|
||||
transaction_type: InstructionType,
|
||||
|
||||
#[serde(rename = "standingInstruction.source")]
|
||||
source: InstructionSource,
|
||||
|
||||
create_registration: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
|
||||
pub struct BankDetails {
|
||||
#[serde(rename = "bankAccount.holder")]
|
||||
@ -128,7 +330,7 @@ pub struct BankDetails {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize)]
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AciPaymentType {
|
||||
#[serde(rename = "PA")]
|
||||
Preauthorization,
|
||||
@ -148,177 +350,187 @@ pub enum AciPaymentType {
|
||||
impl TryFrom<&types::PaymentsAuthorizeRouterData> for AciPaymentsRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||
let payment_details: PaymentDetails = match item.request.payment_method_data.clone() {
|
||||
api::PaymentMethodData::Card(ccard) => PaymentDetails::AciCard(Box::new(CardDetails {
|
||||
card_number: ccard.card_number,
|
||||
card_holder: ccard.card_holder_name,
|
||||
card_expiry_month: ccard.card_exp_month,
|
||||
card_expiry_year: ccard.card_exp_year,
|
||||
card_cvv: ccard.card_cvc,
|
||||
})),
|
||||
api::PaymentMethodData::PayLater(_) => PaymentDetails::Klarna,
|
||||
api::PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
|
||||
api_models::payments::WalletData::MbWayRedirect(data) => {
|
||||
PaymentDetails::Wallet(Box::new(WalletPMData {
|
||||
payment_brand: PaymentBrand::Mbway,
|
||||
account_id: Some(data.telephone_number.clone()),
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
match item.request.payment_method_data.clone() {
|
||||
api::PaymentMethodData::Card(ref card_data) => Self::try_from((item, card_data)),
|
||||
api::PaymentMethodData::Wallet(ref wallet_data) => Self::try_from((item, wallet_data)),
|
||||
api::PaymentMethodData::PayLater(ref pay_later_data) => {
|
||||
Self::try_from((item, pay_later_data))
|
||||
}
|
||||
api_models::payments::WalletData::AliPayRedirect { .. } => {
|
||||
PaymentDetails::Wallet(Box::new(WalletPMData {
|
||||
payment_brand: PaymentBrand::AliPay,
|
||||
account_id: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
api::PaymentMethodData::BankRedirect(ref bank_redirect_data) => {
|
||||
Self::try_from((item, bank_redirect_data))
|
||||
}
|
||||
_ => Err(errors::ConnectorError::NotImplemented(
|
||||
"Payment method".to_string(),
|
||||
))?,
|
||||
},
|
||||
api::PaymentMethodData::BankRedirect(ref redirect_banking_data) => {
|
||||
match redirect_banking_data {
|
||||
api_models::payments::BankRedirectData::Eps { .. } => {
|
||||
PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Eps,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::AT),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Giropay {
|
||||
bank_account_bic,
|
||||
bank_account_iban,
|
||||
..
|
||||
} => PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Giropay,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::DE),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: bank_account_bic.clone(),
|
||||
bank_account_iban: bank_account_iban.clone(),
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})),
|
||||
api_models::payments::BankRedirectData::Ideal { bank_name, .. } => {
|
||||
PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Ideal,
|
||||
bank_account_country: Some(api_models::enums::CountryAlpha2::NL),
|
||||
bank_account_bank_name: bank_name
|
||||
.map(|bank_name| bank_name.to_string()),
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
}
|
||||
api_models::payments::BankRedirectData::Sofort { country, .. } => {
|
||||
PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Sofortueberweisung,
|
||||
bank_account_country: Some(*country),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
api_models::payments::BankRedirectData::Przelewy24 {
|
||||
billing_details, ..
|
||||
} => PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Przelewy,
|
||||
bank_account_country: None,
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: billing_details.email.clone(),
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})),
|
||||
|
||||
api_models::payments::BankRedirectData::Interac { email, country } => {
|
||||
PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::InteracOnline,
|
||||
bank_account_country: Some(*country),
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: None,
|
||||
merchant_customer_id: None,
|
||||
merchant_transaction_id: None,
|
||||
customer_email: Some(email.to_owned()),
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
api_models::payments::BankRedirectData::Trustly { country } => {
|
||||
PaymentDetails::BankRedirect(Box::new(BankRedirectionPMData {
|
||||
payment_brand: PaymentBrand::Trustly,
|
||||
bank_account_country: None,
|
||||
bank_account_bank_name: None,
|
||||
bank_account_bic: None,
|
||||
bank_account_iban: None,
|
||||
billing_country: Some(*country),
|
||||
merchant_customer_id: Some(Secret::new(
|
||||
item.customer_id.clone().ok_or(
|
||||
api::PaymentMethodData::MandatePayment => {
|
||||
let mandate_id = item.request.mandate_id.clone().ok_or(
|
||||
errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "customer_id",
|
||||
field_name: "mandate_id",
|
||||
},
|
||||
)?,
|
||||
)),
|
||||
merchant_transaction_id: Some(Secret::new(item.payment_id.clone())),
|
||||
customer_email: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
}))
|
||||
)?;
|
||||
Self::try_from((item, mandate_id))
|
||||
}
|
||||
|
||||
_ => Err(errors::ConnectorError::NotImplemented(
|
||||
"Payment method".to_string(),
|
||||
))?,
|
||||
}
|
||||
}
|
||||
|
||||
api::PaymentMethodData::Crypto(_)
|
||||
| api::PaymentMethodData::BankDebit(_)
|
||||
| api::PaymentMethodData::BankTransfer(_)
|
||||
| api::PaymentMethodData::Reward(_)
|
||||
| api::PaymentMethodData::MandatePayment => {
|
||||
Err(errors::ConnectorError::NotSupported {
|
||||
| api::PaymentMethodData::Reward(_) => Err(errors::ConnectorError::NotSupported {
|
||||
message: format!("{:?}", item.payment_method),
|
||||
connector: "Aci",
|
||||
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
|
||||
.to_string(),
|
||||
})?
|
||||
payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
|
||||
})?,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::WalletData,
|
||||
)> for AciPaymentsRequest
|
||||
{
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::WalletData,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, wallet_data) = value;
|
||||
let txn_details = get_transaction_details(item)?;
|
||||
let payment_method = PaymentDetails::try_from(wallet_data)?;
|
||||
|
||||
Ok(Self {
|
||||
txn_details,
|
||||
payment_method,
|
||||
instruction: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::BankRedirectData,
|
||||
)> for AciPaymentsRequest
|
||||
{
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::BankRedirectData,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, bank_redirect_data) = value;
|
||||
let txn_details = get_transaction_details(item)?;
|
||||
let payment_method = PaymentDetails::try_from((item, bank_redirect_data))?;
|
||||
|
||||
Ok(Self {
|
||||
txn_details,
|
||||
payment_method,
|
||||
instruction: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::PayLaterData,
|
||||
)> for AciPaymentsRequest
|
||||
{
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
&api_models::payments::PayLaterData,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, _pay_later_data) = value;
|
||||
let txn_details = get_transaction_details(item)?;
|
||||
let payment_method = PaymentDetails::Klarna;
|
||||
|
||||
Ok(Self {
|
||||
txn_details,
|
||||
payment_method,
|
||||
instruction: None,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(&types::PaymentsAuthorizeRouterData, &api::Card)> for AciPaymentsRequest {
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (&types::PaymentsAuthorizeRouterData, &api::Card),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, card_data) = value;
|
||||
let txn_details = get_transaction_details(item)?;
|
||||
let payment_method = PaymentDetails::try_from(card_data.clone())?;
|
||||
let instruction = get_instruction_details(item);
|
||||
|
||||
Ok(Self {
|
||||
txn_details,
|
||||
payment_method,
|
||||
instruction,
|
||||
shopper_result_url: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<(
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
api_models::payments::MandateIds,
|
||||
)> for AciPaymentsRequest
|
||||
{
|
||||
type Error = Error;
|
||||
fn try_from(
|
||||
value: (
|
||||
&types::PaymentsAuthorizeRouterData,
|
||||
api_models::payments::MandateIds,
|
||||
),
|
||||
) -> Result<Self, Self::Error> {
|
||||
let (item, _mandate_data) = value;
|
||||
let instruction = get_instruction_details(item);
|
||||
let txn_details = get_transaction_details(item)?;
|
||||
|
||||
Ok(Self {
|
||||
txn_details,
|
||||
payment_method: PaymentDetails::Mandate,
|
||||
instruction,
|
||||
shopper_result_url: item.request.router_return_url.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn get_transaction_details(
|
||||
item: &types::PaymentsAuthorizeRouterData,
|
||||
) -> Result<TransactionDetails, error_stack::Report<errors::ConnectorError>> {
|
||||
let auth = AciAuthType::try_from(&item.connector_auth_type)?;
|
||||
let aci_payment_request = Self {
|
||||
payment_method: payment_details,
|
||||
Ok(TransactionDetails {
|
||||
entity_id: auth.entity_id,
|
||||
amount: utils::to_currency_base_unit(item.request.amount, item.request.currency)?,
|
||||
currency: item.request.currency.to_string(),
|
||||
payment_type: AciPaymentType::Debit,
|
||||
};
|
||||
Ok(aci_payment_request)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_instruction_details(item: &types::PaymentsAuthorizeRouterData) -> Option<Instruction> {
|
||||
if item.request.setup_mandate_details.is_some() {
|
||||
return Some(Instruction {
|
||||
mode: InstructionMode::Initial,
|
||||
transaction_type: InstructionType::Unscheduled,
|
||||
source: InstructionSource::Cit,
|
||||
create_registration: Some(true),
|
||||
});
|
||||
} else if item.request.mandate_id.is_some() {
|
||||
return Some(Instruction {
|
||||
mode: InstructionMode::Repeated,
|
||||
transaction_type: InstructionType::Unscheduled,
|
||||
source: InstructionSource::Mit,
|
||||
create_registration: None,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl TryFrom<&types::PaymentsCancelRouterData> for AciCancelRequest {
|
||||
@ -374,6 +586,7 @@ impl FromStr for AciPaymentStatus {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AciPaymentsResponse {
|
||||
id: String,
|
||||
registration_id: Option<String>,
|
||||
// ndc is an internal unique identifier for the request.
|
||||
ndc: String,
|
||||
timestamp: String,
|
||||
@ -437,6 +650,14 @@ impl<F, T>
|
||||
}
|
||||
});
|
||||
|
||||
let mandate_reference = item
|
||||
.response
|
||||
.registration_id
|
||||
.map(|id| types::MandateReference {
|
||||
connector_mandate_id: Some(id),
|
||||
payment_method_id: None,
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
status: {
|
||||
if redirection_data.is_some() {
|
||||
@ -450,7 +671,7 @@ impl<F, T>
|
||||
response: Ok(types::PaymentsResponseData::TransactionResponse {
|
||||
resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
|
||||
redirection_data,
|
||||
mandate_reference: None,
|
||||
mandate_reference,
|
||||
connector_metadata: None,
|
||||
network_txn_id: None,
|
||||
}),
|
||||
|
||||
@ -267,6 +267,8 @@ pub enum ConnectorError {
|
||||
FlowNotSupported { flow: String, connector: String },
|
||||
#[error("Capture method not supported")]
|
||||
CaptureMethodNotSupported,
|
||||
#[error("Missing connector mandate ID")]
|
||||
MissingConnectorMandateID,
|
||||
#[error("Missing connector transaction ID")]
|
||||
MissingConnectorTransactionID,
|
||||
#[error("Missing connector refund ID")]
|
||||
|
||||
Reference in New Issue
Block a user