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 reqwest::Url;
use serde::{Deserialize, Serialize};
@ -195,11 +192,11 @@ pub struct AdyenRedirectionResponse {
#[serde(rename_all = "camelCase")]
pub struct AdyenRedirectionAction {
payment_method_type: String,
url: String,
method: String,
url: Url,
method: services::Method,
#[serde(rename = "type")]
type_of_response: String,
data: Option<HashMap<String, String>>,
data: Option<std::collections::HashMap<String, String>>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
@ -755,26 +752,20 @@ pub fn get_redirection_response(
None
};
let redirection_url_response = Url::parse(&response.action.url)
.into_report()
.change_context(errors::ConnectorError::ResponseHandlingFailed)
.attach_printable("Failed to parse redirection url")?;
let form_field_for_redirection = match response.action.data {
Some(data) => data,
None => std::collections::HashMap::from_iter(
redirection_url_response
let form_fields = response.action.data.unwrap_or_else(|| {
std::collections::HashMap::from_iter(
response
.action
.url
.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 {
url: redirection_url_response.to_string(),
method: services::Method::from_str(&response.action.method)
.into_report()
.change_context(errors::ConnectorError::ResponseHandlingFailed)?,
form_fields: form_field_for_redirection,
endpoint: response.action.url.to_string(),
method: response.action.method,
form_fields,
};
// 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 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>
{
fn from(item: transformers::Foreign<(CheckoutPaymentStatus, Balances)>) -> Self {
fn from(item: transformers::Foreign<(CheckoutPaymentStatus, Option<Balances>)>) -> Self {
let (status, balances) = item.0;
match status {
CheckoutPaymentStatus::Authorized => {
if balances.available_to_capture == 0 {
if let Some(Balances {
available_to_capture: 0,
}) = balances
{
enums::AttemptStatus::Charged
} else {
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 {
href: String,
#[serde(rename = "href")]
redirection_url: Url,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
@ -206,7 +209,7 @@ pub struct PaymentsResponse {
status: CheckoutPaymentStatus,
#[serde(rename = "_links")]
links: Links,
balances: Balances,
balances: Option<Balances>,
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
@ -221,24 +224,10 @@ impl TryFrom<types::PaymentsResponseRouterData<PaymentsResponse>>
fn try_from(
item: types::PaymentsResponseRouterData<PaymentsResponse>,
) -> Result<Self, Self::Error> {
let redirection_url = item
.response
.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())),
),
let redirection_data = item.response.links.redirect.map(|href| {
services::RedirectForm::from((href.redirection_url, services::Method::Get))
});
Ok(Self {
status: enums::AttemptStatus::foreign_from((
item.response.status,
@ -262,23 +251,8 @@ impl TryFrom<types::PaymentsSyncResponseRouterData<PaymentsResponse>>
fn try_from(
item: types::PaymentsSyncResponseRouterData<PaymentsResponse>,
) -> Result<Self, Self::Error> {
let redirection_url = item
.response
.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())),
),
let redirection_data = item.response.links.redirect.map(|href| {
services::RedirectForm::from((href.redirection_url, services::Method::Get))
});
Ok(Self {

View File

@ -179,40 +179,39 @@ pub enum RapydPaymentStatus {
New,
}
impl From<transformers::Foreign<(RapydPaymentStatus, String)>>
impl From<transformers::Foreign<(RapydPaymentStatus, NextAction)>>
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;
match status {
RapydPaymentStatus::Closed => enums::AttemptStatus::Charged,
RapydPaymentStatus::Active => {
if next_action == "3d_verification" {
match (status, next_action) {
(RapydPaymentStatus::Closed, _) => enums::AttemptStatus::Charged,
(RapydPaymentStatus::Active, NextAction::ThreedsVerification) => {
enums::AttemptStatus::AuthenticationPending
} else if next_action == "pending_capture" {
}
(RapydPaymentStatus::Active, NextAction::PendingCapture) => {
enums::AttemptStatus::Authorized
} else {
enums::AttemptStatus::Pending
}
}
(
RapydPaymentStatus::CanceledByClientOrBank
| RapydPaymentStatus::Expired
| RapydPaymentStatus::ReversedByRapyd => enums::AttemptStatus::Voided,
RapydPaymentStatus::Error => enums::AttemptStatus::Failure,
RapydPaymentStatus::New => enums::AttemptStatus::Authorizing,
| RapydPaymentStatus::ReversedByRapyd,
_,
) => enums::AttemptStatus::Voided,
(RapydPaymentStatus::Error, _) => enums::AttemptStatus::Failure,
(RapydPaymentStatus::New, _) => enums::AttemptStatus::Authorizing,
}
.into()
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct RapydPaymentsResponse {
pub status: Status,
pub data: Option<ResponseData>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Status {
pub error_code: String,
pub status: Option<String>,
@ -221,13 +220,21 @@ pub struct Status {
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 id: String,
pub amount: i64,
pub status: RapydPaymentStatus,
pub next_action: String,
pub redirect_url: Option<String>,
pub next_action: NextAction,
pub redirect_url: Option<Url>,
pub original_amount: Option<i64>,
pub is_partial: Option<bool>,
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 status: Status,
pub data: Option<RefundResponseData>,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct RefundResponseData {
//Some field related to forign exchange and split payment can be added as and when implemented
pub id: String,
@ -389,25 +396,12 @@ impl<F, T>
}),
),
_ => {
let redirection_data =
match (data.next_action.as_str(), data.redirect_url.to_owned()) {
("3d_verification", Some(url)) => {
let url = Url::parse(&url).into_report().change_context(
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,
};
let redirection_data = data.redirect_url.as_ref().map(|redirect_url| {
services::RedirectForm::from((
redirect_url.to_owned(),
services::Method::Get,
))
});
(
attempt_status,
Ok(types::PaymentsResponseData::TransactionResponse {

View File

@ -501,22 +501,12 @@ impl<F, T>
fn try_from(
item: types::ResponseRouterData<F, PaymentIntentResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> {
let redirection_data = item.response.next_action.as_ref().map(
|StripeNextActionResponse::RedirectToUrl(response)| {
let mut base_url = response.url.clone();
base_url.set_query(None);
services::RedirectForm {
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 redirection_data =
item.response
.next_action
.map(|StripeNextActionResponse::RedirectToUrl(response)| {
services::RedirectForm::from((response.url, services::Method::Get))
});
let mandate_reference =
item.response
@ -556,22 +546,12 @@ impl<F, T>
fn try_from(
item: types::ResponseRouterData<F, SetupIntentResponse, T, types::PaymentsResponseData>,
) -> Result<Self, Self::Error> {
let redirection_data = item.response.next_action.as_ref().map(
|StripeNextActionResponse::RedirectToUrl(response)| {
let mut base_url = response.url.clone();
base_url.set_query(None);
services::RedirectForm {
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 redirection_data =
item.response
.next_action
.map(|StripeNextActionResponse::RedirectToUrl(response)| {
services::RedirectForm::from((response.url, services::Method::Get))
});
let mandate_reference =
item.response

View File

@ -363,15 +363,24 @@ impl From<&storage::PaymentAttempt> for ApplicationRedirectResponse {
#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct RedirectForm {
pub url: String,
pub endpoint: String,
pub method: Method,
pub form_fields: HashMap<String, String>,
}
impl RedirectForm {
pub fn new(url: String, method: Method, form_fields: HashMap<String, String>) -> Self {
impl From<(url::Url, Method)> for RedirectForm {
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 {
url,
endpoint: redirect_url.to_string(),
method,
form_fields,
}
@ -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..." }
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 {
input type="hidden" name=(field) value=(value);
}