Skip to content

Commit

Permalink
add zero auth mandates for novalnet
Browse files Browse the repository at this point in the history
  • Loading branch information
cookieg13 committed Nov 21, 2024
1 parent 26b00c5 commit df85bb8
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 10 deletions.
75 changes: 74 additions & 1 deletion crates/hyperswitch_connectors/src/connectors/novalnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -228,6 +228,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 {
Expand Down
220 changes: 211 additions & 9 deletions crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use hyperswitch_domain_models::{
},
types::{
PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData,
PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, SetupMandateRouterData,
},
};
use hyperswitch_interfaces::errors;
Expand All @@ -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 _,
},
};

Expand Down Expand Up @@ -118,11 +119,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>,
Expand Down Expand Up @@ -235,7 +243,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),
Expand Down Expand Up @@ -266,7 +274,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),
Expand All @@ -288,7 +296,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),
Expand Down Expand Up @@ -332,7 +340,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),
Expand Down Expand Up @@ -390,7 +398,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),
Expand Down Expand Up @@ -1381,3 +1389,197 @@ 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 = match item.test_mode {
Some(true) => 1,
Some(false) | None => 0,
};
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: 1,
};

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(1);

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"),
))?,
}
}
}
Loading

0 comments on commit df85bb8

Please sign in to comment.