mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 11:06:50 +08:00
feat(core): add sessions api endpoint (#104)
This commit is contained in:
@ -99,6 +99,11 @@ pub struct Database {
|
||||
pub pool_size: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SupportedConnectors {
|
||||
pub wallets: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Connectors {
|
||||
pub aci: ConnectorParams,
|
||||
@ -107,6 +112,7 @@ pub struct Connectors {
|
||||
pub checkout: ConnectorParams,
|
||||
pub stripe: ConnectorParams,
|
||||
pub braintree: ConnectorParams,
|
||||
pub supported: SupportedConnectors,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
|
||||
@ -11,7 +11,7 @@ use time;
|
||||
|
||||
pub use self::operations::{
|
||||
PaymentCancel, PaymentCapture, PaymentConfirm, PaymentCreate, PaymentMethodValidate,
|
||||
PaymentResponse, PaymentStatus, PaymentUpdate,
|
||||
PaymentResponse, PaymentSession, PaymentStatus, PaymentUpdate,
|
||||
};
|
||||
use self::{
|
||||
flows::{ConstructFlowSpecificData, Feature},
|
||||
@ -61,9 +61,6 @@ where
|
||||
// To perform router related operation for PaymentResponse
|
||||
PaymentResponse: Operation<F, FData>,
|
||||
{
|
||||
let connector = api::ConnectorData::construct(&state.conf.connectors, &merchant_account)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
|
||||
let operation: BoxedOperation<F, Req> = Box::new(operation);
|
||||
|
||||
let (operation, validate_result) = operation
|
||||
@ -78,7 +75,6 @@ where
|
||||
state,
|
||||
&validate_result.payment_id,
|
||||
validate_result.merchant_id,
|
||||
connector.connector_name,
|
||||
&req,
|
||||
validate_result.mandate_type,
|
||||
validate_result.storage_scheme,
|
||||
@ -110,6 +106,16 @@ where
|
||||
.await?;
|
||||
payment_data.payment_method_data = payment_method_data;
|
||||
|
||||
let connector_details = operation
|
||||
.to_domain()?
|
||||
.get_connector(&merchant_account, state)
|
||||
.await?;
|
||||
|
||||
if let api::ConnectorCallType::Single(ref connector) = connector_details {
|
||||
payment_data.payment_attempt.connector =
|
||||
Some(connector.connector_name.to_owned().to_string());
|
||||
}
|
||||
|
||||
let (operation, mut payment_data) = operation
|
||||
.to_update_tracker()?
|
||||
.update_trackers(
|
||||
@ -127,17 +133,32 @@ where
|
||||
.await?;
|
||||
|
||||
if should_call_connector(&operation, &payment_data) {
|
||||
payment_data = call_connector_service(
|
||||
state,
|
||||
&merchant_account,
|
||||
&validate_result.payment_id,
|
||||
connector,
|
||||
&operation,
|
||||
payment_data,
|
||||
&customer,
|
||||
call_connector_action,
|
||||
)
|
||||
.await?;
|
||||
payment_data = match connector_details {
|
||||
api::ConnectorCallType::Single(connector) => {
|
||||
call_connector_service(
|
||||
state,
|
||||
&merchant_account,
|
||||
&validate_result.payment_id,
|
||||
connector,
|
||||
&operation,
|
||||
payment_data,
|
||||
&customer,
|
||||
call_connector_action,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
api::ConnectorCallType::Multiple(connectors) => {
|
||||
call_multiple_connectors_service(
|
||||
state,
|
||||
&merchant_account,
|
||||
connectors,
|
||||
&operation,
|
||||
payment_data,
|
||||
&customer,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((payment_data, req, customer))
|
||||
}
|
||||
|
||||
@ -21,13 +21,14 @@ use crate::{
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums},
|
||||
storage::{self, enums as storage_enums, ephemeral_key},
|
||||
},
|
||||
utils::{
|
||||
self,
|
||||
crypto::{self, SignMessage},
|
||||
OptionExt,
|
||||
OptionExt, ValueExt,
|
||||
},
|
||||
};
|
||||
|
||||
@ -313,13 +314,14 @@ pub fn create_startpay_url(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_redirect_url(server: &Server, payment_attempt: &storage::PaymentAttempt) -> String {
|
||||
pub fn create_redirect_url(
|
||||
server: &Server,
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
connector_name: &String,
|
||||
) -> String {
|
||||
format!(
|
||||
"{}/payments/{}/{}/response/{}",
|
||||
server.base_url,
|
||||
payment_attempt.payment_id,
|
||||
payment_attempt.merchant_id,
|
||||
payment_attempt.connector
|
||||
server.base_url, payment_attempt.payment_id, payment_attempt.merchant_id, connector_name
|
||||
)
|
||||
}
|
||||
fn validate_recurring_mandate(req: api::MandateValidationFields) -> RouterResult<()> {
|
||||
@ -522,6 +524,44 @@ pub async fn get_customer_from_details(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_connector_default(
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
let connectors = &state.conf.connectors;
|
||||
let vec_val: Vec<serde_json::Value> = merchant_account
|
||||
.custom_routing_rules
|
||||
.clone()
|
||||
.parse_value("CustomRoutingRulesVec")
|
||||
.change_context(errors::ConnectorError::RoutingRulesParsingError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let custom_routing_rules: api::CustomRoutingRules = vec_val[0]
|
||||
.clone()
|
||||
.parse_value("CustomRoutingRules")
|
||||
.change_context(errors::ConnectorError::RoutingRulesParsingError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let connector_names = custom_routing_rules
|
||||
.connectors_pecking_order
|
||||
.unwrap_or_else(|| vec!["stripe".to_string()]);
|
||||
|
||||
//use routing rules if configured by merchant else query MCA as per PM
|
||||
let connector_list: types::ConnectorsList = types::ConnectorsList {
|
||||
connectors: connector_names,
|
||||
};
|
||||
|
||||
let connector_name = connector_list
|
||||
.connectors
|
||||
.first()
|
||||
.get_required_value("connectors")
|
||||
.change_context(errors::ConnectorError::FailedToObtainPreferredConnector)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?
|
||||
.as_str();
|
||||
|
||||
let connector_data = api::ConnectorData::get_connector_by_name(connectors, connector_name)?;
|
||||
|
||||
Ok(api::ConnectorCallType::Single(connector_data))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn create_customer_if_not_exist<'a, F: Clone, R>(
|
||||
operation: BoxedOperation<'a, F, R>,
|
||||
|
||||
@ -92,7 +92,6 @@ pub trait GetTracker<F, D, R>: Send {
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
request: &R,
|
||||
mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
@ -129,6 +128,12 @@ pub trait Domain<F: Clone, R>: Send + Sync {
|
||||
) -> CustomResult<(), errors::ApiErrorResponse> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -224,9 +229,14 @@ where
|
||||
if helpers::check_if_operation_confirm(self) {
|
||||
metrics::TASKS_ADDED_COUNT.add(&metrics::CONTEXT, 1, &[]); // Metrics
|
||||
|
||||
let connector_name = payment_attempt
|
||||
.connector
|
||||
.clone()
|
||||
.ok_or(errors::ApiErrorResponse::InternalServerError)?;
|
||||
|
||||
let schedule_time = payment_sync::get_sync_process_schedule_time(
|
||||
&*state.store,
|
||||
&payment_attempt.connector,
|
||||
&connector_name,
|
||||
&payment_attempt.merchant_id,
|
||||
0,
|
||||
)
|
||||
@ -245,6 +255,14 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -278,6 +296,14 @@ where
|
||||
))
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn make_pm_data<'a>(
|
||||
&'a self,
|
||||
@ -351,6 +377,14 @@ where
|
||||
)> {
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -400,4 +434,12 @@ where
|
||||
)> {
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ use crate::{
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums, Customer},
|
||||
Connector,
|
||||
},
|
||||
utils::OptionExt,
|
||||
};
|
||||
@ -33,7 +32,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &api::PaymentsCancelRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
|
||||
@ -16,7 +16,6 @@ use crate::{
|
||||
api,
|
||||
api::PaymentsCaptureRequest,
|
||||
storage::{self, enums},
|
||||
Connector,
|
||||
},
|
||||
utils::OptionExt,
|
||||
};
|
||||
@ -35,7 +34,6 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &PaymentsCaptureRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
|
||||
@ -17,7 +17,6 @@ use crate::{
|
||||
types::{
|
||||
self, api,
|
||||
storage::{self, enums},
|
||||
Connector,
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
@ -34,7 +33,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &api::PaymentsRequest,
|
||||
mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
@ -194,6 +192,8 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
||||
),
|
||||
};
|
||||
|
||||
let connector = payment_data.payment_attempt.connector.clone();
|
||||
|
||||
payment_data.payment_attempt = db
|
||||
.update_payment_attempt(
|
||||
payment_data.payment_attempt,
|
||||
@ -201,6 +201,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
|
||||
status: attempt_status,
|
||||
payment_method,
|
||||
browser_info,
|
||||
connector,
|
||||
},
|
||||
storage_scheme,
|
||||
)
|
||||
|
||||
@ -37,7 +37,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
request: &api::PaymentsRequest,
|
||||
mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
@ -84,7 +83,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
Self::make_payment_attempt(
|
||||
&payment_id,
|
||||
merchant_id,
|
||||
connector,
|
||||
money,
|
||||
payment_method_type,
|
||||
request,
|
||||
@ -117,7 +115,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
Self::make_payment_intent(
|
||||
&payment_id,
|
||||
merchant_id,
|
||||
&connector.to_string(),
|
||||
money,
|
||||
request,
|
||||
shipping_address.clone().map(|x| x.address_id),
|
||||
@ -314,7 +311,6 @@ impl PaymentCreate {
|
||||
fn make_payment_attempt(
|
||||
payment_id: &str,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
money: (api::Amount, enums::Currency),
|
||||
payment_method: Option<enums::PaymentMethodType>,
|
||||
request: &api::PaymentsRequest,
|
||||
@ -331,7 +327,6 @@ impl PaymentCreate {
|
||||
status,
|
||||
amount: amount.into(),
|
||||
currency,
|
||||
connector: connector.to_string(),
|
||||
payment_method,
|
||||
capture_method: request.capture_method.map(Into::into),
|
||||
capture_on: request.capture_on,
|
||||
@ -349,7 +344,6 @@ impl PaymentCreate {
|
||||
fn make_payment_intent(
|
||||
payment_id: &str,
|
||||
merchant_id: &str,
|
||||
connector_id: &str,
|
||||
money: (api::Amount, enums::Currency),
|
||||
request: &api::PaymentsRequest,
|
||||
shipping_address_id: Option<String>,
|
||||
@ -367,7 +361,6 @@ impl PaymentCreate {
|
||||
status,
|
||||
amount: amount.into(),
|
||||
currency,
|
||||
connector_id: Some(connector_id.to_string()),
|
||||
description: request.description.clone(),
|
||||
created_at,
|
||||
modified_at,
|
||||
|
||||
@ -66,7 +66,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
request: &api::VerifyRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
@ -87,7 +86,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
|
||||
Self::make_payment_attempt(
|
||||
&payment_id,
|
||||
merchant_id,
|
||||
connector,
|
||||
request.payment_method,
|
||||
request,
|
||||
),
|
||||
@ -103,7 +101,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
|
||||
|
||||
payment_intent = match db
|
||||
.insert_payment_intent(
|
||||
Self::make_payment_intent(&payment_id, merchant_id, connector, request),
|
||||
Self::make_payment_intent(&payment_id, merchant_id, request),
|
||||
storage_scheme,
|
||||
)
|
||||
.await
|
||||
@ -256,6 +254,14 @@ where
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
}
|
||||
|
||||
impl PaymentMethodValidate {
|
||||
@ -263,7 +269,6 @@ impl PaymentMethodValidate {
|
||||
fn make_payment_attempt(
|
||||
payment_id: &str,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
payment_method: Option<api_enums::PaymentMethodType>,
|
||||
_request: &api::VerifyRequest,
|
||||
) -> storage::PaymentAttemptNew {
|
||||
@ -278,7 +283,7 @@ impl PaymentMethodValidate {
|
||||
// Amount & Currency will be zero in this case
|
||||
amount: 0,
|
||||
currency: Default::default(),
|
||||
connector: connector.to_string(),
|
||||
connector: None,
|
||||
payment_method: payment_method.map(Into::into),
|
||||
confirm: true,
|
||||
created_at,
|
||||
@ -291,7 +296,6 @@ impl PaymentMethodValidate {
|
||||
fn make_payment_intent(
|
||||
payment_id: &str,
|
||||
merchant_id: &str,
|
||||
connector: types::Connector,
|
||||
request: &api::VerifyRequest,
|
||||
) -> storage::PaymentIntentNew {
|
||||
let created_at @ modified_at @ last_synced = Some(date_time::now());
|
||||
@ -305,7 +309,7 @@ impl PaymentMethodValidate {
|
||||
status,
|
||||
amount: 0,
|
||||
currency: Default::default(),
|
||||
connector_id: Some(connector.to_string()),
|
||||
connector_id: None,
|
||||
created_at,
|
||||
modified_at,
|
||||
last_synced,
|
||||
|
||||
@ -20,7 +20,7 @@ use crate::{
|
||||
#[derive(Debug, Clone, Copy, router_derive::PaymentOperation)]
|
||||
#[operation(
|
||||
ops = "post_tracker",
|
||||
flow = "syncdata,authorizedata,canceldata,capturedata,verifydata"
|
||||
flow = "syncdata,authorizedata,canceldata,capturedata,verifydata,sessiondata"
|
||||
)]
|
||||
pub struct PaymentResponse;
|
||||
|
||||
@ -77,6 +77,28 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSyncData> for
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSessionData>
|
||||
for PaymentResponse
|
||||
{
|
||||
async fn update_tracker<'b>(
|
||||
&'b self,
|
||||
db: &dyn StorageInterface,
|
||||
payment_id: &api::PaymentIdType,
|
||||
payment_data: PaymentData<F>,
|
||||
response: Option<
|
||||
types::RouterData<F, types::PaymentsSessionData, types::PaymentsResponseData>,
|
||||
>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> RouterResult<PaymentData<F>>
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
payment_response_update_tracker(db, payment_id, payment_data, response, storage_scheme)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCaptureData>
|
||||
for PaymentResponse
|
||||
@ -169,6 +191,7 @@ async fn payment_response_update_tracker<F: Clone, T>(
|
||||
};
|
||||
|
||||
let encoded_data = payment_data.connector_response.encoded_data.clone();
|
||||
let connector_name = payment_data.payment_attempt.connector.clone();
|
||||
|
||||
let authentication_data = redirection_data
|
||||
.map(|data| utils::Encode::<RedirectForm>::encode_to_value(&data))
|
||||
@ -189,6 +212,7 @@ async fn payment_response_update_tracker<F: Clone, T>(
|
||||
connector_transaction_id,
|
||||
authentication_data,
|
||||
encoded_data,
|
||||
connector_name,
|
||||
};
|
||||
|
||||
(
|
||||
|
||||
@ -16,7 +16,6 @@ use crate::{
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums},
|
||||
Connector,
|
||||
},
|
||||
utils::OptionExt,
|
||||
};
|
||||
@ -35,7 +34,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &api::PaymentsSessionRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
@ -235,4 +233,38 @@ where
|
||||
//No payment method data for this operation
|
||||
Ok((Box::new(self), None))
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> RouterResult<api::ConnectorCallType> {
|
||||
let connectors = &state.conf.connectors;
|
||||
let db = &state.store;
|
||||
|
||||
let supported_connectors: &Vec<String> = state.conf.connectors.supported.wallets.as_ref();
|
||||
|
||||
//FIXME: Check if merchant has enabled wallet through the connector
|
||||
let connector_names = db
|
||||
.find_merchant_connector_account_by_merchant_id_list(&merchant_account.merchant_id)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Database error when querying for merchant accounts")?
|
||||
.iter()
|
||||
.filter(|connector_account| {
|
||||
supported_connectors.contains(&connector_account.connector_name)
|
||||
})
|
||||
.map(|filtered_connector| filtered_connector.connector_name.clone())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let mut connectors_data = Vec::with_capacity(connector_names.len());
|
||||
|
||||
for connector_name in connector_names {
|
||||
let connector_data =
|
||||
api::ConnectorData::get_connector_by_name(connectors, &connector_name)?;
|
||||
connectors_data.push(connector_data);
|
||||
}
|
||||
|
||||
Ok(api::ConnectorCallType::Multiple(connectors_data))
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ use crate::{
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums, Customer},
|
||||
Connector,
|
||||
},
|
||||
utils::OptionExt,
|
||||
};
|
||||
@ -33,7 +32,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
_request: &api::PaymentsStartRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
@ -252,4 +250,12 @@ where
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_connector<'a>(
|
||||
&'a self,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
state: &AppState,
|
||||
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
|
||||
helpers::get_connector_default(merchant_account, state).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@ use crate::{
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums},
|
||||
Connector,
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PaymentOperation)]
|
||||
#[operation(ops = "all", flow = "sync")]
|
||||
pub struct PaymentStatus;
|
||||
@ -94,7 +94,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRetrieveRequest
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &api::PaymentsRetrieveRequest,
|
||||
_mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
|
||||
@ -17,7 +17,6 @@ use crate::{
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums},
|
||||
Connector,
|
||||
},
|
||||
utils::{OptionExt, StringExt},
|
||||
};
|
||||
@ -33,7 +32,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
state: &'a AppState,
|
||||
payment_id: &api::PaymentIdType,
|
||||
merchant_id: &str,
|
||||
_connector: Connector,
|
||||
request: &api::PaymentsRequest,
|
||||
mandate_type: Option<api::MandateTxnType>,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
|
||||
@ -73,6 +73,7 @@ where
|
||||
let orca_return_url = Some(helpers::create_redirect_url(
|
||||
&state.conf.server,
|
||||
&payment_data.payment_attempt,
|
||||
&merchant_connector_account.connector_name,
|
||||
));
|
||||
|
||||
router_data = types::RouterData {
|
||||
@ -145,6 +146,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::PaymentsSessionResponse
|
||||
where
|
||||
Self: From<Req>,
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
fn generate_response(
|
||||
_req: Option<Req>,
|
||||
payment_data: PaymentData<F>,
|
||||
_customer: Option<storage::Customer>,
|
||||
_auth_flow: services::AuthFlow,
|
||||
_server: &Server,
|
||||
_operation: Op,
|
||||
) -> RouterResponse<Self> {
|
||||
Ok(services::BachResponse::Json(Self {
|
||||
session_token: payment_data.sessions_token,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Op> ToResponse<Req, PaymentData<F>, Op> for api::VerifyResponse
|
||||
where
|
||||
Self: From<Req>,
|
||||
|
||||
@ -91,7 +91,11 @@ pub async fn trigger_refund_to_gateway(
|
||||
payment_attempt: &storage::PaymentAttempt,
|
||||
payment_intent: &storage::PaymentIntent,
|
||||
) -> RouterResult<storage::Refund> {
|
||||
let connector_id = payment_attempt.connector.to_string();
|
||||
let connector = payment_attempt
|
||||
.connector
|
||||
.clone()
|
||||
.ok_or(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let connector_id = connector.to_string();
|
||||
let connector: api::ConnectorData =
|
||||
api::ConnectorData::get_connector_by_name(&state.conf.connectors, &connector_id)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
@ -390,9 +394,14 @@ pub async fn validate_and_create_refund(
|
||||
validator::validate_maximum_refund_against_payment_attempt(&all_refunds)
|
||||
.change_context(errors::ApiErrorResponse::MaximumRefundCount)?;
|
||||
|
||||
let connector = payment_attempt
|
||||
.connector
|
||||
.clone()
|
||||
.ok_or(errors::ApiErrorResponse::InternalServerError)?;
|
||||
|
||||
refund_create_req = mk_new_refund(
|
||||
req,
|
||||
payment_attempt.connector.to_owned(),
|
||||
connector,
|
||||
payment_attempt,
|
||||
currency,
|
||||
&refund_id,
|
||||
|
||||
@ -75,6 +75,9 @@ impl Payments {
|
||||
web::resource("/{payment_id}/{merchant_id}/response/{connector}")
|
||||
.route(web::get().to(payments_response)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/session_tokens").route(web::get().to(payments_connector_session)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,16 +14,16 @@ use super::app::AppState;
|
||||
use crate::{
|
||||
core::{errors::http_not_implemented, payments},
|
||||
services::api,
|
||||
|
||||
types::api::{
|
||||
self as api_types, enums as api_enums,
|
||||
payments::{
|
||||
PaymentIdType, PaymentListConstraints, PaymentsCancelRequest, PaymentsCaptureRequest,
|
||||
PaymentsRequest, PaymentsRetrieveRequest,
|
||||
PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest,
|
||||
},
|
||||
Authorize, Capture, PSync, PaymentRetrieveBody, PaymentsResponse, PaymentsStartRequest,
|
||||
Verify, Void,
|
||||
}, // FIXME imports
|
||||
Authorize, Capture, PSync, PaymentRetrieveBody, PaymentsSessionRequest,
|
||||
PaymentsSessionResponse, PaymentsStartRequest, Session, Verify, Void,
|
||||
},
|
||||
//FIXME: remove specific imports
|
||||
};
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::PaymentsCreate))]
|
||||
@ -269,6 +269,33 @@ pub(crate) async fn payments_capture(
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::PaymentsSessionToken))]
|
||||
pub(crate) async fn payments_connector_session(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
json_payload: web::Json<PaymentsSessionRequest>,
|
||||
) -> HttpResponse {
|
||||
let sessions_payload = json_payload.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
sessions_payload,
|
||||
|state, merchant_account, payload| {
|
||||
payments::payments_core::<Session, PaymentsSessionResponse, _, _, _>(
|
||||
state,
|
||||
merchant_account,
|
||||
payments::PaymentSession,
|
||||
payload,
|
||||
api::AuthFlow::Merchant,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
},
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn payments_response(
|
||||
state: web::Data<AppState>,
|
||||
|
||||
@ -60,9 +60,14 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
||||
.await?
|
||||
}
|
||||
_ => {
|
||||
let connector = payment_data
|
||||
.payment_attempt
|
||||
.connector
|
||||
.clone()
|
||||
.ok_or(errors::ProcessTrackerError::MissingRequiredField)?;
|
||||
retry_sync_task(
|
||||
db,
|
||||
payment_data.payment_attempt.connector,
|
||||
connector,
|
||||
payment_data.payment_attempt.merchant_id,
|
||||
process,
|
||||
)
|
||||
|
||||
@ -45,7 +45,7 @@ diesel::table! {
|
||||
txn_id -> Varchar,
|
||||
created_at -> Timestamp,
|
||||
modified_at -> Timestamp,
|
||||
connector_name -> Varchar,
|
||||
connector_name -> Nullable<Varchar>,
|
||||
connector_transaction_id -> Nullable<Varchar>,
|
||||
authentication_data -> Nullable<Json>,
|
||||
encoded_data -> Nullable<Text>,
|
||||
@ -186,7 +186,7 @@ diesel::table! {
|
||||
amount -> Int4,
|
||||
currency -> Nullable<Currency>,
|
||||
save_to_locker -> Nullable<Bool>,
|
||||
connector -> Varchar,
|
||||
connector -> Nullable<Varchar>,
|
||||
error_message -> Nullable<Text>,
|
||||
offer_amount -> Nullable<Int4>,
|
||||
surcharge_amount -> Nullable<Int4>,
|
||||
|
||||
@ -121,7 +121,7 @@ pub struct PaymentsSessionData {
|
||||
//TODO: Add the fields here as required
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
pub struct ConnectorSessionToken {
|
||||
pub connector_name: String,
|
||||
pub session_token: String,
|
||||
|
||||
@ -12,14 +12,12 @@ use std::{fmt::Debug, marker, str::FromStr};
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
|
||||
pub use self::{admin::*, customers::*, payment_methods::*, payments::*, refunds::*, webhooks::*};
|
||||
use super::{storage, ConnectorsList};
|
||||
use crate::{
|
||||
configs::settings::Connectors,
|
||||
connector,
|
||||
core::errors::{self, CustomResult},
|
||||
services::ConnectorRedirectResponse,
|
||||
types::{self, api},
|
||||
utils::{OptionExt, ValueExt},
|
||||
types,
|
||||
};
|
||||
|
||||
pub trait ConnectorCommon {
|
||||
@ -71,45 +69,12 @@ pub struct ConnectorData {
|
||||
pub connector_name: types::Connector,
|
||||
}
|
||||
|
||||
pub enum ConnectorCallType {
|
||||
Single(ConnectorData),
|
||||
Multiple(Vec<ConnectorData>),
|
||||
}
|
||||
|
||||
impl ConnectorData {
|
||||
pub fn construct(
|
||||
connectors: &Connectors,
|
||||
merchant_account: &storage::MerchantAccount,
|
||||
) -> CustomResult<ConnectorData, errors::ApiErrorResponse> {
|
||||
// Add Validate also to ParseStruct
|
||||
//FIXME: Need Proper Routing Logic
|
||||
let vec_val: Vec<serde_json::Value> = merchant_account
|
||||
.custom_routing_rules
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.parse_value("CustomRoutingRulesVec")
|
||||
.change_context(errors::ConnectorError::RoutingRulesParsingError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let custom_routing_rules: api::CustomRoutingRules = vec_val[0]
|
||||
.clone()
|
||||
.parse_value("CustomRoutingRules")
|
||||
.change_context(errors::ConnectorError::RoutingRulesParsingError)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?;
|
||||
let connector_names = custom_routing_rules
|
||||
.connectors_pecking_order
|
||||
.unwrap_or_else(|| vec!["stripe".to_string()]);
|
||||
|
||||
//use routing rules if configured by merchant else query MCA as per PM
|
||||
let connector_list: ConnectorsList = ConnectorsList {
|
||||
connectors: connector_names,
|
||||
};
|
||||
|
||||
let connector_name = connector_list
|
||||
.connectors
|
||||
.first()
|
||||
.get_required_value("connectors")
|
||||
.change_context(errors::ConnectorError::FailedToObtainPreferredConnector)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?
|
||||
.as_str();
|
||||
|
||||
Self::get_connector_by_name(connectors, connector_name)
|
||||
}
|
||||
|
||||
pub fn get_connector_by_name(
|
||||
connectors: &Connectors,
|
||||
name: &str,
|
||||
|
||||
@ -599,6 +599,28 @@ impl From<PaymentsStartRequest> for PaymentsResponse {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentsSessionRequest> for PaymentsResponse {
|
||||
fn from(item: PaymentsSessionRequest) -> Self {
|
||||
let payment_id = match item.payment_id {
|
||||
api_types::PaymentIdType::PaymentIntentId(id) => Some(id),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
Self {
|
||||
payment_id,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentsSessionRequest> for PaymentsSessionResponse {
|
||||
fn from(_item: PaymentsSessionRequest) -> Self {
|
||||
Self {
|
||||
session_token: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<types::storage::PaymentIntent> for PaymentsResponse {
|
||||
fn from(item: types::storage::PaymentIntent) -> Self {
|
||||
Self {
|
||||
@ -774,6 +796,11 @@ pub struct PaymentsSessionRequest {
|
||||
pub client_secret: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, serde::Serialize, Clone)]
|
||||
pub struct PaymentsSessionResponse {
|
||||
pub session_token: Vec<types::ConnectorSessionToken>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct PaymentRetrieveBody {
|
||||
pub merchant_id: Option<String>,
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct ConnectorResponseNew {
|
||||
pub txn_id: String,
|
||||
pub created_at: PrimitiveDateTime,
|
||||
pub modified_at: PrimitiveDateTime,
|
||||
pub connector_name: String,
|
||||
pub connector_name: Option<String>,
|
||||
pub connector_transaction_id: Option<String>,
|
||||
pub authentication_data: Option<serde_json::Value>,
|
||||
pub encoded_data: Option<String>,
|
||||
@ -30,7 +30,7 @@ pub struct ConnectorResponse {
|
||||
pub txn_id: String,
|
||||
pub created_at: PrimitiveDateTime,
|
||||
pub modified_at: PrimitiveDateTime,
|
||||
pub connector_name: String,
|
||||
pub connector_name: Option<String>,
|
||||
pub connector_transaction_id: Option<String>,
|
||||
pub authentication_data: Option<serde_json::Value>,
|
||||
pub encoded_data: Option<String>,
|
||||
@ -43,6 +43,7 @@ pub struct ConnectorResponseUpdateInternal {
|
||||
pub authentication_data: Option<serde_json::Value>,
|
||||
pub modified_at: PrimitiveDateTime,
|
||||
pub encoded_data: Option<String>,
|
||||
pub connector_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -51,6 +52,7 @@ pub enum ConnectorResponseUpdate {
|
||||
connector_transaction_id: Option<String>,
|
||||
authentication_data: Option<serde_json::Value>,
|
||||
encoded_data: Option<String>,
|
||||
connector_name: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -74,11 +76,13 @@ impl From<ConnectorResponseUpdate> for ConnectorResponseUpdateInternal {
|
||||
connector_transaction_id,
|
||||
authentication_data,
|
||||
encoded_data,
|
||||
connector_name,
|
||||
} => Self {
|
||||
connector_transaction_id,
|
||||
authentication_data,
|
||||
encoded_data,
|
||||
modified_at: common_utils::date_time::now(),
|
||||
connector_name,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ pub struct PaymentAttempt {
|
||||
pub amount: i32,
|
||||
pub currency: Option<storage_enums::Currency>,
|
||||
pub save_to_locker: Option<bool>,
|
||||
pub connector: String,
|
||||
pub connector: Option<String>,
|
||||
pub error_message: Option<String>,
|
||||
pub offer_amount: Option<i32>,
|
||||
pub surcharge_amount: Option<i32>,
|
||||
@ -49,7 +49,7 @@ pub struct PaymentAttemptNew {
|
||||
pub currency: Option<storage_enums::Currency>,
|
||||
// pub auto_capture: Option<bool>,
|
||||
pub save_to_locker: Option<bool>,
|
||||
pub connector: String,
|
||||
pub connector: Option<String>,
|
||||
pub error_message: Option<String>,
|
||||
pub offer_amount: Option<i32>,
|
||||
pub surcharge_amount: Option<i32>,
|
||||
@ -88,6 +88,7 @@ pub enum PaymentAttemptUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
payment_method: Option<storage_enums::PaymentMethodType>,
|
||||
browser_info: Option<serde_json::Value>,
|
||||
connector: Option<String>,
|
||||
},
|
||||
VoidUpdate {
|
||||
status: storage_enums::AttemptStatus,
|
||||
@ -117,6 +118,7 @@ pub(super) struct PaymentAttemptUpdateInternal {
|
||||
currency: Option<storage_enums::Currency>,
|
||||
status: Option<storage_enums::AttemptStatus>,
|
||||
connector_transaction_id: Option<String>,
|
||||
connector: Option<String>,
|
||||
authentication_type: Option<storage_enums::AuthenticationType>,
|
||||
payment_method: Option<storage_enums::PaymentMethodType>,
|
||||
error_message: Option<String>,
|
||||
@ -182,11 +184,13 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
|
||||
status,
|
||||
payment_method,
|
||||
browser_info,
|
||||
connector,
|
||||
} => Self {
|
||||
status: Some(status),
|
||||
payment_method,
|
||||
modified_at: Some(common_utils::date_time::now()),
|
||||
browser_info,
|
||||
connector,
|
||||
..Default::default()
|
||||
},
|
||||
PaymentAttemptUpdate::VoidUpdate {
|
||||
@ -256,7 +260,7 @@ mod tests {
|
||||
let current_time = common_utils::date_time::now();
|
||||
let payment_attempt = PaymentAttemptNew {
|
||||
payment_id: payment_id.clone(),
|
||||
connector: types::Connector::Dummy.to_string(),
|
||||
connector: Some(types::Connector::Dummy.to_string()),
|
||||
created_at: current_time.into(),
|
||||
modified_at: current_time.into(),
|
||||
..PaymentAttemptNew::default()
|
||||
@ -287,7 +291,7 @@ mod tests {
|
||||
let payment_attempt = PaymentAttemptNew {
|
||||
payment_id: payment_id.clone(),
|
||||
merchant_id: merchant_id.clone(),
|
||||
connector: types::Connector::Dummy.to_string(),
|
||||
connector: Some(types::Connector::Dummy.to_string()),
|
||||
created_at: current_time.into(),
|
||||
modified_at: current_time.into(),
|
||||
..PaymentAttemptNew::default()
|
||||
@ -326,7 +330,7 @@ mod tests {
|
||||
let payment_attempt = PaymentAttemptNew {
|
||||
payment_id: uuid.clone(),
|
||||
merchant_id: "1".to_string(),
|
||||
connector: types::Connector::Dummy.to_string(),
|
||||
connector: Some(types::Connector::Dummy.to_string()),
|
||||
created_at: current_time.into(),
|
||||
modified_at: current_time.into(),
|
||||
// Adding a mandate_id
|
||||
|
||||
Reference in New Issue
Block a user