mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 21:37:41 +08:00
feat(core): Hyperswitch <|> UCS Mandate flow integration (#8738)
Co-authored-by: Aishwariyaa Anand <aishwariyaa.anand@Aishwariyaa-Anand-C3PGW02T6Y.local> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
20049d52fa
commit
f94f39ef0c
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -3363,8 +3363,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "g2h"
|
name = "g2h"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/NishantJoshi00/g2h?branch=fixing-response-serializing#fd2c856b2c6c88a85d6fe51d95b4d3342b788d31"
|
||||||
checksum = "0aece561ff748cdd2a37c8ee938a47bbf9b2c03823b393a332110599b14ee827"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo_metadata 0.19.2",
|
"cargo_metadata 0.19.2",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
@ -3526,7 +3525,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "grpc-api-types"
|
name = "grpc-api-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/juspay/connector-service?rev=4918efedd5ea6c33e4a1600b988b2cf4948bed10#4918efedd5ea6c33e4a1600b988b2cf4948bed10"
|
source = "git+https://github.com/juspay/connector-service?rev=a9f7cd96693fa034ea69d8e21125ea0f76182fae#a9f7cd96693fa034ea69d8e21125ea0f76182fae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.4",
|
"axum 0.8.4",
|
||||||
"error-stack 0.5.0",
|
"error-stack 0.5.0",
|
||||||
@ -6900,7 +6899,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-grpc-client"
|
name = "rust-grpc-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/juspay/connector-service?rev=4918efedd5ea6c33e4a1600b988b2cf4948bed10#4918efedd5ea6c33e4a1600b988b2cf4948bed10"
|
source = "git+https://github.com/juspay/connector-service?rev=a9f7cd96693fa034ea69d8e21125ea0f76182fae#a9f7cd96693fa034ea69d8e21125ea0f76182fae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"grpc-api-types",
|
"grpc-api-types",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -53,7 +53,7 @@ reqwest = { version = "0.11.27", features = ["rustls-tls"] }
|
|||||||
http = "0.2.12"
|
http = "0.2.12"
|
||||||
url = { version = "2.5.4", features = ["serde"] }
|
url = { version = "2.5.4", features = ["serde"] }
|
||||||
quick-xml = { version = "0.31.0", features = ["serialize"] }
|
quick-xml = { version = "0.31.0", features = ["serialize"] }
|
||||||
unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "4918efedd5ea6c33e4a1600b988b2cf4948bed10", package = "rust-grpc-client" }
|
unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "a9f7cd96693fa034ea69d8e21125ea0f76182fae", package = "rust-grpc-client" }
|
||||||
|
|
||||||
|
|
||||||
# First party crates
|
# First party crates
|
||||||
|
|||||||
@ -88,6 +88,14 @@ pub enum UnifiedConnectorServiceError {
|
|||||||
/// Failed to perform Payment Get from gRPC Server
|
/// Failed to perform Payment Get from gRPC Server
|
||||||
#[error("Failed to perform Payment Get from gRPC Server")]
|
#[error("Failed to perform Payment Get from gRPC Server")]
|
||||||
PaymentGetFailure,
|
PaymentGetFailure,
|
||||||
|
|
||||||
|
/// Failed to perform Payment Setup Mandate from gRPC Server
|
||||||
|
#[error("Failed to perform Setup Mandate from gRPC Server")]
|
||||||
|
PaymentRegisterFailure,
|
||||||
|
|
||||||
|
/// Failed to perform Payment Repeat Payment from gRPC Server
|
||||||
|
#[error("Failed to perform Repeat Payment from gRPC Server")]
|
||||||
|
PaymentRepeatEverythingFailure,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result type for Dynamic Routing
|
/// Result type for Dynamic Routing
|
||||||
@ -160,7 +168,10 @@ impl UnifiedConnectorServiceClient {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
match connect_result {
|
match connect_result {
|
||||||
Ok(Ok(client)) => Some(Self { client }),
|
Ok(Ok(client)) => {
|
||||||
|
logger::info!("Successfully connected to Unified Connector Service");
|
||||||
|
Some(Self { client })
|
||||||
|
}
|
||||||
Ok(Err(err)) => {
|
Ok(Err(err)) => {
|
||||||
logger::error!(error = ?err, "Failed to connect to Unified Connector Service");
|
logger::error!(error = ?err, "Failed to connect to Unified Connector Service");
|
||||||
None
|
None
|
||||||
@ -217,6 +228,51 @@ impl UnifiedConnectorServiceClient {
|
|||||||
.change_context(UnifiedConnectorServiceError::PaymentGetFailure)
|
.change_context(UnifiedConnectorServiceError::PaymentGetFailure)
|
||||||
.inspect_err(|error| logger::error!(?error))
|
.inspect_err(|error| logger::error!(?error))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs Payment Setup Mandate
|
||||||
|
pub async fn payment_setup_mandate(
|
||||||
|
&self,
|
||||||
|
payment_register_request: payments_grpc::PaymentServiceRegisterRequest,
|
||||||
|
connector_auth_metadata: ConnectorAuthMetadata,
|
||||||
|
grpc_headers: GrpcHeaders,
|
||||||
|
) -> UnifiedConnectorServiceResult<tonic::Response<payments_grpc::PaymentServiceRegisterResponse>>
|
||||||
|
{
|
||||||
|
let mut request = tonic::Request::new(payment_register_request);
|
||||||
|
|
||||||
|
let metadata =
|
||||||
|
build_unified_connector_service_grpc_headers(connector_auth_metadata, grpc_headers)?;
|
||||||
|
*request.metadata_mut() = metadata;
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.clone()
|
||||||
|
.register(request)
|
||||||
|
.await
|
||||||
|
.change_context(UnifiedConnectorServiceError::PaymentRegisterFailure)
|
||||||
|
.inspect_err(|error| logger::error!(?error))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs Payment repeat (MIT - Merchant Initiated Transaction).
|
||||||
|
pub async fn payment_repeat(
|
||||||
|
&self,
|
||||||
|
payment_repeat_request: payments_grpc::PaymentServiceRepeatEverythingRequest,
|
||||||
|
connector_auth_metadata: ConnectorAuthMetadata,
|
||||||
|
grpc_headers: GrpcHeaders,
|
||||||
|
) -> UnifiedConnectorServiceResult<
|
||||||
|
tonic::Response<payments_grpc::PaymentServiceRepeatEverythingResponse>,
|
||||||
|
> {
|
||||||
|
let mut request = tonic::Request::new(payment_repeat_request);
|
||||||
|
|
||||||
|
let metadata =
|
||||||
|
build_unified_connector_service_grpc_headers(connector_auth_metadata, grpc_headers)?;
|
||||||
|
*request.metadata_mut() = metadata;
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.clone()
|
||||||
|
.repeat_everything(request)
|
||||||
|
.await
|
||||||
|
.change_context(UnifiedConnectorServiceError::PaymentRepeatEverythingFailure)
|
||||||
|
.inspect_err(|error| logger::error!(?error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the gRPC Headers for Unified Connector Service Request
|
/// Build the gRPC Headers for Unified Connector Service Request
|
||||||
|
|||||||
@ -88,7 +88,7 @@ reqwest = { version = "0.11.27", features = ["json", "rustls-tls", "gzip", "mult
|
|||||||
ring = "0.17.14"
|
ring = "0.17.14"
|
||||||
rust_decimal = { version = "1.37.1", features = ["serde-with-float", "serde-with-str"] }
|
rust_decimal = { version = "1.37.1", features = ["serde-with-float", "serde-with-str"] }
|
||||||
rust-i18n = { git = "https://github.com/kashif-m/rust-i18n", rev = "f2d8096aaaff7a87a847c35a5394c269f75e077a" }
|
rust-i18n = { git = "https://github.com/kashif-m/rust-i18n", rev = "f2d8096aaaff7a87a847c35a5394c269f75e077a" }
|
||||||
unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "4918efedd5ea6c33e4a1600b988b2cf4948bed10", package = "rust-grpc-client" }
|
unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "a9f7cd96693fa034ea69d8e21125ea0f76182fae", package = "rust-grpc-client" }
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
rustls = "0.22"
|
rustls = "0.22"
|
||||||
rustls-pemfile = "2"
|
rustls-pemfile = "2"
|
||||||
|
|||||||
@ -20,6 +20,7 @@ use crate::{
|
|||||||
unified_connector_service::{
|
unified_connector_service::{
|
||||||
build_unified_connector_service_auth_metadata,
|
build_unified_connector_service_auth_metadata,
|
||||||
handle_unified_connector_service_response_for_payment_authorize,
|
handle_unified_connector_service_response_for_payment_authorize,
|
||||||
|
handle_unified_connector_service_response_for_payment_repeat,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
logger,
|
logger,
|
||||||
@ -515,51 +516,23 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
|
|||||||
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
|
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
|
||||||
merchant_context: &domain::MerchantContext,
|
merchant_context: &domain::MerchantContext,
|
||||||
) -> RouterResult<()> {
|
) -> RouterResult<()> {
|
||||||
let client = state
|
if self.request.mandate_id.is_some() {
|
||||||
.grpc_client
|
call_unified_connector_service_repeat_payment(
|
||||||
.unified_connector_service_client
|
self,
|
||||||
.clone()
|
state,
|
||||||
.ok_or(ApiErrorResponse::InternalServerError)
|
merchant_connector_account,
|
||||||
.attach_printable("Failed to fetch Unified Connector Service client")?;
|
merchant_context,
|
||||||
|
|
||||||
let payment_authorize_request =
|
|
||||||
payments_grpc::PaymentServiceAuthorizeRequest::foreign_try_from(self)
|
|
||||||
.change_context(ApiErrorResponse::InternalServerError)
|
|
||||||
.attach_printable("Failed to construct Payment Authorize Request")?;
|
|
||||||
|
|
||||||
let connector_auth_metadata = build_unified_connector_service_auth_metadata(
|
|
||||||
merchant_connector_account,
|
|
||||||
merchant_context,
|
|
||||||
)
|
|
||||||
.change_context(ApiErrorResponse::InternalServerError)
|
|
||||||
.attach_printable("Failed to construct request metadata")?;
|
|
||||||
|
|
||||||
let response = client
|
|
||||||
.payment_authorize(
|
|
||||||
payment_authorize_request,
|
|
||||||
connector_auth_metadata,
|
|
||||||
state.get_grpc_headers(),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.change_context(ApiErrorResponse::InternalServerError)
|
} else {
|
||||||
.attach_printable("Failed to authorize payment")?;
|
call_unified_connector_service_authorize(
|
||||||
|
self,
|
||||||
let payment_authorize_response = response.into_inner();
|
state,
|
||||||
|
merchant_connector_account,
|
||||||
let (status, router_data_response) =
|
merchant_context,
|
||||||
handle_unified_connector_service_response_for_payment_authorize(
|
|
||||||
payment_authorize_response.clone(),
|
|
||||||
)
|
)
|
||||||
.change_context(ApiErrorResponse::InternalServerError)
|
.await
|
||||||
.attach_printable("Failed to deserialize UCS response")?;
|
}
|
||||||
|
|
||||||
self.status = status;
|
|
||||||
self.response = router_data_response;
|
|
||||||
self.raw_connector_response = payment_authorize_response
|
|
||||||
.raw_connector_response
|
|
||||||
.map(Secret::new);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,3 +819,115 @@ async fn process_capture_flow(
|
|||||||
router_data.response = Ok(updated_response);
|
router_data.response = Ok(updated_response);
|
||||||
Ok(router_data)
|
Ok(router_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn call_unified_connector_service_authorize(
|
||||||
|
router_data: &mut types::RouterData<
|
||||||
|
api::Authorize,
|
||||||
|
types::PaymentsAuthorizeData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
>,
|
||||||
|
state: &SessionState,
|
||||||
|
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
|
||||||
|
#[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
|
||||||
|
merchant_context: &domain::MerchantContext,
|
||||||
|
) -> RouterResult<()> {
|
||||||
|
let client = state
|
||||||
|
.grpc_client
|
||||||
|
.unified_connector_service_client
|
||||||
|
.clone()
|
||||||
|
.ok_or(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to fetch Unified Connector Service client")?;
|
||||||
|
|
||||||
|
let payment_authorize_request =
|
||||||
|
payments_grpc::PaymentServiceAuthorizeRequest::foreign_try_from(router_data)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct Payment Authorize Request")?;
|
||||||
|
|
||||||
|
let connector_auth_metadata =
|
||||||
|
build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct request metadata")?;
|
||||||
|
|
||||||
|
let response = client
|
||||||
|
.payment_authorize(
|
||||||
|
payment_authorize_request,
|
||||||
|
connector_auth_metadata,
|
||||||
|
state.get_grpc_headers(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to authorize payment")?;
|
||||||
|
|
||||||
|
let payment_authorize_response = response.into_inner();
|
||||||
|
|
||||||
|
let (status, router_data_response) =
|
||||||
|
handle_unified_connector_service_response_for_payment_authorize(
|
||||||
|
payment_authorize_response.clone(),
|
||||||
|
)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to deserialize UCS response")?;
|
||||||
|
|
||||||
|
router_data.status = status;
|
||||||
|
router_data.response = router_data_response;
|
||||||
|
router_data.raw_connector_response = payment_authorize_response
|
||||||
|
.raw_connector_response
|
||||||
|
.map(Secret::new);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn call_unified_connector_service_repeat_payment(
|
||||||
|
router_data: &mut types::RouterData<
|
||||||
|
api::Authorize,
|
||||||
|
types::PaymentsAuthorizeData,
|
||||||
|
types::PaymentsResponseData,
|
||||||
|
>,
|
||||||
|
state: &SessionState,
|
||||||
|
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
|
||||||
|
#[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
|
||||||
|
merchant_context: &domain::MerchantContext,
|
||||||
|
) -> RouterResult<()> {
|
||||||
|
let client = state
|
||||||
|
.grpc_client
|
||||||
|
.unified_connector_service_client
|
||||||
|
.clone()
|
||||||
|
.ok_or(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to fetch Unified Connector Service client")?;
|
||||||
|
|
||||||
|
let payment_repeat_request =
|
||||||
|
payments_grpc::PaymentServiceRepeatEverythingRequest::foreign_try_from(router_data)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct Payment Authorize Request")?;
|
||||||
|
|
||||||
|
let connector_auth_metadata =
|
||||||
|
build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct request metadata")?;
|
||||||
|
|
||||||
|
let response = client
|
||||||
|
.payment_repeat(
|
||||||
|
payment_repeat_request,
|
||||||
|
connector_auth_metadata,
|
||||||
|
state.get_grpc_headers(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to authorize payment")?;
|
||||||
|
|
||||||
|
let payment_repeat_response = response.into_inner();
|
||||||
|
|
||||||
|
let (status, router_data_response) =
|
||||||
|
handle_unified_connector_service_response_for_payment_repeat(
|
||||||
|
payment_repeat_response.clone(),
|
||||||
|
)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to deserialize UCS response")?;
|
||||||
|
|
||||||
|
router_data.status = status;
|
||||||
|
router_data.response = router_data_response;
|
||||||
|
router_data.raw_connector_response = payment_repeat_response
|
||||||
|
.raw_connector_response
|
||||||
|
.map(Secret::new);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@ -1,19 +1,25 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use common_types::payments as common_payments_types;
|
use common_types::payments as common_payments_types;
|
||||||
|
use error_stack::ResultExt;
|
||||||
use router_env::logger;
|
use router_env::logger;
|
||||||
|
use unified_connector_service_client::payments as payments_grpc;
|
||||||
|
|
||||||
use super::{ConstructFlowSpecificData, Feature};
|
use super::{ConstructFlowSpecificData, Feature};
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{
|
core::{
|
||||||
errors::{ConnectorErrorExt, RouterResult},
|
errors::{ApiErrorResponse, ConnectorErrorExt, RouterResult},
|
||||||
mandate,
|
mandate,
|
||||||
payments::{
|
payments::{
|
||||||
self, access_token, customers, helpers, tokenization, transformers, PaymentData,
|
self, access_token, customers, helpers, tokenization, transformers, PaymentData,
|
||||||
},
|
},
|
||||||
|
unified_connector_service::{
|
||||||
|
build_unified_connector_service_auth_metadata,
|
||||||
|
handle_unified_connector_service_response_for_payment_register,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
routes::SessionState,
|
routes::SessionState,
|
||||||
services,
|
services,
|
||||||
types::{self, api, domain},
|
types::{self, api, domain, transformers::ForeignTryFrom},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "v1")]
|
#[cfg(feature = "v1")]
|
||||||
@ -200,6 +206,62 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
|
|||||||
_ => Ok((None, true)),
|
_ => Ok((None, true)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn call_unified_connector_service<'a>(
|
||||||
|
&mut self,
|
||||||
|
state: &SessionState,
|
||||||
|
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
|
||||||
|
#[cfg(feature = "v2")]
|
||||||
|
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
|
||||||
|
merchant_context: &domain::MerchantContext,
|
||||||
|
) -> RouterResult<()> {
|
||||||
|
let client = state
|
||||||
|
.grpc_client
|
||||||
|
.unified_connector_service_client
|
||||||
|
.clone()
|
||||||
|
.ok_or(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to fetch Unified Connector Service client")?;
|
||||||
|
|
||||||
|
let payment_register_request =
|
||||||
|
payments_grpc::PaymentServiceRegisterRequest::foreign_try_from(self)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct Payment Setup Mandate Request")?;
|
||||||
|
|
||||||
|
let connector_auth_metadata = build_unified_connector_service_auth_metadata(
|
||||||
|
merchant_connector_account,
|
||||||
|
merchant_context,
|
||||||
|
)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to construct request metadata")?;
|
||||||
|
|
||||||
|
let response = client
|
||||||
|
.payment_setup_mandate(
|
||||||
|
payment_register_request,
|
||||||
|
connector_auth_metadata,
|
||||||
|
state.get_grpc_headers(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to Setup Mandate payment")?;
|
||||||
|
|
||||||
|
let payment_register_response = response.into_inner();
|
||||||
|
|
||||||
|
let (status, router_data_response) =
|
||||||
|
handle_unified_connector_service_response_for_payment_register(
|
||||||
|
payment_register_response.clone(),
|
||||||
|
)
|
||||||
|
.change_context(ApiErrorResponse::InternalServerError)
|
||||||
|
.attach_printable("Failed to deserialize UCS response")?;
|
||||||
|
|
||||||
|
self.status = status;
|
||||||
|
self.response = router_data_response;
|
||||||
|
// UCS does not return raw connector response for setup mandate right now
|
||||||
|
// self.raw_connector_response = payment_register_response
|
||||||
|
// .raw_connector_response
|
||||||
|
// .map(Secret::new);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mandate::MandateBehaviour for types::SetupMandateRequestData {
|
impl mandate::MandateBehaviour for types::SetupMandateRequestData {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAcco
|
|||||||
use hyperswitch_domain_models::{
|
use hyperswitch_domain_models::{
|
||||||
merchant_context::MerchantContext,
|
merchant_context::MerchantContext,
|
||||||
router_data::{ConnectorAuthType, ErrorResponse, RouterData},
|
router_data::{ConnectorAuthType, ErrorResponse, RouterData},
|
||||||
router_response_types::{PaymentsResponseData, RedirectForm},
|
router_response_types::PaymentsResponseData,
|
||||||
};
|
};
|
||||||
use masking::{ExposeInterface, PeekInterface, Secret};
|
use masking::{ExposeInterface, PeekInterface, Secret};
|
||||||
use unified_connector_service_client::payments::{
|
use unified_connector_service_client::payments::{
|
||||||
@ -238,85 +238,8 @@ pub fn handle_unified_connector_service_response_for_payment_authorize(
|
|||||||
> {
|
> {
|
||||||
let status = AttemptStatus::foreign_try_from(response.status())?;
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
let connector_response_reference_id =
|
let router_data_response =
|
||||||
response.response_ref_id.as_ref().and_then(|identifier| {
|
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
|
||||||
identifier
|
|
||||||
.id_type
|
|
||||||
.clone()
|
|
||||||
.and_then(|id_type| match id_type {
|
|
||||||
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
|
||||||
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
|
||||||
Some(encoded_data)
|
|
||||||
}
|
|
||||||
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let transaction_id = response.transaction_id.as_ref().and_then(|id| {
|
|
||||||
id.id_type.clone().and_then(|id_type| match id_type {
|
|
||||||
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
|
||||||
payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
|
|
||||||
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let router_data_response = match status {
|
|
||||||
AttemptStatus::Charged |
|
|
||||||
AttemptStatus::Authorized |
|
|
||||||
AttemptStatus::AuthenticationPending |
|
|
||||||
AttemptStatus::DeviceDataCollectionPending |
|
|
||||||
AttemptStatus::Started |
|
|
||||||
AttemptStatus::AuthenticationSuccessful |
|
|
||||||
AttemptStatus::Authorizing |
|
|
||||||
AttemptStatus::ConfirmationAwaited |
|
|
||||||
AttemptStatus::Pending => Ok(PaymentsResponseData::TransactionResponse {
|
|
||||||
resource_id: match transaction_id.as_ref() {
|
|
||||||
Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
|
|
||||||
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
|
|
||||||
},
|
|
||||||
redirection_data: Box::new(
|
|
||||||
response
|
|
||||||
.redirection_data
|
|
||||||
.clone()
|
|
||||||
.map(RedirectForm::foreign_try_from)
|
|
||||||
.transpose()?
|
|
||||||
),
|
|
||||||
mandate_reference: Box::new(None),
|
|
||||||
connector_metadata: None,
|
|
||||||
network_txn_id: response.network_txn_id.clone(),
|
|
||||||
connector_response_reference_id,
|
|
||||||
incremental_authorization_allowed: response.incremental_authorization_allowed,
|
|
||||||
charges: None,
|
|
||||||
}),
|
|
||||||
AttemptStatus::AuthenticationFailed
|
|
||||||
| AttemptStatus::AuthorizationFailed
|
|
||||||
| AttemptStatus::Unresolved
|
|
||||||
| AttemptStatus::Failure => Err(ErrorResponse {
|
|
||||||
code: response.error_code().to_owned(),
|
|
||||||
message: response.error_message().to_owned(),
|
|
||||||
reason: Some(response.error_message().to_owned()),
|
|
||||||
status_code: 500,
|
|
||||||
attempt_status: Some(status),
|
|
||||||
connector_transaction_id: connector_response_reference_id,
|
|
||||||
network_decline_code: None,
|
|
||||||
network_advice_code: None,
|
|
||||||
network_error_message: None,
|
|
||||||
}),
|
|
||||||
AttemptStatus::RouterDeclined |
|
|
||||||
AttemptStatus::CodInitiated |
|
|
||||||
AttemptStatus::Voided |
|
|
||||||
AttemptStatus::VoidInitiated |
|
|
||||||
AttemptStatus::CaptureInitiated |
|
|
||||||
AttemptStatus::VoidFailed |
|
|
||||||
AttemptStatus::AutoRefunded |
|
|
||||||
AttemptStatus::PartialCharged |
|
|
||||||
AttemptStatus::PartialChargedAndChargeable |
|
|
||||||
AttemptStatus::PaymentMethodAwaited |
|
|
||||||
AttemptStatus::CaptureFailed |
|
|
||||||
AttemptStatus::IntegrityFailure => return Err(UnifiedConnectorServiceError::NotImplemented(format!(
|
|
||||||
"AttemptStatus {status:?} is not implemented for Unified Connector Service"
|
|
||||||
)).into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((status, router_data_response))
|
Ok((status, router_data_response))
|
||||||
}
|
}
|
||||||
@ -329,75 +252,36 @@ pub fn handle_unified_connector_service_response_for_payment_get(
|
|||||||
> {
|
> {
|
||||||
let status = AttemptStatus::foreign_try_from(response.status())?;
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
let connector_response_reference_id =
|
let router_data_response =
|
||||||
response.response_ref_id.as_ref().and_then(|identifier| {
|
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
|
||||||
identifier
|
|
||||||
.id_type
|
Ok((status, router_data_response))
|
||||||
.clone()
|
}
|
||||||
.and_then(|id_type| match id_type {
|
|
||||||
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
pub fn handle_unified_connector_service_response_for_payment_register(
|
||||||
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
response: payments_grpc::PaymentServiceRegisterResponse,
|
||||||
Some(encoded_data)
|
) -> CustomResult<
|
||||||
}
|
(AttemptStatus, Result<PaymentsResponseData, ErrorResponse>),
|
||||||
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
UnifiedConnectorServiceError,
|
||||||
})
|
> {
|
||||||
});
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
let router_data_response = match status {
|
let router_data_response =
|
||||||
AttemptStatus::Charged |
|
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
|
||||||
AttemptStatus::Authorized |
|
|
||||||
AttemptStatus::AuthenticationPending |
|
Ok((status, router_data_response))
|
||||||
AttemptStatus::DeviceDataCollectionPending |
|
}
|
||||||
AttemptStatus::Started |
|
|
||||||
AttemptStatus::AuthenticationSuccessful |
|
pub fn handle_unified_connector_service_response_for_payment_repeat(
|
||||||
AttemptStatus::Authorizing |
|
response: payments_grpc::PaymentServiceRepeatEverythingResponse,
|
||||||
AttemptStatus::ConfirmationAwaited |
|
) -> CustomResult<
|
||||||
AttemptStatus::Pending => Ok(
|
(AttemptStatus, Result<PaymentsResponseData, ErrorResponse>),
|
||||||
PaymentsResponseData::TransactionResponse {
|
UnifiedConnectorServiceError,
|
||||||
resource_id: match connector_response_reference_id.as_ref() {
|
> {
|
||||||
Some(connector_response_reference_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(connector_response_reference_id.clone()),
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
|
|
||||||
},
|
let router_data_response =
|
||||||
redirection_data: Box::new(
|
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
|
||||||
None
|
|
||||||
),
|
|
||||||
mandate_reference: Box::new(None),
|
|
||||||
connector_metadata: None,
|
|
||||||
network_txn_id: response.network_txn_id.clone(),
|
|
||||||
connector_response_reference_id,
|
|
||||||
incremental_authorization_allowed: None,
|
|
||||||
charges: None,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
AttemptStatus::AuthenticationFailed
|
|
||||||
| AttemptStatus::AuthorizationFailed
|
|
||||||
| AttemptStatus::Failure => Err(ErrorResponse {
|
|
||||||
code: response.error_code().to_owned(),
|
|
||||||
message: response.error_message().to_owned(),
|
|
||||||
reason: Some(response.error_message().to_owned()),
|
|
||||||
status_code: 500,
|
|
||||||
attempt_status: Some(status),
|
|
||||||
connector_transaction_id: connector_response_reference_id,
|
|
||||||
network_decline_code: None,
|
|
||||||
network_advice_code: None,
|
|
||||||
network_error_message: None,
|
|
||||||
}),
|
|
||||||
AttemptStatus::RouterDeclined |
|
|
||||||
AttemptStatus::CodInitiated |
|
|
||||||
AttemptStatus::Voided |
|
|
||||||
AttemptStatus::VoidInitiated |
|
|
||||||
AttemptStatus::CaptureInitiated |
|
|
||||||
AttemptStatus::VoidFailed |
|
|
||||||
AttemptStatus::AutoRefunded |
|
|
||||||
AttemptStatus::PartialCharged |
|
|
||||||
AttemptStatus::PartialChargedAndChargeable |
|
|
||||||
AttemptStatus::Unresolved |
|
|
||||||
AttemptStatus::PaymentMethodAwaited |
|
|
||||||
AttemptStatus::CaptureFailed |
|
|
||||||
AttemptStatus::IntegrityFailure => return Err(UnifiedConnectorServiceError::NotImplemented(format!(
|
|
||||||
"AttemptStatus {status:?} is not implemented for Unified Connector Service"
|
|
||||||
)).into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((status, router_data_response))
|
Ok((status, router_data_response))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,11 @@ use diesel_models::enums as storage_enums;
|
|||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
use external_services::grpc_client::unified_connector_service::UnifiedConnectorServiceError;
|
use external_services::grpc_client::unified_connector_service::UnifiedConnectorServiceError;
|
||||||
use hyperswitch_domain_models::{
|
use hyperswitch_domain_models::{
|
||||||
router_data::RouterData,
|
router_data::{ErrorResponse, RouterData},
|
||||||
router_flow_types::payments::{Authorize, PSync},
|
router_flow_types::payments::{Authorize, PSync, SetupMandate},
|
||||||
router_request_types::{AuthenticationData, PaymentsAuthorizeData, PaymentsSyncData},
|
router_request_types::{
|
||||||
|
AuthenticationData, PaymentsAuthorizeData, PaymentsSyncData, SetupMandateRequestData,
|
||||||
|
},
|
||||||
router_response_types::{PaymentsResponseData, RedirectForm},
|
router_response_types::{PaymentsResponseData, RedirectForm},
|
||||||
};
|
};
|
||||||
use masking::{ExposeInterface, PeekInterface};
|
use masking::{ExposeInterface, PeekInterface};
|
||||||
@ -167,6 +169,443 @@ impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsRespon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<&RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>>
|
||||||
|
for payments_grpc::PaymentServiceRegisterRequest
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
router_data: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let currency = payments_grpc::Currency::foreign_try_from(router_data.request.currency)?;
|
||||||
|
let payment_method = router_data
|
||||||
|
.request
|
||||||
|
.payment_method_type
|
||||||
|
.map(|payment_method_type| {
|
||||||
|
build_unified_connector_service_payment_method(
|
||||||
|
router_data.request.payment_method_data.clone(),
|
||||||
|
payment_method_type,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
let address = payments_grpc::PaymentAddress::foreign_try_from(router_data.address.clone())?;
|
||||||
|
let auth_type = payments_grpc::AuthenticationType::foreign_try_from(router_data.auth_type)?;
|
||||||
|
let browser_info = router_data
|
||||||
|
.request
|
||||||
|
.browser_info
|
||||||
|
.clone()
|
||||||
|
.map(payments_grpc::BrowserInformation::foreign_try_from)
|
||||||
|
.transpose()?;
|
||||||
|
let setup_future_usage = router_data
|
||||||
|
.request
|
||||||
|
.setup_future_usage
|
||||||
|
.map(payments_grpc::FutureUsage::foreign_try_from)
|
||||||
|
.transpose()?;
|
||||||
|
let customer_acceptance = router_data
|
||||||
|
.request
|
||||||
|
.customer_acceptance
|
||||||
|
.clone()
|
||||||
|
.map(payments_grpc::CustomerAcceptance::foreign_try_from)
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
request_ref_id: Some(Identifier {
|
||||||
|
id_type: Some(payments_grpc::identifier::IdType::Id(
|
||||||
|
router_data.connector_request_reference_id.clone(),
|
||||||
|
)),
|
||||||
|
}),
|
||||||
|
currency: currency.into(),
|
||||||
|
payment_method,
|
||||||
|
minor_amount: router_data.request.amount,
|
||||||
|
email: router_data
|
||||||
|
.request
|
||||||
|
.email
|
||||||
|
.clone()
|
||||||
|
.map(|e| e.expose().expose()),
|
||||||
|
customer_name: router_data
|
||||||
|
.request
|
||||||
|
.customer_name
|
||||||
|
.clone()
|
||||||
|
.map(|customer_name| customer_name.peek().to_owned()),
|
||||||
|
connector_customer_id: router_data
|
||||||
|
.request
|
||||||
|
.customer_id
|
||||||
|
.as_ref()
|
||||||
|
.map(|id| id.get_string_repr().to_string()),
|
||||||
|
address: Some(address),
|
||||||
|
auth_type: auth_type.into(),
|
||||||
|
enrolled_for_3ds: false,
|
||||||
|
authentication_data: None,
|
||||||
|
metadata: router_data
|
||||||
|
.request
|
||||||
|
.metadata
|
||||||
|
.as_ref()
|
||||||
|
.map(|secret| secret.peek())
|
||||||
|
.and_then(|val| val.as_object()) //secret
|
||||||
|
.map(|map| {
|
||||||
|
map.iter()
|
||||||
|
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
|
||||||
|
.collect::<HashMap<String, String>>()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
return_url: router_data.request.router_return_url.clone(),
|
||||||
|
webhook_url: router_data.request.webhook_url.clone(),
|
||||||
|
complete_authorize_url: router_data.request.complete_authorize_url.clone(),
|
||||||
|
access_token: None,
|
||||||
|
session_token: None,
|
||||||
|
order_tax_amount: None,
|
||||||
|
order_category: None,
|
||||||
|
merchant_order_reference_id: None,
|
||||||
|
shipping_cost: router_data
|
||||||
|
.request
|
||||||
|
.shipping_cost
|
||||||
|
.map(|cost| cost.get_amount_as_i64()),
|
||||||
|
setup_future_usage: setup_future_usage.map(|s| s.into()),
|
||||||
|
off_session: router_data.request.off_session,
|
||||||
|
request_incremental_authorization: router_data
|
||||||
|
.request
|
||||||
|
.request_incremental_authorization,
|
||||||
|
request_extended_authorization: None,
|
||||||
|
customer_acceptance,
|
||||||
|
browser_info,
|
||||||
|
payment_experience: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>>
|
||||||
|
for payments_grpc::PaymentServiceRepeatEverythingRequest
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
router_data: &RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let currency = payments_grpc::Currency::foreign_try_from(router_data.request.currency)?;
|
||||||
|
|
||||||
|
let mandate_reference = match &router_data.request.mandate_id {
|
||||||
|
Some(mandate) => match &mandate.mandate_reference_id {
|
||||||
|
Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
|
||||||
|
connector_mandate_id,
|
||||||
|
)) => Some(payments_grpc::MandateReference {
|
||||||
|
mandate_id: connector_mandate_id.get_connector_mandate_id(),
|
||||||
|
}),
|
||||||
|
_ => {
|
||||||
|
return Err(UnifiedConnectorServiceError::MissingRequiredField {
|
||||||
|
field_name: "connector_mandate_id",
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return Err(UnifiedConnectorServiceError::MissingRequiredField {
|
||||||
|
field_name: "connector_mandate_id",
|
||||||
|
}
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
request_ref_id: Some(Identifier {
|
||||||
|
id_type: Some(payments_grpc::identifier::IdType::Id(
|
||||||
|
router_data.connector_request_reference_id.clone(),
|
||||||
|
)),
|
||||||
|
}),
|
||||||
|
mandate_reference,
|
||||||
|
amount: router_data.request.amount,
|
||||||
|
currency: currency.into(),
|
||||||
|
minor_amount: router_data.request.amount,
|
||||||
|
merchant_order_reference_id: router_data.request.merchant_order_reference_id.clone(),
|
||||||
|
metadata: router_data
|
||||||
|
.request
|
||||||
|
.metadata
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|val| val.as_object())
|
||||||
|
.map(|map| {
|
||||||
|
map.iter()
|
||||||
|
.filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
|
||||||
|
.collect::<HashMap<String, String>>()
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
webhook_url: router_data.request.webhook_url.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
|
||||||
|
for Result<PaymentsResponseData, ErrorResponse>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
response: payments_grpc::PaymentServiceAuthorizeResponse,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
|
let connector_response_reference_id =
|
||||||
|
response.response_ref_id.as_ref().and_then(|identifier| {
|
||||||
|
identifier
|
||||||
|
.id_type
|
||||||
|
.clone()
|
||||||
|
.and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
||||||
|
Some(encoded_data)
|
||||||
|
}
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let transaction_id = response.transaction_id.as_ref().and_then(|id| {
|
||||||
|
id.id_type.clone().and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = if response.error_code.is_some() {
|
||||||
|
Err(ErrorResponse {
|
||||||
|
code: response.error_code().to_owned(),
|
||||||
|
message: response.error_message().to_owned(),
|
||||||
|
reason: Some(response.error_message().to_owned()),
|
||||||
|
status_code: 500, //TODO: To be handled once UCS sends proper status codes
|
||||||
|
attempt_status: Some(status),
|
||||||
|
connector_transaction_id: connector_response_reference_id,
|
||||||
|
network_decline_code: None,
|
||||||
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(PaymentsResponseData::TransactionResponse {
|
||||||
|
resource_id: match transaction_id.as_ref() {
|
||||||
|
Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
|
||||||
|
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
|
||||||
|
},
|
||||||
|
redirection_data: Box::new(
|
||||||
|
response
|
||||||
|
.redirection_data
|
||||||
|
.clone()
|
||||||
|
.map(RedirectForm::foreign_try_from)
|
||||||
|
.transpose()?
|
||||||
|
),
|
||||||
|
mandate_reference: Box::new(None),
|
||||||
|
connector_metadata: None,
|
||||||
|
network_txn_id: response.network_txn_id.clone(),
|
||||||
|
connector_response_reference_id,
|
||||||
|
incremental_authorization_allowed: response.incremental_authorization_allowed,
|
||||||
|
charges: None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
|
||||||
|
for Result<PaymentsResponseData, ErrorResponse>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
response: payments_grpc::PaymentServiceGetResponse,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
|
let connector_response_reference_id =
|
||||||
|
response.response_ref_id.as_ref().and_then(|identifier| {
|
||||||
|
identifier
|
||||||
|
.id_type
|
||||||
|
.clone()
|
||||||
|
.and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
||||||
|
Some(encoded_data)
|
||||||
|
}
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = if response.error_code.is_some() {
|
||||||
|
Err(ErrorResponse {
|
||||||
|
code: response.error_code().to_owned(),
|
||||||
|
message: response.error_message().to_owned(),
|
||||||
|
reason: Some(response.error_message().to_owned()),
|
||||||
|
status_code: 500, //TODO: To be handled once UCS sends proper status codes
|
||||||
|
attempt_status: Some(status),
|
||||||
|
connector_transaction_id: connector_response_reference_id,
|
||||||
|
network_decline_code: None,
|
||||||
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(PaymentsResponseData::TransactionResponse {
|
||||||
|
resource_id: match connector_response_reference_id.as_ref() {
|
||||||
|
Some(connector_response_reference_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(connector_response_reference_id.clone()),
|
||||||
|
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
|
||||||
|
},
|
||||||
|
redirection_data: Box::new(
|
||||||
|
None
|
||||||
|
),
|
||||||
|
mandate_reference: Box::new(None),
|
||||||
|
connector_metadata: None,
|
||||||
|
network_txn_id: response.network_txn_id.clone(),
|
||||||
|
connector_response_reference_id,
|
||||||
|
incremental_authorization_allowed: None,
|
||||||
|
charges: None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
|
||||||
|
for Result<PaymentsResponseData, ErrorResponse>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
response: payments_grpc::PaymentServiceRegisterResponse,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
|
let connector_response_reference_id =
|
||||||
|
response.response_ref_id.as_ref().and_then(|identifier| {
|
||||||
|
identifier
|
||||||
|
.id_type
|
||||||
|
.clone()
|
||||||
|
.and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
||||||
|
Some(encoded_data)
|
||||||
|
}
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = if response.error_code.is_some() {
|
||||||
|
Err(ErrorResponse {
|
||||||
|
code: response.error_code().to_owned(),
|
||||||
|
message: response.error_message().to_owned(),
|
||||||
|
reason: Some(response.error_message().to_owned()),
|
||||||
|
status_code: 500, //TODO: To be handled once UCS sends proper status codes
|
||||||
|
attempt_status: Some(status),
|
||||||
|
connector_transaction_id: connector_response_reference_id,
|
||||||
|
network_decline_code: None,
|
||||||
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(PaymentsResponseData::TransactionResponse {
|
||||||
|
resource_id: response.registration_id.as_ref().and_then(|identifier| {
|
||||||
|
identifier
|
||||||
|
.id_type
|
||||||
|
.clone()
|
||||||
|
.and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(
|
||||||
|
hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id),
|
||||||
|
),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(
|
||||||
|
hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(encoded_data),
|
||||||
|
),
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
}).unwrap_or(hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId),
|
||||||
|
redirection_data: Box::new(
|
||||||
|
response
|
||||||
|
.redirection_data
|
||||||
|
.clone()
|
||||||
|
.map(RedirectForm::foreign_try_from)
|
||||||
|
.transpose()?
|
||||||
|
),
|
||||||
|
mandate_reference: Box::new(
|
||||||
|
response.mandate_reference.map(|grpc_mandate| {
|
||||||
|
hyperswitch_domain_models::router_response_types::MandateReference {
|
||||||
|
connector_mandate_id: grpc_mandate.mandate_id,
|
||||||
|
payment_method_id: None,
|
||||||
|
mandate_metadata: None,
|
||||||
|
connector_mandate_request_reference_id: None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
),
|
||||||
|
connector_metadata: None,
|
||||||
|
network_txn_id: response.network_txn_id,
|
||||||
|
connector_response_reference_id,
|
||||||
|
incremental_authorization_allowed: response.incremental_authorization_allowed,
|
||||||
|
charges: None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
|
||||||
|
for Result<PaymentsResponseData, ErrorResponse>
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
response: payments_grpc::PaymentServiceRepeatEverythingResponse,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let status = AttemptStatus::foreign_try_from(response.status())?;
|
||||||
|
|
||||||
|
let connector_response_reference_id =
|
||||||
|
response.response_ref_id.as_ref().and_then(|identifier| {
|
||||||
|
identifier
|
||||||
|
.id_type
|
||||||
|
.clone()
|
||||||
|
.and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
|
||||||
|
Some(encoded_data)
|
||||||
|
}
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let transaction_id = response.transaction_id.as_ref().and_then(|id| {
|
||||||
|
id.id_type.clone().and_then(|id_type| match id_type {
|
||||||
|
payments_grpc::identifier::IdType::Id(id) => Some(id),
|
||||||
|
payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
|
||||||
|
payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = if response.error_code.is_some() {
|
||||||
|
Err(ErrorResponse {
|
||||||
|
code: response.error_code().to_owned(),
|
||||||
|
message: response.error_message().to_owned(),
|
||||||
|
reason: Some(response.error_message().to_owned()),
|
||||||
|
status_code: 500, //TODO: To be handled once UCS sends proper status codes
|
||||||
|
attempt_status: Some(status),
|
||||||
|
connector_transaction_id: transaction_id,
|
||||||
|
network_decline_code: None,
|
||||||
|
network_advice_code: None,
|
||||||
|
network_error_message: None,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(PaymentsResponseData::TransactionResponse {
|
||||||
|
resource_id: match transaction_id.as_ref() {
|
||||||
|
Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
|
||||||
|
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
|
||||||
|
},
|
||||||
|
redirection_data: Box::new(None),
|
||||||
|
mandate_reference: Box::new(None),
|
||||||
|
connector_metadata: None,
|
||||||
|
network_txn_id: response.network_txn_id.clone(),
|
||||||
|
connector_response_reference_id,
|
||||||
|
incremental_authorization_allowed: None,
|
||||||
|
charges: None,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ForeignTryFrom<common_enums::Currency> for payments_grpc::Currency {
|
impl ForeignTryFrom<common_enums::Currency> for payments_grpc::Currency {
|
||||||
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
@ -480,3 +919,48 @@ impl ForeignTryFrom<payments_grpc::HttpMethod> for Method {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<storage_enums::FutureUsage> for payments_grpc::FutureUsage {
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(future_usage: storage_enums::FutureUsage) -> Result<Self, Self::Error> {
|
||||||
|
match future_usage {
|
||||||
|
storage_enums::FutureUsage::OnSession => Ok(Self::OnSession),
|
||||||
|
storage_enums::FutureUsage::OffSession => Ok(Self::OffSession),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForeignTryFrom<common_types::payments::CustomerAcceptance>
|
||||||
|
for payments_grpc::CustomerAcceptance
|
||||||
|
{
|
||||||
|
type Error = error_stack::Report<UnifiedConnectorServiceError>;
|
||||||
|
|
||||||
|
fn foreign_try_from(
|
||||||
|
customer_acceptance: common_types::payments::CustomerAcceptance,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let acceptance_type = match customer_acceptance.acceptance_type {
|
||||||
|
common_types::payments::AcceptanceType::Online => payments_grpc::AcceptanceType::Online,
|
||||||
|
common_types::payments::AcceptanceType::Offline => {
|
||||||
|
payments_grpc::AcceptanceType::Offline
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let online_mandate_details =
|
||||||
|
customer_acceptance
|
||||||
|
.online
|
||||||
|
.map(|online| payments_grpc::OnlineMandate {
|
||||||
|
ip_address: online.ip_address.map(|ip| ip.peek().to_string()),
|
||||||
|
user_agent: online.user_agent,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
acceptance_type: acceptance_type.into(),
|
||||||
|
accepted_at: customer_acceptance
|
||||||
|
.accepted_at
|
||||||
|
.map(|dt| dt.assume_utc().unix_timestamp())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
online_mandate_details,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user