mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
feat(connector): [Novalnet] Add zero auth mandate (#6631)
This commit is contained in:
@ -28,7 +28,7 @@ use hyperswitch_domain_models::{
|
||||
router_response_types::{PaymentsResponseData, RefundsResponseData},
|
||||
types::{
|
||||
PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
|
||||
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
|
||||
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData,
|
||||
},
|
||||
};
|
||||
use hyperswitch_interfaces::{
|
||||
@ -231,6 +231,79 @@ impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken>
|
||||
impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
|
||||
for Novalnet
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &SetupMandateRouterData,
|
||||
connectors: &Connectors,
|
||||
) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
_req: &SetupMandateRouterData,
|
||||
connectors: &Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
let endpoint = self.base_url(connectors);
|
||||
Ok(format!("{}/payment", endpoint))
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &SetupMandateRouterData,
|
||||
_connectors: &Connectors,
|
||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||
let connector_req = novalnet::NovalnetPaymentsRequest::try_from(req)?;
|
||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &SetupMandateRouterData,
|
||||
connectors: &Connectors,
|
||||
) -> CustomResult<Option<Request>, errors::ConnectorError> {
|
||||
Ok(Some(
|
||||
RequestBuilder::new()
|
||||
.method(Method::Post)
|
||||
.url(&types::SetupMandateType::get_url(self, req, connectors)?)
|
||||
.attach_default_headers()
|
||||
.headers(types::SetupMandateType::get_headers(self, req, connectors)?)
|
||||
.set_body(types::SetupMandateType::get_request_body(
|
||||
self, req, connectors,
|
||||
)?)
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &SetupMandateRouterData,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
res: Response,
|
||||
) -> CustomResult<SetupMandateRouterData, errors::ConnectorError> {
|
||||
let response: novalnet::NovalnetPaymentsResponse = res
|
||||
.response
|
||||
.parse_struct("Novalnet PaymentsAuthorizeResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
RouterData::try_from(ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
}
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: Response,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res, event_builder)
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Novalnet {
|
||||
|
||||
@ -17,7 +17,7 @@ use hyperswitch_domain_models::{
|
||||
},
|
||||
types::{
|
||||
PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
|
||||
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
|
||||
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData,
|
||||
},
|
||||
};
|
||||
use hyperswitch_interfaces::errors;
|
||||
@ -28,8 +28,9 @@ use strum::Display;
|
||||
use crate::{
|
||||
types::{RefundsResponseRouterData, ResponseRouterData},
|
||||
utils::{
|
||||
self, ApplePay, PaymentsAuthorizeRequestData, PaymentsCancelRequestData,
|
||||
PaymentsCaptureRequestData, PaymentsSyncRequestData, RefundsRequestData, RouterData as _,
|
||||
self, AddressDetailsData, ApplePay, PaymentsAuthorizeRequestData,
|
||||
PaymentsCancelRequestData, PaymentsCaptureRequestData, PaymentsSetupMandateRequestData,
|
||||
PaymentsSyncRequestData, RefundsRequestData, RouterData as _,
|
||||
},
|
||||
};
|
||||
|
||||
@ -47,6 +48,19 @@ impl<T> From<(StringMinorUnit, T)> for NovalnetRouterData<T> {
|
||||
}
|
||||
}
|
||||
|
||||
const MINIMAL_CUSTOMER_DATA_PASSED: i64 = 1;
|
||||
const CREATE_TOKEN_REQUIRED: i8 = 1;
|
||||
|
||||
const TEST_MODE_ENABLED: i8 = 1;
|
||||
const TEST_MODE_DISABLED: i8 = 0;
|
||||
|
||||
fn get_test_mode(item: Option<bool>) -> i8 {
|
||||
match item {
|
||||
Some(true) => TEST_MODE_ENABLED,
|
||||
Some(false) | None => TEST_MODE_DISABLED,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Serialize, Deserialize, Clone)]
|
||||
pub enum NovalNetPaymentTypes {
|
||||
CREDITCARD,
|
||||
@ -117,11 +131,18 @@ pub struct NovalnetCustom {
|
||||
lang: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum NovalNetAmount {
|
||||
StringMinor(StringMinorUnit),
|
||||
Int(i64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct NovalnetPaymentsRequestTransaction {
|
||||
test_mode: i8,
|
||||
payment_type: NovalNetPaymentTypes,
|
||||
amount: StringMinorUnit,
|
||||
amount: NovalNetAmount,
|
||||
currency: common_enums::Currency,
|
||||
order_no: String,
|
||||
payment_data: Option<NovalNetPaymentData>,
|
||||
@ -171,10 +192,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
enums::AuthenticationType::ThreeDs => Some(1),
|
||||
enums::AuthenticationType::NoThreeDs => None,
|
||||
};
|
||||
let test_mode = match item.router_data.test_mode {
|
||||
Some(true) => 1,
|
||||
Some(false) | None => 0,
|
||||
};
|
||||
let test_mode = get_test_mode(item.router_data.test_mode);
|
||||
|
||||
let billing = NovalnetPaymentsRequestBilling {
|
||||
house_no: item.router_data.get_optional_billing_line1(),
|
||||
@ -197,7 +215,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
mobile: item.router_data.get_optional_billing_phone_number(),
|
||||
billing: Some(billing),
|
||||
// no_nc is used to indicate if minimal customer data is passed or not
|
||||
no_nc: 1,
|
||||
no_nc: MINIMAL_CUSTOMER_DATA_PASSED,
|
||||
};
|
||||
|
||||
let lang = item
|
||||
@ -209,7 +227,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let hook_url = item.router_data.request.get_webhook_url()?;
|
||||
let return_url = item.router_data.request.get_router_return_url()?;
|
||||
let create_token = if item.router_data.request.is_mandate_payment() {
|
||||
Some(1)
|
||||
Some(CREATE_TOKEN_REQUIRED)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -234,7 +252,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::CREDITCARD,
|
||||
amount: item.amount.clone(),
|
||||
amount: NovalNetAmount::StringMinor(item.amount.clone()),
|
||||
currency: item.router_data.request.currency,
|
||||
order_no: item.router_data.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
@ -265,7 +283,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::GOOGLEPAY,
|
||||
amount: item.amount.clone(),
|
||||
amount: NovalNetAmount::StringMinor(item.amount.clone()),
|
||||
currency: item.router_data.request.currency,
|
||||
order_no: item.router_data.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
@ -287,7 +305,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::APPLEPAY,
|
||||
amount: item.amount.clone(),
|
||||
amount: NovalNetAmount::StringMinor(item.amount.clone()),
|
||||
currency: item.router_data.request.currency,
|
||||
order_no: item.router_data.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
@ -331,7 +349,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::PAYPAL,
|
||||
amount: item.amount.clone(),
|
||||
amount: NovalNetAmount::StringMinor(item.amount.clone()),
|
||||
currency: item.router_data.request.currency,
|
||||
order_no: item.router_data.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
@ -389,7 +407,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type,
|
||||
amount: item.amount.clone(),
|
||||
amount: NovalNetAmount::StringMinor(item.amount.clone()),
|
||||
currency: item.router_data.request.currency,
|
||||
order_no: item.router_data.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
@ -1380,3 +1398,194 @@ pub fn get_novalnet_dispute_status(status: WebhookEventType) -> WebhookDisputeSt
|
||||
pub fn option_to_result<T>(opt: Option<T>) -> Result<T, errors::ConnectorError> {
|
||||
opt.ok_or(errors::ConnectorError::WebhookBodyDecodingFailed)
|
||||
}
|
||||
|
||||
impl TryFrom<&SetupMandateRouterData> for NovalnetPaymentsRequest {
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(item: &SetupMandateRouterData) -> Result<Self, Self::Error> {
|
||||
let auth = NovalnetAuthType::try_from(&item.connector_auth_type)?;
|
||||
|
||||
let merchant = NovalnetPaymentsRequestMerchant {
|
||||
signature: auth.product_activation_key,
|
||||
tariff: auth.tariff_id,
|
||||
};
|
||||
|
||||
let enforce_3d = match item.auth_type {
|
||||
enums::AuthenticationType::ThreeDs => Some(1),
|
||||
enums::AuthenticationType::NoThreeDs => None,
|
||||
};
|
||||
let test_mode = get_test_mode(item.test_mode);
|
||||
let req_address = item.get_billing_address()?.to_owned();
|
||||
|
||||
let billing = NovalnetPaymentsRequestBilling {
|
||||
house_no: item.get_optional_billing_line1(),
|
||||
street: item.get_optional_billing_line2(),
|
||||
city: item.get_optional_billing_city().map(Secret::new),
|
||||
zip: item.get_optional_billing_zip(),
|
||||
country_code: item.get_optional_billing_country(),
|
||||
};
|
||||
|
||||
let customer = NovalnetPaymentsRequestCustomer {
|
||||
first_name: req_address.get_first_name()?.clone(),
|
||||
last_name: req_address.get_last_name()?.clone(),
|
||||
email: item.request.get_email()?.clone(),
|
||||
mobile: item.get_optional_billing_phone_number(),
|
||||
billing: Some(billing),
|
||||
// no_nc is used to indicate if minimal customer data is passed or not
|
||||
no_nc: MINIMAL_CUSTOMER_DATA_PASSED,
|
||||
};
|
||||
|
||||
let lang = item
|
||||
.request
|
||||
.get_optional_language_from_browser_info()
|
||||
.unwrap_or(consts::DEFAULT_LOCALE.to_string().to_string());
|
||||
|
||||
let custom = NovalnetCustom { lang };
|
||||
let hook_url = item.request.get_webhook_url()?;
|
||||
let return_url = item.request.get_return_url()?;
|
||||
let create_token = Some(CREATE_TOKEN_REQUIRED);
|
||||
|
||||
match item.request.payment_method_data {
|
||||
PaymentMethodData::Card(ref req_card) => {
|
||||
let novalnet_card = NovalNetPaymentData::Card(NovalnetCard {
|
||||
card_number: req_card.card_number.clone(),
|
||||
card_expiry_month: req_card.card_exp_month.clone(),
|
||||
card_expiry_year: req_card.card_exp_year.clone(),
|
||||
card_cvc: req_card.card_cvc.clone(),
|
||||
card_holder: req_address.get_full_name()?.clone(),
|
||||
});
|
||||
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::CREDITCARD,
|
||||
amount: NovalNetAmount::Int(0),
|
||||
currency: item.request.currency,
|
||||
order_no: item.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
return_url: Some(return_url.clone()),
|
||||
error_return_url: Some(return_url.clone()),
|
||||
payment_data: Some(novalnet_card),
|
||||
enforce_3d,
|
||||
create_token,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
merchant,
|
||||
transaction,
|
||||
customer,
|
||||
custom,
|
||||
})
|
||||
}
|
||||
|
||||
PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
|
||||
WalletDataPaymentMethod::GooglePay(ref req_wallet) => {
|
||||
let novalnet_google_pay: NovalNetPaymentData =
|
||||
NovalNetPaymentData::GooglePay(NovalnetGooglePay {
|
||||
wallet_data: Secret::new(req_wallet.tokenization_data.token.clone()),
|
||||
});
|
||||
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::GOOGLEPAY,
|
||||
amount: NovalNetAmount::Int(0),
|
||||
currency: item.request.currency,
|
||||
order_no: item.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
return_url: None,
|
||||
error_return_url: None,
|
||||
payment_data: Some(novalnet_google_pay),
|
||||
enforce_3d,
|
||||
create_token,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
merchant,
|
||||
transaction,
|
||||
customer,
|
||||
custom,
|
||||
})
|
||||
}
|
||||
WalletDataPaymentMethod::ApplePay(payment_method_data) => {
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::APPLEPAY,
|
||||
amount: NovalNetAmount::Int(0),
|
||||
currency: item.request.currency,
|
||||
order_no: item.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
return_url: None,
|
||||
error_return_url: None,
|
||||
payment_data: Some(NovalNetPaymentData::ApplePay(NovalnetApplePay {
|
||||
wallet_data: Secret::new(payment_method_data.payment_data.clone()),
|
||||
})),
|
||||
enforce_3d: None,
|
||||
create_token,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
merchant,
|
||||
transaction,
|
||||
customer,
|
||||
custom,
|
||||
})
|
||||
}
|
||||
WalletDataPaymentMethod::AliPayQr(_)
|
||||
| WalletDataPaymentMethod::AliPayRedirect(_)
|
||||
| WalletDataPaymentMethod::AliPayHkRedirect(_)
|
||||
| WalletDataPaymentMethod::MomoRedirect(_)
|
||||
| WalletDataPaymentMethod::KakaoPayRedirect(_)
|
||||
| WalletDataPaymentMethod::GoPayRedirect(_)
|
||||
| WalletDataPaymentMethod::GcashRedirect(_)
|
||||
| WalletDataPaymentMethod::ApplePayRedirect(_)
|
||||
| WalletDataPaymentMethod::ApplePayThirdPartySdk(_)
|
||||
| WalletDataPaymentMethod::DanaRedirect {}
|
||||
| WalletDataPaymentMethod::GooglePayRedirect(_)
|
||||
| WalletDataPaymentMethod::GooglePayThirdPartySdk(_)
|
||||
| WalletDataPaymentMethod::MbWayRedirect(_)
|
||||
| WalletDataPaymentMethod::MobilePayRedirect(_) => {
|
||||
Err(errors::ConnectorError::NotImplemented(
|
||||
utils::get_unimplemented_payment_method_error_message("novalnet"),
|
||||
))?
|
||||
}
|
||||
WalletDataPaymentMethod::PaypalRedirect(_) => {
|
||||
let transaction = NovalnetPaymentsRequestTransaction {
|
||||
test_mode,
|
||||
payment_type: NovalNetPaymentTypes::PAYPAL,
|
||||
amount: NovalNetAmount::Int(0),
|
||||
currency: item.request.currency,
|
||||
order_no: item.connector_request_reference_id.clone(),
|
||||
hook_url: Some(hook_url),
|
||||
return_url: Some(return_url.clone()),
|
||||
error_return_url: Some(return_url.clone()),
|
||||
payment_data: None,
|
||||
enforce_3d: None,
|
||||
create_token,
|
||||
};
|
||||
Ok(Self {
|
||||
merchant,
|
||||
transaction,
|
||||
customer,
|
||||
custom,
|
||||
})
|
||||
}
|
||||
WalletDataPaymentMethod::PaypalSdk(_)
|
||||
| WalletDataPaymentMethod::Paze(_)
|
||||
| WalletDataPaymentMethod::SamsungPay(_)
|
||||
| WalletDataPaymentMethod::TwintRedirect {}
|
||||
| WalletDataPaymentMethod::VippsRedirect {}
|
||||
| WalletDataPaymentMethod::TouchNGoRedirect(_)
|
||||
| WalletDataPaymentMethod::WeChatPayRedirect(_)
|
||||
| WalletDataPaymentMethod::CashappQr(_)
|
||||
| WalletDataPaymentMethod::SwishQr(_)
|
||||
| WalletDataPaymentMethod::WeChatPayQr(_)
|
||||
| WalletDataPaymentMethod::Mifinity(_) => {
|
||||
Err(errors::ConnectorError::NotImplemented(
|
||||
utils::get_unimplemented_payment_method_error_message("novalnet"),
|
||||
))?
|
||||
}
|
||||
},
|
||||
_ => Err(errors::ConnectorError::NotImplemented(
|
||||
utils::get_unimplemented_payment_method_error_message("novalnet"),
|
||||
))?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1595,6 +1595,9 @@ pub trait PaymentsSetupMandateRequestData {
|
||||
fn get_email(&self) -> Result<Email, Error>;
|
||||
fn get_router_return_url(&self) -> Result<String, Error>;
|
||||
fn is_card(&self) -> bool;
|
||||
fn get_return_url(&self) -> Result<String, Error>;
|
||||
fn get_webhook_url(&self) -> Result<String, Error>;
|
||||
fn get_optional_language_from_browser_info(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
impl PaymentsSetupMandateRequestData for SetupMandateRequestData {
|
||||
@ -1614,6 +1617,21 @@ impl PaymentsSetupMandateRequestData for SetupMandateRequestData {
|
||||
fn is_card(&self) -> bool {
|
||||
matches!(self.payment_method_data, PaymentMethodData::Card(_))
|
||||
}
|
||||
fn get_return_url(&self) -> Result<String, Error> {
|
||||
self.router_return_url
|
||||
.clone()
|
||||
.ok_or_else(missing_field_err("return_url"))
|
||||
}
|
||||
fn get_webhook_url(&self) -> Result<String, Error> {
|
||||
self.webhook_url
|
||||
.clone()
|
||||
.ok_or_else(missing_field_err("webhook_url"))
|
||||
}
|
||||
fn get_optional_language_from_browser_info(&self) -> Option<String> {
|
||||
self.browser_info
|
||||
.clone()
|
||||
.and_then(|browser_info| browser_info.language)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PaymentMethodTokenizationRequestData {
|
||||
|
||||
@ -871,6 +871,7 @@ pub struct SetupMandateRequestData {
|
||||
pub off_session: Option<bool>,
|
||||
pub setup_mandate_details: Option<mandates::MandateData>,
|
||||
pub router_return_url: Option<String>,
|
||||
pub webhook_url: Option<String>,
|
||||
pub browser_info: Option<BrowserInformation>,
|
||||
pub email: Option<pii::Email>,
|
||||
pub customer_name: Option<Secret<String>>,
|
||||
|
||||
@ -6564,8 +6564,17 @@ pub async fn payment_external_authentication(
|
||||
&payment_attempt.clone(),
|
||||
payment_connector_name,
|
||||
));
|
||||
let webhook_url =
|
||||
helpers::create_webhook_url(&state.base_url, merchant_id, &authentication_connector);
|
||||
let mca_id_option = merchant_connector_account.get_mca_id(); // Bind temporary value
|
||||
let merchant_connector_account_id_or_connector_name = mca_id_option
|
||||
.as_ref()
|
||||
.map(|mca_id| mca_id.get_string_repr())
|
||||
.unwrap_or(&authentication_connector);
|
||||
|
||||
let webhook_url = helpers::create_webhook_url(
|
||||
&state.base_url,
|
||||
merchant_id,
|
||||
merchant_connector_account_id_or_connector_name,
|
||||
);
|
||||
|
||||
let authentication_details = business_profile
|
||||
.authentication_connector_details
|
||||
|
||||
@ -1241,17 +1241,18 @@ pub fn create_authorize_url(
|
||||
}
|
||||
|
||||
pub fn create_webhook_url(
|
||||
router_base_url: &String,
|
||||
router_base_url: &str,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
connector_name: impl std::fmt::Display,
|
||||
merchant_connector_id_or_connector_name: &str,
|
||||
) -> String {
|
||||
format!(
|
||||
"{}/webhooks/{}/{}",
|
||||
router_base_url,
|
||||
merchant_id.get_string_repr(),
|
||||
connector_name
|
||||
merchant_connector_id_or_connector_name,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_complete_authorize_url(
|
||||
router_base_url: &String,
|
||||
payment_attempt: &PaymentAttempt,
|
||||
|
||||
@ -225,7 +225,7 @@ pub async fn construct_payment_router_data_for_authorize<'a>(
|
||||
let webhook_url = Some(helpers::create_webhook_url(
|
||||
router_base_url,
|
||||
&attempt.merchant_id,
|
||||
connector_id,
|
||||
merchant_connector_account.get_id().get_string_repr(),
|
||||
));
|
||||
|
||||
let router_return_url = payment_data
|
||||
@ -2751,11 +2751,17 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
|
||||
attempt,
|
||||
connector_name,
|
||||
));
|
||||
let merchant_connector_account_id_or_connector_name = payment_data
|
||||
.payment_attempt
|
||||
.merchant_connector_id
|
||||
.as_ref()
|
||||
.map(|mca_id| mca_id.get_string_repr())
|
||||
.unwrap_or(connector_name);
|
||||
|
||||
let webhook_url = Some(helpers::create_webhook_url(
|
||||
router_base_url,
|
||||
&attempt.merchant_id,
|
||||
connector_name,
|
||||
merchant_connector_account_id_or_connector_name,
|
||||
));
|
||||
let router_return_url = Some(helpers::create_redirect_url(
|
||||
router_base_url,
|
||||
@ -3575,6 +3581,18 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequ
|
||||
.map(|customer| customer.clone().into_inner())
|
||||
});
|
||||
let amount = payment_data.payment_attempt.get_total_amount();
|
||||
let merchant_connector_account_id_or_connector_name = payment_data
|
||||
.payment_attempt
|
||||
.merchant_connector_id
|
||||
.as_ref()
|
||||
.map(|mca_id| mca_id.get_string_repr())
|
||||
.unwrap_or(connector_name);
|
||||
let webhook_url = Some(helpers::create_webhook_url(
|
||||
router_base_url,
|
||||
&attempt.merchant_id,
|
||||
merchant_connector_account_id_or_connector_name,
|
||||
));
|
||||
|
||||
Ok(Self {
|
||||
currency: payment_data.currency,
|
||||
confirm: true,
|
||||
@ -3604,6 +3622,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequ
|
||||
),
|
||||
metadata: payment_data.payment_intent.metadata.clone().map(Into::into),
|
||||
shipping_cost: payment_data.payment_intent.shipping_cost,
|
||||
webhook_url,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -3770,11 +3789,16 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPreProce
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let merchant_connector_account_id_or_connector_name = payment_data
|
||||
.payment_attempt
|
||||
.merchant_connector_id
|
||||
.as_ref()
|
||||
.map(|mca_id| mca_id.get_string_repr())
|
||||
.unwrap_or(connector_name);
|
||||
let webhook_url = Some(helpers::create_webhook_url(
|
||||
router_base_url,
|
||||
&attempt.merchant_id,
|
||||
connector_name,
|
||||
merchant_connector_account_id_or_connector_name,
|
||||
));
|
||||
let router_return_url = Some(helpers::create_redirect_url(
|
||||
router_base_url,
|
||||
|
||||
@ -32,7 +32,7 @@ pub async fn construct_relay_refund_router_data<'a, F>(
|
||||
let webhook_url = Some(payments::helpers::create_webhook_url(
|
||||
&state.base_url.clone(),
|
||||
merchant_id,
|
||||
connector_name,
|
||||
connector_account.get_id().get_string_repr(),
|
||||
));
|
||||
|
||||
let supported_connector = &state
|
||||
|
||||
@ -288,11 +288,16 @@ pub async fn construct_refund_router_data<'a, F>(
|
||||
.payment_method
|
||||
.get_required_value("payment_method_type")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let merchant_connector_account_id_or_connector_name = payment_attempt
|
||||
.merchant_connector_id
|
||||
.as_ref()
|
||||
.map(|mca_id| mca_id.get_string_repr())
|
||||
.unwrap_or(connector_id);
|
||||
|
||||
let webhook_url = Some(helpers::create_webhook_url(
|
||||
&state.base_url.clone(),
|
||||
merchant_account.get_id(),
|
||||
connector_id,
|
||||
merchant_connector_account_id_or_connector_name,
|
||||
));
|
||||
let test_mode: Option<bool> = merchant_connector_account.is_test_mode_on();
|
||||
|
||||
|
||||
@ -6,6 +6,31 @@ const successfulThreeDSTestCardDetails = {
|
||||
card_cvc: "123",
|
||||
};
|
||||
|
||||
const successfulNo3DSCardDetails = {
|
||||
card_number: "4242424242424242",
|
||||
card_exp_month: "01",
|
||||
card_exp_year: "50",
|
||||
card_holder_name: "joseph Doe",
|
||||
card_cvc: "123",
|
||||
};
|
||||
|
||||
const singleUseMandateData = {
|
||||
customer_acceptance: {
|
||||
acceptance_type: "offline",
|
||||
accepted_at: "1963-05-03T04:07:52.723Z",
|
||||
online: {
|
||||
ip_address: "125.0.0.1",
|
||||
user_agent: "amet irure esse",
|
||||
},
|
||||
},
|
||||
mandate_type: {
|
||||
single_use: {
|
||||
amount: 8000,
|
||||
currency: "EUR",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const connectorDetails = {
|
||||
card_pm: {
|
||||
PaymentIntent: {
|
||||
@ -206,6 +231,87 @@ export const connectorDetails = {
|
||||
},
|
||||
},
|
||||
},
|
||||
SaveCardConfirmAutoCaptureOffSession: {
|
||||
Request: {
|
||||
setup_future_usage: "off_session",
|
||||
},
|
||||
Response: {
|
||||
status: 200,
|
||||
trigger_skip: true,
|
||||
body: {
|
||||
status: "requires_customer_action",
|
||||
},
|
||||
},
|
||||
},
|
||||
PaymentIntentOffSession: {
|
||||
Request: {
|
||||
currency: "EUR",
|
||||
amount: 6500,
|
||||
authentication_type: "no_three_ds",
|
||||
customer_acceptance: null,
|
||||
setup_future_usage: "off_session",
|
||||
},
|
||||
Response: {
|
||||
status: 200,
|
||||
trigger_skip: true,
|
||||
body: {
|
||||
status: "requires_payment_method",
|
||||
setup_future_usage: "off_session",
|
||||
},
|
||||
},
|
||||
},
|
||||
ZeroAuthPaymentIntent: {
|
||||
Request: {
|
||||
amount: 0,
|
||||
setup_future_usage: "off_session",
|
||||
currency: "EUR",
|
||||
},
|
||||
Response: {
|
||||
status: 200,
|
||||
trigger_skip: true,
|
||||
body: {
|
||||
status: "requires_payment_method",
|
||||
setup_future_usage: "off_session",
|
||||
},
|
||||
},
|
||||
},
|
||||
ZeroAuthMandate: {
|
||||
Request: {
|
||||
payment_method: "card",
|
||||
payment_method_data: {
|
||||
card: successfulNo3DSCardDetails,
|
||||
},
|
||||
currency: "USD",
|
||||
mandate_data: singleUseMandateData,
|
||||
},
|
||||
Response: {
|
||||
status: 200,
|
||||
trigger_skip: true,
|
||||
body: {
|
||||
status: "succeeded",
|
||||
},
|
||||
},
|
||||
},
|
||||
ZeroAuthConfirmPayment: {
|
||||
Request: {
|
||||
payment_type: "setup_mandate",
|
||||
payment_method: "card",
|
||||
payment_method_type: "credit",
|
||||
payment_method_data: {
|
||||
card: successfulNo3DSCardDetails,
|
||||
},
|
||||
},
|
||||
Response: {
|
||||
status: 501,
|
||||
body: {
|
||||
error: {
|
||||
type: "invalid_request",
|
||||
message: "Setup Mandate flow for Novalnet is not implemented",
|
||||
code: "IR_00",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pm_list: {
|
||||
PmListResponse: {
|
||||
|
||||
Reference in New Issue
Block a user