refactor(redirection): From impl for redirection data for ease of use (#613)

This commit is contained in:
Narayan Bhat
2023-02-20 16:18:31 +05:30
committed by GitHub
parent 73d0538d09
commit e8255b4ae2
5 changed files with 101 additions and 153 deletions

View File

@ -1,6 +1,3 @@
use std::{collections::HashMap, str::FromStr};
use error_stack::{IntoReport, ResultExt};
use masking::PeekInterface; use masking::PeekInterface;
use reqwest::Url; use reqwest::Url;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -195,11 +192,11 @@ pub struct AdyenRedirectionResponse {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct AdyenRedirectionAction { pub struct AdyenRedirectionAction {
payment_method_type: String, payment_method_type: String,
url: String, url: Url,
method: String, method: services::Method,
#[serde(rename = "type")] #[serde(rename = "type")]
type_of_response: String, type_of_response: String,
data: Option<HashMap<String, String>>, data: Option<std::collections::HashMap<String, String>>,
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, Serialize, Deserialize)]
@ -755,26 +752,20 @@ pub fn get_redirection_response(
None None
}; };
let redirection_url_response = Url::parse(&response.action.url) let form_fields = response.action.data.unwrap_or_else(|| {
.into_report() std::collections::HashMap::from_iter(
.change_context(errors::ConnectorError::ResponseHandlingFailed) response
.attach_printable("Failed to parse redirection url")?; .action
.url
let form_field_for_redirection = match response.action.data {
Some(data) => data,
None => std::collections::HashMap::from_iter(
redirection_url_response
.query_pairs() .query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())), .map(|(key, value)| (key.to_string(), value.to_string())),
), )
}; });
let redirection_data = services::RedirectForm { let redirection_data = services::RedirectForm {
url: redirection_url_response.to_string(), endpoint: response.action.url.to_string(),
method: services::Method::from_str(&response.action.method) method: response.action.method,
.into_report() form_fields,
.change_context(errors::ConnectorError::ResponseHandlingFailed)?,
form_fields: form_field_for_redirection,
}; };
// We don't get connector transaction id for redirections in Adyen. // We don't get connector transaction id for redirections in Adyen.

View File

@ -1,4 +1,3 @@
use error_stack::{IntoReport, ResultExt};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -167,15 +166,18 @@ impl From<transformers::Foreign<(CheckoutPaymentStatus, Option<enums::CaptureMet
} }
} }
impl From<transformers::Foreign<(CheckoutPaymentStatus, Balances)>> impl From<transformers::Foreign<(CheckoutPaymentStatus, Option<Balances>)>>
for transformers::Foreign<enums::AttemptStatus> for transformers::Foreign<enums::AttemptStatus>
{ {
fn from(item: transformers::Foreign<(CheckoutPaymentStatus, Balances)>) -> Self { fn from(item: transformers::Foreign<(CheckoutPaymentStatus, Option<Balances>)>) -> Self {
let (status, balances) = item.0; let (status, balances) = item.0;
match status { match status {
CheckoutPaymentStatus::Authorized => { CheckoutPaymentStatus::Authorized => {
if balances.available_to_capture == 0 { if let Some(Balances {
available_to_capture: 0,
}) = balances
{
enums::AttemptStatus::Charged enums::AttemptStatus::Charged
} else { } else {
enums::AttemptStatus::Authorized enums::AttemptStatus::Authorized
@ -190,9 +192,10 @@ impl From<transformers::Foreign<(CheckoutPaymentStatus, Balances)>>
} }
} }
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Deserialize)]
pub struct Href { pub struct Href {
href: String, #[serde(rename = "href")]
redirection_url: Url,
} }
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
@ -206,7 +209,7 @@ pub struct PaymentsResponse {
status: CheckoutPaymentStatus, status: CheckoutPaymentStatus,
#[serde(rename = "_links")] #[serde(rename = "_links")]
links: Links, links: Links,
balances: Balances, balances: Option<Balances>,
} }
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
@ -221,24 +224,10 @@ impl TryFrom<types::PaymentsResponseRouterData<PaymentsResponse>>
fn try_from( fn try_from(
item: types::PaymentsResponseRouterData<PaymentsResponse>, item: types::PaymentsResponseRouterData<PaymentsResponse>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let redirection_url = item let redirection_data = item.response.links.redirect.map(|href| {
.response services::RedirectForm::from((href.redirection_url, services::Method::Get))
.links
.redirect
.map(|data| Url::parse(&data.href))
.transpose()
.into_report()
.change_context(errors::ConnectorError::ResponseHandlingFailed)
.attach_printable("Could not parse the redirection data")?;
let redirection_data = redirection_url.map(|url| services::RedirectForm {
url: url.to_string(),
method: services::Method::Get,
form_fields: std::collections::HashMap::from_iter(
url.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())),
),
}); });
Ok(Self { Ok(Self {
status: enums::AttemptStatus::foreign_from(( status: enums::AttemptStatus::foreign_from((
item.response.status, item.response.status,
@ -262,23 +251,8 @@ impl TryFrom<types::PaymentsSyncResponseRouterData<PaymentsResponse>>
fn try_from( fn try_from(
item: types::PaymentsSyncResponseRouterData<PaymentsResponse>, item: types::PaymentsSyncResponseRouterData<PaymentsResponse>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let redirection_url = item let redirection_data = item.response.links.redirect.map(|href| {
.response services::RedirectForm::from((href.redirection_url, services::Method::Get))
.links
.redirect
.map(|data| Url::parse(&data.href))
.transpose()
.into_report()
.change_context(errors::ConnectorError::ResponseHandlingFailed)
.attach_printable("Could not parse the redirection data")?;
let redirection_data = redirection_url.map(|url| services::RedirectForm {
url: url.to_string(),
method: services::Method::Get,
form_fields: std::collections::HashMap::from_iter(
url.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())),
),
}); });
Ok(Self { Ok(Self {

View File

@ -179,40 +179,39 @@ pub enum RapydPaymentStatus {
New, New,
} }
impl From<transformers::Foreign<(RapydPaymentStatus, String)>> impl From<transformers::Foreign<(RapydPaymentStatus, NextAction)>>
for transformers::Foreign<enums::AttemptStatus> for transformers::Foreign<enums::AttemptStatus>
{ {
fn from(item: transformers::Foreign<(RapydPaymentStatus, String)>) -> Self { fn from(item: transformers::Foreign<(RapydPaymentStatus, NextAction)>) -> Self {
let (status, next_action) = item.0; let (status, next_action) = item.0;
match status { match (status, next_action) {
RapydPaymentStatus::Closed => enums::AttemptStatus::Charged, (RapydPaymentStatus::Closed, _) => enums::AttemptStatus::Charged,
RapydPaymentStatus::Active => { (RapydPaymentStatus::Active, NextAction::ThreedsVerification) => {
if next_action == "3d_verification" { enums::AttemptStatus::AuthenticationPending
enums::AttemptStatus::AuthenticationPending
} else if next_action == "pending_capture" {
enums::AttemptStatus::Authorized
} else {
enums::AttemptStatus::Pending
}
} }
RapydPaymentStatus::CanceledByClientOrBank (RapydPaymentStatus::Active, NextAction::PendingCapture) => {
| RapydPaymentStatus::Expired enums::AttemptStatus::Authorized
| RapydPaymentStatus::ReversedByRapyd => enums::AttemptStatus::Voided, }
RapydPaymentStatus::Error => enums::AttemptStatus::Failure, (
RapydPaymentStatus::CanceledByClientOrBank
RapydPaymentStatus::New => enums::AttemptStatus::Authorizing, | RapydPaymentStatus::Expired
| RapydPaymentStatus::ReversedByRapyd,
_,
) => enums::AttemptStatus::Voided,
(RapydPaymentStatus::Error, _) => enums::AttemptStatus::Failure,
(RapydPaymentStatus::New, _) => enums::AttemptStatus::Authorizing,
} }
.into() .into()
} }
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct RapydPaymentsResponse { pub struct RapydPaymentsResponse {
pub status: Status, pub status: Status,
pub data: Option<ResponseData>, pub data: Option<ResponseData>,
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Status { pub struct Status {
pub error_code: String, pub error_code: String,
pub status: Option<String>, pub status: Option<String>,
@ -221,13 +220,21 @@ pub struct Status {
pub operation_id: Option<String>, pub operation_id: Option<String>,
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NextAction {
#[serde(rename = "3d_verification")]
ThreedsVerification,
#[serde(rename = "pending_capture")]
PendingCapture,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ResponseData { pub struct ResponseData {
pub id: String, pub id: String,
pub amount: i64, pub amount: i64,
pub status: RapydPaymentStatus, pub status: RapydPaymentStatus,
pub next_action: String, pub next_action: NextAction,
pub redirect_url: Option<String>, pub redirect_url: Option<Url>,
pub original_amount: Option<i64>, pub original_amount: Option<i64>,
pub is_partial: Option<bool>, pub is_partial: Option<bool>,
pub currency_code: Option<enums::Currency>, pub currency_code: Option<enums::Currency>,
@ -277,13 +284,13 @@ impl From<RefundStatus> for enums::RefundStatus {
} }
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RefundResponse { pub struct RefundResponse {
pub status: Status, pub status: Status,
pub data: Option<RefundResponseData>, pub data: Option<RefundResponseData>,
} }
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct RefundResponseData { pub struct RefundResponseData {
//Some field related to forign exchange and split payment can be added as and when implemented //Some field related to forign exchange and split payment can be added as and when implemented
pub id: String, pub id: String,
@ -389,25 +396,12 @@ impl<F, T>
}), }),
), ),
_ => { _ => {
let redirection_data = let redirection_data = data.redirect_url.as_ref().map(|redirect_url| {
match (data.next_action.as_str(), data.redirect_url.to_owned()) { services::RedirectForm::from((
("3d_verification", Some(url)) => { redirect_url.to_owned(),
let url = Url::parse(&url).into_report().change_context( services::Method::Get,
errors::ConnectorError::ResponseHandlingFailed, ))
)?; });
let mut base_url = url.clone();
base_url.set_query(None);
Some(services::RedirectForm {
url: base_url.to_string(),
method: services::Method::Get,
form_fields: std::collections::HashMap::from_iter(
url.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())),
),
})
}
(_, _) => None,
};
( (
attempt_status, attempt_status,
Ok(types::PaymentsResponseData::TransactionResponse { Ok(types::PaymentsResponseData::TransactionResponse {

View File

@ -501,22 +501,12 @@ impl<F, T>
fn try_from( fn try_from(
item: types::ResponseRouterData<F, PaymentIntentResponse, T, types::PaymentsResponseData>, item: types::ResponseRouterData<F, PaymentIntentResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let redirection_data = item.response.next_action.as_ref().map( let redirection_data =
|StripeNextActionResponse::RedirectToUrl(response)| { item.response
let mut base_url = response.url.clone(); .next_action
base_url.set_query(None); .map(|StripeNextActionResponse::RedirectToUrl(response)| {
services::RedirectForm { services::RedirectForm::from((response.url, services::Method::Get))
url: base_url.to_string(), });
method: services::Method::Get,
form_fields: std::collections::HashMap::from_iter(
response
.url
.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())),
),
}
},
);
let mandate_reference = let mandate_reference =
item.response item.response
@ -556,22 +546,12 @@ impl<F, T>
fn try_from( fn try_from(
item: types::ResponseRouterData<F, SetupIntentResponse, T, types::PaymentsResponseData>, item: types::ResponseRouterData<F, SetupIntentResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let redirection_data = item.response.next_action.as_ref().map( let redirection_data =
|StripeNextActionResponse::RedirectToUrl(response)| { item.response
let mut base_url = response.url.clone(); .next_action
base_url.set_query(None); .map(|StripeNextActionResponse::RedirectToUrl(response)| {
services::RedirectForm { services::RedirectForm::from((response.url, services::Method::Get))
url: base_url.to_string(), });
method: services::Method::Get,
form_fields: std::collections::HashMap::from_iter(
response
.url
.query_pairs()
.map(|(k, v)| (k.to_string(), v.to_string())),
),
}
},
);
let mandate_reference = let mandate_reference =
item.response item.response

View File

@ -363,15 +363,24 @@ impl From<&storage::PaymentAttempt> for ApplicationRedirectResponse {
#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct RedirectForm { pub struct RedirectForm {
pub url: String, pub endpoint: String,
pub method: Method, pub method: Method,
pub form_fields: HashMap<String, String>, pub form_fields: HashMap<String, String>,
} }
impl RedirectForm { impl From<(url::Url, Method)> for RedirectForm {
pub fn new(url: String, method: Method, form_fields: HashMap<String, String>) -> Self { fn from((mut redirect_url, method): (url::Url, Method)) -> Self {
let form_fields = std::collections::HashMap::from_iter(
redirect_url
.query_pairs()
.map(|(key, value)| (key.to_string(), value.to_string())),
);
// Do not include query params in the endpoint
redirect_url.set_query(None);
Self { Self {
url, endpoint: redirect_url.to_string(),
method, method,
form_fields, form_fields,
} }
@ -574,18 +583,18 @@ pub fn build_redirection_form(form: &RedirectForm) -> maud::Markup {
head { head {
style { style {
r##" r##"
"## "##
} }
(PreEscaped(r##" (PreEscaped(r##"
<style> <style>
#loader1 { #loader1 {
width: 500px, width: 500px,
} }
@media max-width: 600px { @media max-width: 600px {
#loader1 { #loader1 {
width: 200px width: 200px
} }
} }
</style> </style>
"##)) "##))
@ -612,7 +621,7 @@ pub fn build_redirection_form(form: &RedirectForm) -> maud::Markup {
h3 style="text-align: center;" { "Please wait while we process your payment..." } h3 style="text-align: center;" { "Please wait while we process your payment..." }
form action=(PreEscaped(&form.url)) method=(form.method.to_string()) #payment_form { form action=(PreEscaped(&form.endpoint)) method=(form.method.to_string()) #payment_form {
@for (field, value) in &form.form_fields { @for (field, value) in &form.form_fields {
input type="hidden" name=(field) value=(value); input type="hidden" name=(field) value=(value);
} }