Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(compatibility): add additional fields to stripe payment and refund response types #618

Merged
merged 9 commits into from
Feb 24, 2023
98 changes: 1 addition & 97 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::num::NonZeroI64;

use common_utils::{errors, ext_traits::Encode, pii};
use common_utils::pii;
use masking::{PeekInterface, Secret};
use router_derive::Setter;
use time::PrimitiveDateTime;
Expand Down Expand Up @@ -797,46 +797,6 @@ impl From<&VerifyRequest> for MandateValidationFields {
}
}

impl TryFrom<PaymentsRequest> for PaymentsResponse {
type Error = error_stack::Report<errors::ParsingError>;
fn try_from(item: PaymentsRequest) -> Result<Self, Self::Error> {
let payment_id = match item.payment_id {
Some(PaymentIdType::PaymentIntentId(id)) => Some(id),
_ => None,
};
let metadata = item
.metadata
.as_ref()
.map(Encode::<Metadata>::encode_to_value)
.transpose()?;
Ok(Self {
payment_id,
merchant_id: item.merchant_id,
setup_future_usage: item.setup_future_usage,
off_session: item.off_session,
shipping: item.shipping,
billing: item.billing,
metadata,
capture_method: item.capture_method,
payment_method: item.payment_method,
capture_on: item.capture_on,
payment_method_data: item
.payment_method_data
.map(PaymentMethodDataResponse::from),
email: item.email,
name: item.name,
phone: item.phone,
payment_token: item.payment_token,
return_url: item.return_url,
authentication_type: item.authentication_type,
statement_descriptor_name: item.statement_descriptor_name,
statement_descriptor_suffix: item.statement_descriptor_suffix,
mandate_data: item.mandate_data,
..Default::default()
})
}
}

impl From<VerifyRequest> for VerifyResponse {
fn from(item: VerifyRequest) -> Self {
Self {
Expand All @@ -855,25 +815,6 @@ impl From<VerifyRequest> for VerifyResponse {
}
}

impl From<PaymentsStartRequest> for PaymentsResponse {
fn from(item: PaymentsStartRequest) -> Self {
Self {
payment_id: Some(item.payment_id),
merchant_id: Some(item.merchant_id),
..Default::default()
}
}
}

impl From<PaymentsSessionRequest> for PaymentsResponse {
fn from(item: PaymentsSessionRequest) -> Self {
Self {
payment_id: Some(item.payment_id),
..Default::default()
}
}
}

impl From<PaymentsSessionRequest> for PaymentsSessionResponse {
fn from(item: PaymentsSessionRequest) -> Self {
let client_secret: Secret<String, pii::ClientSecret> = Secret::new(item.client_secret);
Expand All @@ -895,43 +836,6 @@ impl From<PaymentsStartRequest> for PaymentsRequest {
}
}

impl From<PaymentsRetrieveRequest> for PaymentsResponse {
// After removing the request from the payments_to_payments_response this will no longer be needed
fn from(item: PaymentsRetrieveRequest) -> Self {
let payment_id = match item.resource_id {
PaymentIdType::PaymentIntentId(id) => Some(id),
_ => None,
};

Self {
payment_id,
merchant_id: item.merchant_id,
..Default::default()
}
}
}

impl From<PaymentsCancelRequest> for PaymentsResponse {
fn from(item: PaymentsCancelRequest) -> Self {
Self {
payment_id: Some(item.payment_id),
cancellation_reason: item.cancellation_reason,
..Default::default()
}
}
}

impl From<PaymentsCaptureRequest> for PaymentsResponse {
// After removing the request from the payments_to_payments_response this will no longer be needed
fn from(item: PaymentsCaptureRequest) -> Self {
Self {
payment_id: item.payment_id,
amount_received: item.amount_to_capture,
..Self::default()
}
}
}

impl From<Card> for CardResponse {
fn from(card: Card) -> Self {
let card_number_length = card.card_number.peek().clone().len();
Expand Down
88 changes: 79 additions & 9 deletions crates/router/src/compatibility/stripe/payment_intents/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,40 +265,110 @@ pub struct StripeCaptureRequest {
#[derive(Default, Eq, PartialEq, Serialize)]
pub struct StripePaymentIntentResponse {
pub id: Option<String>,
pub object: String,
pub object: &'static str,
pub amount: i64,
pub amount_received: Option<i64>,
pub amount_capturable: Option<i64>,
pub currency: String,
pub status: StripePaymentStatus,
pub client_secret: Option<masking::Secret<String>>,
#[serde(with = "common_utils::custom_serde::iso8601::option")]
pub created: Option<time::PrimitiveDateTime>,
pub created: Option<i64>,
pub customer: Option<String>,
pub refunds: Option<Vec<refunds::RefundResponse>>,
pub mandate_id: Option<String>,
pub metadata: Option<Value>,
pub charges: Charges,
pub connector: Option<String>,
pub description: Option<String>,
pub mandate_data: Option<payments::MandateData>,
pub setup_future_usage: Option<api_models::enums::FutureUsage>,
pub off_session: Option<bool>,
pub return_url: Option<String>,
pub authentication_type: Option<api_models::enums::AuthenticationType>,
pub next_action: Option<payments::NextAction>,
pub cancellation_reason: Option<String>,
pub payment_method: Option<api_models::enums::PaymentMethodType>,
pub payment_method_data: Option<payments::PaymentMethodDataResponse>,
pub shipping: Option<payments::Address>,
pub billing: Option<payments::Address>,
#[serde(with = "common_utils::custom_serde::iso8601::option")]
pub capture_on: Option<time::PrimitiveDateTime>,
Abhicodes-crypto marked this conversation as resolved.
Show resolved Hide resolved
pub payment_token: Option<String>,
pub email: Option<masking::Secret<String, common_utils::pii::Email>>,
pub phone: Option<masking::Secret<String>>,
pub error_code: Option<String>,
pub error_message: Option<String>,
pub statement_descriptor_suffix: Option<String>,
pub statement_descriptor_name: Option<String>,
pub capture_method: Option<api_models::enums::CaptureMethod>,
pub name: Option<masking::Secret<String>>,
}

impl From<payments::PaymentsResponse> for StripePaymentIntentResponse {
fn from(resp: payments::PaymentsResponse) -> Self {
Self {
object: "payment_intent".to_owned(),
object: "payment_intent",
id: resp.payment_id,
status: StripePaymentStatus::from(resp.status),
amount: resp.amount,
amount_received: resp.amount_received,
amount_capturable: resp.amount_capturable,
currency: resp.currency.to_lowercase(),
status: StripePaymentStatus::from(resp.status),
amount_received: resp.amount_received,
connector: resp.connector,
client_secret: resp.client_secret,
created: resp.created,
created: resp.created.map(|t| t.assume_utc().unix_timestamp()),
currency: resp.currency.to_lowercase(),
customer: resp.customer_id,
id: resp.payment_id,
description: resp.description,
refunds: resp.refunds,
mandate_id: resp.mandate_id,
mandate_data: resp.mandate_data,
setup_future_usage: resp.setup_future_usage,
off_session: resp.off_session,
capture_on: resp.capture_on,
capture_method: resp.capture_method,
payment_method: resp.payment_method,
payment_method_data: resp.payment_method_data,
payment_token: resp.payment_token,
shipping: resp.shipping,
billing: resp.billing,
email: resp.email,
name: resp.name,
phone: resp.phone,
return_url: resp.return_url,
authentication_type: resp.authentication_type,
statement_descriptor_name: resp.statement_descriptor_name,
statement_descriptor_suffix: resp.statement_descriptor_suffix,
next_action: resp.next_action,
cancellation_reason: resp.cancellation_reason,
error_code: resp.error_code,
error_message: resp.error_message,
metadata: resp.metadata,
charges: Charges::new(),
}
}
}

#[derive(Default, Eq, PartialEq, Serialize)]
pub struct Charges {
object: &'static str,
data: Vec<String>,
has_more: bool,
total_count: i32,
url: String,
}

impl Charges {
fn new() -> Self {
Self {
object: "list",
data: vec![],
has_more: false,
total_count: 0,
url: "http://placeholder".to_string(),
}
}
}

#[derive(Clone, Debug, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct StripePaymentListConstraints {
Expand Down
16 changes: 11 additions & 5 deletions crates/router/src/compatibility/stripe/refunds/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{convert::From, default::Default};

use serde::{Deserialize, Serialize};

use crate::types::api::refunds;
use crate::{core::errors, types::api::refunds};

#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct StripeCreateRefundRequest {
Expand All @@ -23,6 +23,8 @@ pub struct StripeCreateRefundResponse {
pub currency: String,
pub payment_intent: String,
pub status: StripeRefundStatus,
pub created: Option<i64>,
pub metadata: serde_json::Value,
}

#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
Expand All @@ -40,6 +42,7 @@ impl From<StripeCreateRefundRequest> for refunds::RefundRequest {
amount: req.amount,
payment_id: req.payment_intent,
reason: req.reason,
refund_type: Some(refunds::RefundType::Instant),
..Default::default()
}
}
Expand All @@ -65,14 +68,17 @@ impl From<refunds::RefundStatus> for StripeRefundStatus {
}
}

impl From<refunds::RefundResponse> for StripeCreateRefundResponse {
fn from(res: refunds::RefundResponse) -> Self {
Self {
impl TryFrom<refunds::RefundResponse> for StripeCreateRefundResponse {
type Error = error_stack::Report<errors::ApiErrorResponse>;
fn try_from(res: refunds::RefundResponse) -> Result<Self, Self::Error> {
Ok(Self {
id: res.refund_id,
amount: res.amount,
currency: res.currency.to_ascii_lowercase(),
payment_intent: res.payment_id,
status: res.status.into(),
}
created: res.created_at.map(|t| t.assume_utc().unix_timestamp()),
metadata: res.metadata.unwrap_or(serde_json::json!({})),
})
}
}
2 changes: 1 addition & 1 deletion crates/router/src/compatibility/wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ where
F: Fn(&'b A, U, T) -> Fut,
Fut: Future<Output = RouterResult<api::ApplicationResponse<Q>>>,
Q: Serialize + std::fmt::Debug + 'a,
S: From<Q> + Serialize,
S: TryFrom<Q> + Serialize,
E: Serialize + error_stack::Context + actix_web::ResponseError + Clone,
errors::ApiErrorResponse: ErrorSwitch<E>,
T: std::fmt::Debug,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/core/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ where
FData: Send,
Op: Operation<F, Req> + Send + Sync + Clone,
Req: Debug,
Res: transformers::ToResponse<Req, PaymentData<F>, Op> + TryFrom<Req>,
Res: transformers::ToResponse<Req, PaymentData<F>, Op>,
// To create connector flow specific interface data
PaymentData<F>: ConstructFlowSpecificData<F, FData, types::PaymentsResponseData>,
types::RouterData<F, FData, types::PaymentsResponseData>: Feature<F, FData>,
Expand Down
14 changes: 5 additions & 9 deletions crates/router/src/core/payments/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ where

pub trait ToResponse<Req, D, Op>
where
Self: TryFrom<Req>,
Self: Sized,
Op: Debug,
{
fn generate_response(
Expand All @@ -121,7 +121,6 @@ where

impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::PaymentsResponse
where
Self: TryFrom<Req>,
F: Clone,
Op: Debug,
{
Expand Down Expand Up @@ -236,7 +235,6 @@ pub fn payments_to_payments_response<R, Op>(
operation: Op,
) -> RouterResponse<api::PaymentsResponse>
where
api::PaymentsResponse: TryFrom<R>,
Op: Debug,
{
let currency = payment_attempt
Expand All @@ -252,16 +250,13 @@ where
};

Ok(match payment_request {
Some(request) => {
Some(_request) => {
if payments::is_start_pay(&operation) && redirection_data.is_some() {
let redirection_data = redirection_data.get_required_value("redirection_data")?;
let form: RedirectForm = serde_json::from_value(redirection_data)
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
services::ApplicationResponse::Form(form)
} else {
let mut response: api::PaymentsResponse = request
.try_into()
.map_err(|_| errors::ApiErrorResponse::InternalServerError)?;
let mut next_action_response = None;
if payment_intent.status == enums::IntentStatus::RequiresCustomerAction {
next_action_response = Some(api::NextAction {
Expand All @@ -273,7 +268,7 @@ where
)),
})
}

let mut response: api::PaymentsResponse = Default::default();
services::ApplicationResponse::Json(
response
.set_payment_id(Some(payment_attempt.payment_id))
Expand Down Expand Up @@ -320,7 +315,6 @@ where
.set_error_code(payment_attempt.error_code)
.set_shipping(address.shipping)
.set_billing(address.billing)
.to_owned()
.set_next_action(next_action_response)
.set_return_url(payment_intent.return_url)
.set_cancellation_reason(payment_attempt.cancellation_reason)
Expand All @@ -341,6 +335,7 @@ where
.capture_method
.map(ForeignInto::foreign_into),
)
.set_metadata(payment_intent.metadata)
.to_owned(),
)
}
Expand Down Expand Up @@ -381,6 +376,7 @@ where
billing: address.billing,
cancellation_reason: payment_attempt.cancellation_reason,
payment_token: payment_attempt.payment_token,
metadata: payment_intent.metadata,
..Default::default()
}),
})
Expand Down