mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
refactor(redirection): From impl for redirection data for ease of use (#613)
This commit is contained in:
@ -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.
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user