From 0e105db2160442eee74646e18a32b481f5ca2dcb Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Fri, 9 Dec 2022 20:58:15 +0530 Subject: [PATCH] Sessions flow for wallets (#60) --- crates/router/src/connector/aci.rs | 12 ++ .../router/src/connector/aci/transformers.rs | 3 +- crates/router/src/connector/adyen.rs | 12 ++ .../src/connector/adyen/transformers.rs | 6 +- .../router/src/connector/authorizedotnet.rs | 12 ++ .../connector/authorizedotnet/transformers.rs | 32 ++-- crates/router/src/connector/braintree.rs | 13 ++ .../src/connector/braintree/transformers.rs | 2 +- crates/router/src/connector/checkout.rs | 12 ++ .../src/connector/checkout/transformers.rs | 6 +- crates/router/src/connector/stripe.rs | 12 ++ .../src/connector/stripe/transformers.rs | 4 +- crates/router/src/core/payments.rs | 2 +- crates/router/src/core/payments/flows.rs | 3 +- .../src/core/payments/flows/authorize_flow.rs | 19 ++- .../src/core/payments/flows/cancel_flow.rs | 15 +- .../src/core/payments/flows/capture_flow.rs | 15 +- .../src/core/payments/flows/psync_flow.rs | 15 +- .../src/core/payments/flows/session_flow.rs | 94 ++++++++++++ .../src/core/payments/flows/verfiy_flow.rs | 16 +- .../payments/operations/payment_response.rs | 143 ++++++++++-------- .../router/src/core/payments/transformers.rs | 19 ++- crates/router/src/types.rs | 27 +++- crates/router/src/types/api/payments.rs | 10 ++ crates/router/tests/connectors/aci.rs | 12 +- crates/router/tests/connectors/checkout.rs | 24 +-- 26 files changed, 378 insertions(+), 162 deletions(-) create mode 100644 crates/router/src/core/payments/flows/session_flow.rs diff --git a/crates/router/src/connector/aci.rs b/crates/router/src/connector/aci.rs index a8567cf2ff..b3fb8b4589 100644 --- a/crates/router/src/connector/aci.rs +++ b/crates/router/src/connector/aci.rs @@ -53,6 +53,18 @@ impl api::PaymentAuthorize for Aci {} impl api::PaymentSync for Aci {} impl api::PaymentVoid for Aci {} impl api::PaymentCapture for Aci {} +impl api::PaymentSession for Aci {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Aci +{ + // Not Implemented (R) +} + impl api::PreVerify for Aci {} impl diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index 5b45bd58c7..040c70b68e 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -213,9 +213,8 @@ impl status: enums::AttemptStatus::from(AciPaymentStatus::from_str( &item.response.result.code, )?), - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), - //TODO: Add redirection details here redirection_data: None, redirect: false, }), diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index c9ed24cd74..10847f5d83 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -65,6 +65,18 @@ impl // TODO: Critical implement } +impl api::PaymentSession for Adyen {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Adyen +{ + // Not Implemented (R) +} + impl services::ConnectorIntegration< api::Capture, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index cf8c71da1a..a12b9b3a1a 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -405,7 +405,7 @@ impl TryFrom> }; Ok(types::RouterData { status, - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.psp_reference), redirection_data: None, redirect: false, @@ -445,7 +445,7 @@ pub fn get_adyen_response( None }; - let payments_response_data = types::PaymentsResponseData { + let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.psp_reference), redirection_data: None, redirect: false, @@ -509,7 +509,7 @@ pub fn get_redirection_response( }; // We don't get connector transaction id for redirections in Adyen. - let payments_response_data = types::PaymentsResponseData { + let payments_response_data = types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::NoResponseId, redirection_data: Some(redirection_data), redirect: true, diff --git a/crates/router/src/connector/authorizedotnet.rs b/crates/router/src/connector/authorizedotnet.rs index 38f3eaedae..948b01ecc5 100644 --- a/crates/router/src/connector/authorizedotnet.rs +++ b/crates/router/src/connector/authorizedotnet.rs @@ -43,6 +43,18 @@ impl api::PaymentAuthorize for Authorizedotnet {} impl api::PaymentSync for Authorizedotnet {} impl api::PaymentVoid for Authorizedotnet {} impl api::PaymentCapture for Authorizedotnet {} +impl api::PaymentSession for Authorizedotnet {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Authorizedotnet +{ + // Not Implemented (R) +} + impl api::PreVerify for Authorizedotnet {} impl diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index 982a031f45..ed550422ce 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -298,16 +298,13 @@ impl status, response: match error { Some(err) => Err(err), - None => { - Ok(types::PaymentsResponseData { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.transaction_response.transaction_id, - ), - //TODO: Add redirection details here - redirection_data: None, - redirect: false, - }) - } + None => Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId( + item.response.transaction_response.transaction_id, + ), + redirection_data: None, + redirect: false, + }), }, ..item.data }) @@ -472,10 +469,15 @@ impl TryFrom<&types::PaymentsSyncRouterData> for AuthorizedotnetCreateSyncReques .response .as_ref() .ok() - .map(|payment_response_data| { - payment_response_data - .resource_id - .get_connector_transaction_id() + .map(|payment_response_data| match payment_response_data { + types::PaymentsResponseData::TransactionResponse { resource_id, .. } => { + resource_id.get_connector_transaction_id() + } + _ => Err(error_stack::report!( + errors::ValidationError::MissingRequiredField { + field_name: "transaction_id".to_string() + } + )), }) .transpose() .change_context(errors::ConnectorError::ResponseHandlingFailed)?; @@ -580,7 +582,7 @@ impl let payment_status = enums::AttemptStatus::from(item.response.transaction.transaction_status); Ok(types::RouterData { - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction.transaction_id, ), diff --git a/crates/router/src/connector/braintree.rs b/crates/router/src/connector/braintree.rs index 8d591700aa..006c125b57 100644 --- a/crates/router/src/connector/braintree.rs +++ b/crates/router/src/connector/braintree.rs @@ -51,6 +51,19 @@ impl api::PaymentAuthorize for Braintree {} impl api::PaymentSync for Braintree {} impl api::PaymentVoid for Braintree {} impl api::PaymentCapture for Braintree {} + +impl api::PaymentSession for Braintree {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Braintree +{ + //TODO: implement sessions flow +} + impl api::PreVerify for Braintree {} #[allow(dead_code)] diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs index c100296876..5b5ab8f9e8 100644 --- a/crates/router/src/connector/braintree/transformers.rs +++ b/crates/router/src/connector/braintree/transformers.rs @@ -140,7 +140,7 @@ impl >, ) -> Result { Ok(types::RouterData { - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId( item.response.transaction.id, ), diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs index f1df92b941..1e0cbd6df5 100644 --- a/crates/router/src/connector/checkout.rs +++ b/crates/router/src/connector/checkout.rs @@ -57,6 +57,18 @@ impl api::PaymentAuthorize for Checkout {} impl api::PaymentSync for Checkout {} impl api::PaymentVoid for Checkout {} impl api::PaymentCapture for Checkout {} +impl api::PaymentSession for Checkout {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Checkout +{ + // Not Implemented (R) +} + impl api::PreVerify for Checkout {} impl diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 3ad9665489..1f6b0a0399 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -207,7 +207,7 @@ impl TryFrom> item.response.status, item.data.request.capture_method, )), - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), redirection_data, @@ -226,7 +226,7 @@ impl TryFrom> ) -> Result { Ok(types::RouterData { status: enums::AttemptStatus::from((item.response.status, None)), - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), //TODO: Add redirection details here redirection_data: None, @@ -267,7 +267,7 @@ impl TryFrom> ) -> Result { let response = &item.response; Ok(types::RouterData { - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(response.action_id.clone()), redirect: false, redirection_data: None, diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index b682933a09..60d280b04d 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -55,6 +55,18 @@ impl api::PaymentAuthorize for Stripe {} impl api::PaymentSync for Stripe {} impl api::PaymentVoid for Stripe {} impl api::PaymentCapture for Stripe {} +impl api::PaymentSession for Stripe {} + +impl + services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > for Stripe +{ + // Not Implemented (R) +} + impl api::PreVerify for Stripe {} impl diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 6a3747e037..7a08115be3 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -365,7 +365,7 @@ impl // description: item.response.description.map(|x| x.as_str()), // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), redirection_data, @@ -402,7 +402,7 @@ impl Ok(types::RouterData { status: enums::AttemptStatus::from(item.response.status), - response: Ok(types::PaymentsResponseData { + response: Ok(types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(item.response.id), redirect: redirection_data.is_some(), redirection_data, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 1c9f08b0be..7017a56ce5 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -294,7 +294,7 @@ where let stime_connector = Instant::now(); let router_data = payment_data - .construct_r_d(state, connector.connector.id(), merchant_account) + .construct_router_data(state, connector.connector.id(), merchant_account) .await?; let (res, payment_data) = router_data .decide_flows( diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 18e75a7de4..cb90ec9bad 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -2,6 +2,7 @@ mod authorize_flow; mod cancel_flow; mod capture_flow; mod psync_flow; +mod session_flow; mod verfiy_flow; use async_trait::async_trait; @@ -19,7 +20,7 @@ use crate::{ #[async_trait] pub trait ConstructFlowSpecificData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index b75003271b..35e2ba6cc1 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -28,7 +28,7 @@ impl types::PaymentsResponseData, > for PaymentData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, @@ -40,19 +40,18 @@ impl types::PaymentsResponseData, >, > { - let output = transformers::construct_payment_router_data::< - api::Authorize, - types::PaymentsAuthorizeData, - >(state, self.clone(), connector_id, merchant_account) - .await?; - Ok(output.1) + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await } } #[async_trait] -impl Feature - for types::RouterData -{ +impl Feature for types::PaymentsAuthorizeRouterData { async fn decide_flows<'a>( self, state: &AppState, diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index 5b6b0f9ba6..9df808207e 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -19,18 +19,19 @@ use crate::{ impl ConstructFlowSpecificData for PaymentData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, merchant_account: &storage::MerchantAccount, ) -> RouterResult { - let output = transformers::construct_payment_router_data::< - api::Void, - types::PaymentsCancelData, - >(state, self.clone(), connector_id, merchant_account) - .await?; - Ok(output.1) + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await } } diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs index 0bda242bc7..330f63a92b 100644 --- a/crates/router/src/core/payments/flows/capture_flow.rs +++ b/crates/router/src/core/payments/flows/capture_flow.rs @@ -20,18 +20,19 @@ impl ConstructFlowSpecificData for PaymentData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, merchant_account: &storage::MerchantAccount, ) -> RouterResult { - let output = transformers::construct_payment_router_data::< - api::Capture, - types::PaymentsCaptureData, - >(state, self.clone(), connector_id, merchant_account) - .await?; - Ok(output.1) + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await } } diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index 9b269340ed..580c86338e 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -19,7 +19,7 @@ use crate::{ impl ConstructFlowSpecificData for PaymentData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, @@ -27,12 +27,13 @@ impl ConstructFlowSpecificData RouterResult< types::RouterData, > { - let output = transformers::construct_payment_router_data::< - api::PSync, - types::PaymentsSyncData, - >(state, self.clone(), connector_id, merchant_account) - .await?; - Ok(output.1) + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await } } diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs new file mode 100644 index 0000000000..964ef34838 --- /dev/null +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -0,0 +1,94 @@ +use async_trait::async_trait; + +use super::{ConstructFlowSpecificData, Feature}; +use crate::{ + core::{ + errors::{ConnectorErrorExt, RouterResult}, + payments::{self, transformers, PaymentData}, + }, + routes, services, + types::{ + self, api, + storage::{self, enums}, + }, +}; + +#[async_trait] +impl + ConstructFlowSpecificData + for PaymentData +{ + async fn construct_router_data<'a>( + &self, + state: &routes::AppState, + connector_id: &str, + merchant_account: &storage::MerchantAccount, + ) -> RouterResult { + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await + } +} + +#[async_trait] +impl Feature for types::PaymentsSessionRouterData { + async fn decide_flows<'a>( + self, + state: &routes::AppState, + connector: api::ConnectorData, + customer: &Option, + payment_data: PaymentData, + call_connector_action: payments::CallConnectorAction, + _storage_schema: enums::MerchantStorageScheme, + ) -> (RouterResult, PaymentData) { + let resp = self + .decide_flow( + state, + connector, + customer, + Some(true), + call_connector_action, + ) + .await; + + (resp, payment_data) + } +} + +impl types::PaymentsSessionRouterData { + pub async fn decide_flow<'a, 'b>( + &'b self, + state: &'a routes::AppState, + connector: api::ConnectorData, + _customer: &Option, + _confirm: Option, + call_connector_action: payments::CallConnectorAction, + ) -> RouterResult + where + dyn api::Connector + Sync: services::ConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + >, + { + let connector_integration: services::BoxedConnectorIntegration< + api::Session, + types::PaymentsSessionData, + types::PaymentsResponseData, + > = connector.connector.get_connector_integration(); + let resp = services::execute_connector_processing_step( + state, + connector_integration, + self, + call_connector_action, + ) + .await + .map_err(|error| error.to_payment_failed_response())?; + + Ok(resp) + } +} diff --git a/crates/router/src/core/payments/flows/verfiy_flow.rs b/crates/router/src/core/payments/flows/verfiy_flow.rs index 98f1e15fa7..753e15371b 100644 --- a/crates/router/src/core/payments/flows/verfiy_flow.rs +++ b/crates/router/src/core/payments/flows/verfiy_flow.rs @@ -22,19 +22,19 @@ use crate::{ impl ConstructFlowSpecificData for PaymentData { - async fn construct_r_d<'a>( + async fn construct_router_data<'a>( &self, state: &AppState, connector_id: &str, merchant_account: &storage::MerchantAccount, ) -> RouterResult { - let (_, router_data) = transformers::construct_payment_router_data::< - api::Verify, - types::VerifyRequestData, - >(state, self.clone(), connector_id, merchant_account) - .await?; - - Ok(router_data) + transformers::construct_payment_router_data::( + state, + self.clone(), + connector_id, + merchant_account, + ) + .await } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index bb4535ffe7..04fbc982b0 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -45,14 +45,15 @@ impl PostUpdateTracker, types::PaymentsAuthorizeData payment_data.mandate_id = payment_data .mandate_id .or_else(|| router_data.request.mandate_id.clone()); - Ok(payment_response_ut( + + payment_response_update_tracker( db, payment_id, payment_data, Some(router_data), storage_scheme, ) - .await?) + .await } } @@ -71,7 +72,8 @@ impl PostUpdateTracker, types::PaymentsSyncData> for where F: 'b + Send, { - Ok(payment_response_ut(db, payment_id, payment_data, response, storage_scheme).await?) + payment_response_update_tracker(db, payment_id, payment_data, response, storage_scheme) + .await } } @@ -92,7 +94,8 @@ impl PostUpdateTracker, types::PaymentsCaptureData> where F: 'b + Send, { - Ok(payment_response_ut(db, payment_id, payment_data, response, storage_scheme).await?) + payment_response_update_tracker(db, payment_id, payment_data, response, storage_scheme) + .await } } @@ -111,7 +114,8 @@ impl PostUpdateTracker, types::PaymentsCancelData> f where F: 'b + Send, { - Ok(payment_response_ut(db, payment_id, payment_data, response, storage_scheme).await?) + payment_response_update_tracker(db, payment_id, payment_data, response, storage_scheme) + .await } } @@ -130,11 +134,12 @@ impl PostUpdateTracker, types::VerifyRequestData> fo where F: 'b + Send, { - Ok(payment_response_ut(db, payment_id, payment_data, response, storage_scheme).await?) + payment_response_update_tracker(db, payment_id, payment_data, response, storage_scheme) + .await } } -async fn payment_response_ut( +async fn payment_response_update_tracker( db: &dyn StorageInterface, _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, @@ -142,68 +147,77 @@ async fn payment_response_ut( storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> { let router_data = response.ok_or(report!(errors::ApiErrorResponse::InternalServerError))?; - let mut connector_response_data = None; - let payment_attempt_update = match router_data.response.clone() { - Err(err) => storage::PaymentAttemptUpdate::ErrorUpdate { - status: storage::enums::AttemptStatus::Failure, - error_message: Some(err.message), - }, - Ok(response) => { - connector_response_data = Some(response.clone()); - - storage::PaymentAttemptUpdate::ResponseUpdate { - status: router_data.status, - connector_transaction_id: match response.resource_id { + let (payment_attempt_update, connector_response_update) = match router_data.response.clone() { + Err(err) => ( + Some(storage::PaymentAttemptUpdate::ErrorUpdate { + status: storage::enums::AttemptStatus::Failure, + error_message: Some(err.message), + }), + None, + ), + Ok(payments_response) => match payments_response { + types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data, + redirect, + } => { + let connector_transaction_id = match resource_id { types::ResponseId::NoResponseId => None, - _ => Some( - response - .resource_id - .get_connector_transaction_id() - .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?, - ), - }, - authentication_type: None, - payment_method_id: Some(router_data.payment_method_id), - redirect: Some(response.redirect), - mandate_id: payment_data.mandate_id.clone(), + types::ResponseId::ConnectorTransactionId(id) + | types::ResponseId::EncodedData(id) => Some(id), + }; + + let encoded_data = payment_data.connector_response.encoded_data.clone(); + + let authentication_data = redirection_data + .map(|data| utils::Encode::::encode_to_value(&data)) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Could not parse the connector response")?; + + let payment_attempt_update = storage::PaymentAttemptUpdate::ResponseUpdate { + status: router_data.status, + connector_transaction_id: connector_transaction_id.clone(), + authentication_type: None, + payment_method_id: Some(router_data.payment_method_id), + redirect: Some(redirect), + mandate_id: payment_data.mandate_id.clone(), + }; + + let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate { + connector_transaction_id, + authentication_data, + encoded_data, + }; + + ( + Some(payment_attempt_update), + Some(connector_response_update), + ) } - } + + types::PaymentsResponseData::SessionResponse { .. } => (None, None), + }, }; - payment_data.payment_attempt = db - .update_payment_attempt( - payment_data.payment_attempt, - payment_attempt_update, - storage_scheme, - ) - .await - .map_err(|error| error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound))?; + payment_data.payment_attempt = match payment_attempt_update { + Some(payment_attempt_update) => db + .update_payment_attempt( + payment_data.payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .map_err(|error| { + error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound) + })?, + None => payment_data.payment_attempt, + }; - payment_data.connector_response = match connector_response_data { - Some(connector_response) => { - let authentication_data = connector_response - .redirection_data - .map(|data| utils::Encode::::encode_to_value(&data)) - .transpose() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Could not parse the connector response")?; - - let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate { - connector_transaction_id: match connector_response.resource_id { - types::ResponseId::NoResponseId => None, - _ => Some( - connector_response - .resource_id - .get_connector_transaction_id() - .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?, - ), - }, - authentication_data, - encoded_data: payment_data.connector_response.encoded_data.clone(), - }; - - db.update_connector_response( + payment_data.connector_response = match connector_response_update { + Some(connector_response_update) => db + .update_connector_response( payment_data.connector_response, connector_response_update, storage_scheme, @@ -211,8 +225,7 @@ async fn payment_response_ut( .await .map_err(|error| { error.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound) - })? - } + })?, None => payment_data.connector_response, }; diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index df63eb59e5..509dcca02a 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -26,10 +26,7 @@ pub async fn construct_payment_router_data<'a, F, T>( payment_data: PaymentData, connector_id: &str, merchant_account: &storage::MerchantAccount, -) -> RouterResult<( - PaymentData, - types::RouterData, -)> +) -> RouterResult> where T: TryFrom>, types::RouterData: Feature, @@ -62,13 +59,13 @@ where .or(payment_data.payment_attempt.payment_method) .get_required_value("payment_method_type")?; + //FIXME[#44]: why should response be filled during request let response = payment_data .payment_attempt .connector_transaction_id .as_ref() - .map(|id| types::PaymentsResponseData { + .map(|id| types::PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::ConnectorTransactionId(id.to_string()), - //TODO: Add redirection details here redirection_data: None, redirect: false, }); @@ -100,7 +97,7 @@ where response: response.map_or_else(|| Err(types::ErrorResponse::default()), Ok), }; - Ok((payment_data, router_data)) + Ok(router_data) } pub trait ToResponse @@ -417,6 +414,14 @@ impl TryFrom> for types::PaymentsCancelData { } } +impl TryFrom> for types::PaymentsSessionData { + type Error = errors::ApiErrorResponse; + + fn try_from(_payment_data: PaymentData) -> Result { + Ok(Self {}) + } +} + impl TryFrom> for types::VerifyRequestData { type Error = error_stack::Report; diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 0c904a16bd..d5e4adefd4 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -26,6 +26,8 @@ pub type PaymentsSyncRouterData = RouterData; pub type PaymentsCancelRouterData = RouterData; +pub type PaymentsSessionRouterData = + RouterData; pub type RefundsRouterData = RouterData; pub type PaymentsResponseRouterData = @@ -114,6 +116,16 @@ pub struct PaymentsCancelData { pub cancellation_reason: Option, } +#[derive(Debug, Clone)] +pub struct PaymentsSessionData { + //TODO: Add the fields here as required +} + +#[derive(Debug, Clone)] +pub struct PaymentsSessionResponseData { + pub client_token: Option, +} + #[derive(Debug, Clone)] pub struct VerifyRequestData { pub payment_method_data: payments::PaymentMethod, @@ -124,12 +136,17 @@ pub struct VerifyRequestData { pub off_session: Option, pub setup_mandate_details: Option, } + #[derive(Debug, Clone)] -pub struct PaymentsResponseData { - pub resource_id: ResponseId, - // pub amount_received: Option, // Calculation for amount received not in place yet - pub redirection_data: Option, - pub redirect: bool, +pub enum PaymentsResponseData { + TransactionResponse { + resource_id: ResponseId, + redirection_data: Option, + redirect: bool, + }, + SessionResponse { + session_token: String, + }, } #[derive(Debug, Clone, Default)] diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index 698836d2b6..cd50fa14eb 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -275,6 +275,9 @@ pub struct PSync; #[derive(Debug, Clone)] pub struct Void; +#[derive(Debug, Clone)] +pub struct Session; + #[derive(Debug, Clone)] pub struct Verify; @@ -710,6 +713,11 @@ pub trait PaymentCapture: { } +pub trait PaymentSession: + api::ConnectorIntegration +{ +} + pub trait PreVerify: api::ConnectorIntegration { @@ -722,8 +730,10 @@ pub trait Payment: + PaymentCapture + PaymentVoid + PreVerify + + PaymentSession { } + #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] pub struct PaymentsRetrieveRequest { pub resource_id: PaymentIdType, diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index eaf9e51794..41b0543be7 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -195,12 +195,12 @@ async fn refund_for_successful_payments() { types::RefundsResponseData, > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = response - .response - .unwrap() - .resource_id - .get_connector_transaction_id() - .unwrap(); + refund_request.request.connector_transaction_id = match response.response.unwrap() { + types::PaymentsResponseData::TransactionResponse { resource_id, .. } => { + resource_id.get_connector_transaction_id().unwrap() + } + _ => panic!("Connector transaction id not found"), + }; let response = services::api::execute_connector_processing_step( &state, connector_integration, diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs index 4e1a0c819b..ac64dfdcf3 100644 --- a/crates/router/tests/connectors/checkout.rs +++ b/crates/router/tests/connectors/checkout.rs @@ -167,12 +167,12 @@ async fn test_checkout_refund_success() { > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = response - .response - .unwrap() - .resource_id - .get_connector_transaction_id() - .unwrap(); + refund_request.request.connector_transaction_id = match response.response.unwrap() { + types::PaymentsResponseData::TransactionResponse { resource_id, .. } => { + resource_id.get_connector_transaction_id().unwrap() + } + _ => panic!("Connector transaction id not found"), + }; let response = services::api::execute_connector_processing_step( &state, @@ -260,12 +260,12 @@ async fn test_checkout_refund_failure() { types::RefundsResponseData, > = connector.connector.get_connector_integration(); let mut refund_request = construct_refund_router_data(); - refund_request.request.connector_transaction_id = response - .response - .unwrap() - .resource_id - .get_connector_transaction_id() - .unwrap(); + refund_request.request.connector_transaction_id = match response.response.unwrap() { + types::PaymentsResponseData::TransactionResponse { resource_id, .. } => { + resource_id.get_connector_transaction_id().unwrap() + } + _ => panic!("Connector transaction id not found"), + }; // Higher amout than that of payment refund_request.request.refund_amount = 696969;