feat(core): accept gateway credentials in the request body in payments and refunds (#766)

This commit is contained in:
Abhishek
2023-03-21 14:37:41 +05:30
committed by GitHub
parent d302b286b8
commit cb188f92a6
35 changed files with 748 additions and 130 deletions

View File

@ -9,6 +9,7 @@ impl PaymentIntents {
pub fn server(state: routes::AppState) -> Scope {
web::scope("/payment_intents")
.app_data(web::Data::new(state))
.service(payment_intents_retrieve_with_gateway_creds)
.service(payment_intents_create)
.service(payment_intents_retrieve)
.service(payment_intents_update)

View File

@ -75,6 +75,7 @@ pub async fn payment_intents_retrieve(
force_sync: true,
connector: None,
param: None,
merchant_connector_details: None,
};
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
@ -110,6 +111,64 @@ pub async fn payment_intents_retrieve(
.await
}
#[instrument(skip_all)]
#[post("/sync")]
pub async fn payment_intents_retrieve_with_gateway_creds(
state: web::Data<routes::AppState>,
qs_config: web::Data<serde_qs::Config>,
req: HttpRequest,
form_payload: web::Bytes,
) -> HttpResponse {
let json_payload: payment_types::PaymentRetrieveBodyWithCredentials = match qs_config
.deserialize_bytes(&form_payload)
.map_err(|err| report!(errors::StripeErrorCode::from(err)))
{
Ok(p) => p,
Err(err) => return api::log_and_return_error_response(err),
};
let payload = payment_types::PaymentsRetrieveRequest {
resource_id: payment_types::PaymentIdType::PaymentIntentId(
json_payload.payment_id.to_string(),
),
merchant_id: json_payload.merchant_id.clone(),
force_sync: json_payload.force_sync.unwrap_or(false),
merchant_connector_details: json_payload.merchant_connector_details.clone(),
..Default::default()
};
let (auth_type, _auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {
Ok(auth) => auth,
Err(err) => return api::log_and_return_error_response(report!(err)),
};
wrap::compatibility_api_wrap::<
_,
_,
_,
_,
_,
_,
types::StripePaymentIntentResponse,
errors::StripeErrorCode,
>(
state.get_ref(),
&req,
payload,
|state, merchant_account, req| {
payments::payments_core::<api_types::PSync, payment_types::PaymentsResponse, _, _, _>(
state,
merchant_account,
payments::PaymentStatus,
req,
api::AuthFlow::Merchant,
payments::CallConnectorAction::Trigger,
)
},
&*auth_type,
)
.await
}
#[instrument(skip_all)]
#[post("/{payment_id}")]
pub async fn payment_intents_update(

View File

@ -1,13 +1,14 @@
use api_models::{payments, refunds};
use api_models::payments;
use common_utils::{ext_traits::StringExt, pii as secret};
use error_stack::ResultExt;
use serde::{Deserialize, Serialize};
use crate::{
compatibility::stripe::refunds::types as stripe_refunds,
core::errors,
pii::{self, PeekInterface},
types::{
api::enums as api_enums,
api::{admin, enums as api_enums},
transformers::{ForeignFrom, ForeignInto},
},
};
@ -113,8 +114,10 @@ impl From<Shipping> for payments::Address {
}
}
}
#[derive(PartialEq, Eq, Deserialize, Clone)]
#[derive(Deserialize, Clone)]
pub struct StripePaymentIntentRequest {
pub id: Option<String>,
pub amount: Option<i64>, //amount in cents, hence passed as integer
pub connector: Option<Vec<api_enums::Connector>>,
pub currency: Option<String>,
@ -129,18 +132,19 @@ pub struct StripePaymentIntentRequest {
pub return_url: Option<url::Url>,
pub setup_future_usage: Option<api_enums::FutureUsage>,
pub shipping: Option<Shipping>,
pub billing_details: Option<StripeBillingDetails>,
pub statement_descriptor: Option<String>,
pub statement_descriptor_suffix: Option<String>,
pub metadata: Option<api_models::payments::Metadata>,
pub client_secret: Option<pii::Secret<String>>,
pub payment_method_options: Option<StripePaymentMethodOptions>,
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
}
impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
type Error = error_stack::Report<errors::ApiErrorResponse>;
fn try_from(item: StripePaymentIntentRequest) -> errors::RouterResult<Self> {
Ok(Self {
payment_id: item.id.map(payments::PaymentIdType::PaymentIntentId),
amount: item.amount.map(|amount| amount.into()),
connector: item.connector,
currency: item
@ -156,10 +160,6 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
confirm: item.confirm,
customer_id: item.customer,
email: item.receipt_email,
name: item
.billing_details
.as_ref()
.and_then(|b| b.name.as_ref().map(|x| masking::Secret::new(x.to_owned()))),
phone: item.shipping.as_ref().and_then(|s| s.phone.clone()),
description: item.description,
return_url: item.return_url,
@ -177,9 +177,8 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
.as_ref()
.map(|s| payments::Address::from(s.to_owned())),
billing: item
.billing_details
.as_ref()
.map(|b| payments::Address::from(b.to_owned())),
.payment_method_data
.and_then(|pmd| pmd.billing_details.map(payments::Address::from)),
statement_descriptor_name: item.statement_descriptor,
statement_descriptor_suffix: item.statement_descriptor_suffix,
metadata: item.metadata,
@ -191,6 +190,7 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
request_three_d_secure.foreign_into()
}),
merchant_connector_details: item.merchant_connector_details,
..Self::default()
})
}
@ -274,7 +274,7 @@ pub struct StripePaymentIntentResponse {
pub client_secret: Option<masking::Secret<String>>,
pub created: Option<i64>,
pub customer: Option<String>,
pub refunds: Option<Vec<refunds::RefundResponse>>,
pub refunds: Option<Vec<stripe_refunds::StripeRefundResponse>>,
pub mandate_id: Option<String>,
pub metadata: Option<secret::SecretSerdeValue>,
pub charges: Charges,
@ -283,7 +283,6 @@ pub struct StripePaymentIntentResponse {
pub mandate_data: Option<payments::MandateData>,
pub setup_future_usage: Option<api_models::enums::FutureUsage>,
pub off_session: Option<bool>,
pub authentication_type: Option<api_models::enums::AuthenticationType>,
pub next_action: Option<StripeNextAction>,
pub cancellation_reason: Option<String>,
@ -319,7 +318,9 @@ impl From<payments::PaymentsResponse> for StripePaymentIntentResponse {
currency: resp.currency.to_lowercase(),
customer: resp.customer_id,
description: resp.description,
refunds: resp.refunds,
refunds: resp
.refunds
.map(|a| a.into_iter().map(Into::into).collect()),
mandate_id: resp.mandate_id,
mandate_data: resp.mandate_data,
setup_future_usage: resp.setup_future_usage,

View File

@ -1,13 +1,14 @@
pub mod types;
use actix_web::{get, post, web, HttpRequest, HttpResponse};
use error_stack::report;
use router_env::{instrument, tracing};
use crate::{
compatibility::{stripe::errors, wrap},
core::refunds,
routes,
services::authentication as auth,
services::{api, authentication as auth},
types::api::refunds as refund_types,
};
@ -15,10 +16,18 @@ use crate::{
#[post("")]
pub async fn refund_create(
state: web::Data<routes::AppState>,
qs_config: web::Data<serde_qs::Config>,
req: HttpRequest,
form_payload: web::Form<types::StripeCreateRefundRequest>,
form_payload: web::Bytes,
) -> HttpResponse {
let payload = form_payload.into_inner();
let payload: types::StripeCreateRefundRequest = match qs_config
.deserialize_bytes(&form_payload)
.map_err(|err| report!(errors::StripeErrorCode::from(err)))
{
Ok(p) => p,
Err(err) => return api::log_and_return_error_response(err),
};
let create_refund_req: refund_types::RefundRequest = payload.into();
wrap::compatibility_api_wrap::<
@ -28,7 +37,7 @@ pub async fn refund_create(
_,
_,
_,
types::StripeCreateRefundResponse,
types::StripeRefundResponse,
errors::StripeErrorCode,
>(
state.get_ref(),
@ -47,7 +56,10 @@ pub async fn refund_retrieve(
req: HttpRequest,
path: web::Path<String>,
) -> HttpResponse {
let refund_id = path.into_inner();
let refund_request = refund_types::RefundsRetrieveRequest {
refund_id: path.into_inner(),
merchant_connector_details: None,
};
wrap::compatibility_api_wrap::<
_,
_,
@ -55,17 +67,17 @@ pub async fn refund_retrieve(
_,
_,
_,
types::StripeCreateRefundResponse,
types::StripeRefundResponse,
errors::StripeErrorCode,
>(
state.get_ref(),
&req,
refund_id,
|state, merchant_account, refund_id| {
refund_request,
|state, merchant_account, refund_request| {
refunds::refund_response_wrapper(
state,
merchant_account,
refund_id,
refund_request,
refunds::refund_retrieve_core,
)
},
@ -93,7 +105,7 @@ pub async fn refund_update(
_,
_,
_,
types::StripeCreateRefundResponse,
types::StripeRefundResponse,
errors::StripeErrorCode,
>(
state.get_ref(),

View File

@ -3,13 +3,16 @@ use std::{convert::From, default::Default};
use common_utils::pii;
use serde::{Deserialize, Serialize};
use crate::types::api::refunds;
use crate::types::api::{admin, refunds};
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct StripeCreateRefundRequest {
pub refund_id: Option<String>,
pub amount: Option<i64>,
pub payment_intent: String,
pub reason: Option<String>,
pub metadata: Option<pii::SecretSerdeValue>,
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
}
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
@ -18,7 +21,7 @@ pub struct StripeUpdateRefundRequest {
}
#[derive(Clone, Serialize, PartialEq, Eq)]
pub struct StripeCreateRefundResponse {
pub struct StripeRefundResponse {
pub id: String,
pub amount: i64,
pub currency: String,
@ -40,10 +43,13 @@ pub enum StripeRefundStatus {
impl From<StripeCreateRefundRequest> for refunds::RefundRequest {
fn from(req: StripeCreateRefundRequest) -> Self {
Self {
refund_id: req.refund_id,
amount: req.amount,
payment_id: req.payment_intent,
reason: req.reason,
refund_type: Some(refunds::RefundType::Instant),
metadata: req.metadata,
merchant_connector_details: req.merchant_connector_details,
..Default::default()
}
}
@ -69,7 +75,7 @@ impl From<refunds::RefundStatus> for StripeRefundStatus {
}
}
impl From<refunds::RefundResponse> for StripeCreateRefundResponse {
impl From<refunds::RefundResponse> for StripeRefundResponse {
fn from(res: refunds::RefundResponse) -> Self {
Self {
id: res.refund_id,

View File

@ -72,6 +72,7 @@ pub async fn setup_intents_retrieve(
force_sync: true,
connector: None,
param: None,
merchant_connector_details: None,
};
let (auth_type, auth_flow) = match auth::get_auth_type_and_flow(req.headers()) {

View File

@ -2,7 +2,7 @@ use api_models::webhooks::{self as api};
use serde::Serialize;
use super::{
payment_intents::types::StripePaymentIntentResponse, refunds::types::StripeCreateRefundResponse,
payment_intents::types::StripePaymentIntentResponse, refunds::types::StripeRefundResponse,
};
#[derive(Serialize)]
@ -19,7 +19,7 @@ impl api::OutgoingWebhookType for StripeOutgoingWebhook {}
#[serde(tag = "type", content = "object", rename_all = "snake_case")]
pub enum StripeWebhookObject {
PaymentIntent(StripePaymentIntentResponse),
Refund(StripeCreateRefundResponse),
Refund(StripeRefundResponse),
}
impl From<api::OutgoingWebhook> for StripeOutgoingWebhook {