feat(ucs): Add profile ID to lineage tracking in Unified Connector Service (#9559)

This commit is contained in:
Hrithikesh
2025-09-30 12:24:12 +05:30
committed by GitHub
parent c90744a6aa
commit 7654dbf436
11 changed files with 141 additions and 68 deletions

View File

@ -167,9 +167,9 @@ pub struct GrpcHeadersUcs {
/// Type aliase for GrpcHeaders builder in initial stage
pub type GrpcHeadersUcsBuilderInitial = GrpcHeadersUcsBuilder<((String,), (), (), ())>;
/// Type aliase for GrpcHeaders builder in intermediate stage
pub type GrpcHeadersUcsBuilderIntermediate = GrpcHeadersUcsBuilder<(
pub type GrpcHeadersUcsBuilderFinal = GrpcHeadersUcsBuilder<(
(String,),
(),
(LineageIds,),
(Option<String>,),
(Option<ucs_types::UcsReferenceId>,),
)>;
@ -178,11 +178,15 @@ pub type GrpcHeadersUcsBuilderIntermediate = GrpcHeadersUcsBuilder<(
#[derive(Debug, serde::Serialize)]
pub struct LineageIds {
merchant_id: id_type::MerchantId,
profile_id: id_type::ProfileId,
}
impl LineageIds {
/// constructor for LineageIds
pub fn new(merchant_id: id_type::MerchantId) -> Self {
Self { merchant_id }
pub fn new(merchant_id: id_type::MerchantId, profile_id: id_type::ProfileId) -> Self {
Self {
merchant_id,
profile_id,
}
}
/// get url encoded string representation of LineageIds
pub fn get_url_encoded_string(self) -> Result<String, serde_urlencoded::ser::Error> {

View File

@ -11,7 +11,6 @@ pub enum MerchantContext {
/// Represents a normal operation merchant context.
NormalMerchant(Box<Context>),
}
/// `Context` holds the merchant account details and cryptographic key store.
#[derive(Clone, Debug)]
pub struct Context(pub MerchantAccount, pub MerchantKeyStore);

View File

@ -95,14 +95,11 @@ impl VaultMetadataProcessor for VgsMetadata {
cert_content
} else {
match BASE64_ENGINE.decode(&cert_content) {
Ok(decoded_bytes) => {
let decoded_string = String::from_utf8(decoded_bytes).map_err(|e| {
Ok(decoded_bytes) => String::from_utf8(decoded_bytes).map_err(|e| {
VaultMetadataError::CertificateValidationFailed(format!(
"Certificate is not valid UTF-8 after base64 decoding: {e}"
))
})?;
decoded_string
}
})?,
Err(e) => {
logger::error!(
error = %e,

View File

@ -2,10 +2,10 @@ pub mod opensearch;
#[cfg(feature = "olap")]
pub mod user;
pub mod user_role;
use std::collections::HashSet;
use std::{collections::HashSet, str::FromStr, sync};
use api_models::enums::Country;
use common_utils::consts;
use common_utils::{consts, id_type};
pub use hyperswitch_domain_models::consts::{
CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH, ROUTING_ENABLED_PAYMENT_METHODS,
ROUTING_ENABLED_PAYMENT_METHOD_TYPES,
@ -274,6 +274,12 @@ pub const IRRELEVANT_PAYMENT_INTENT_ID: &str = "irrelevant_payment_intent_id";
/// Default payment attempt id
pub const IRRELEVANT_PAYMENT_ATTEMPT_ID: &str = "irrelevant_payment_attempt_id";
pub static PROFILE_ID_UNAVAILABLE: sync::LazyLock<id_type::ProfileId> = sync::LazyLock::new(|| {
#[allow(clippy::expect_used)]
id_type::ProfileId::from_str("PROFILE_ID_UNAVAIABLE")
.expect("Failed to parse PROFILE_ID_UNAVAIABLE")
});
/// Default payment attempt id
pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID: &str =
"irrelevant_connector_request_reference_id";
@ -332,3 +338,15 @@ pub const UCS_AUTH_CURRENCY_AUTH_KEY: &str = "currency-auth-key";
/// Form field name for challenge request during creq submission
pub const CREQ_CHALLENGE_REQUEST_KEY: &str = "creq";
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
#[test]
fn test_profile_id_unavailable_initialization() {
// Just access the lazy static to ensure it doesn't panic during initialization
let _profile_id = super::PROFILE_ID_UNAVAILABLE.clone();
// If we get here without panicking, the test passes
}
}

View File

@ -22,6 +22,8 @@ use std::{
vec::IntoIter,
};
use external_services::grpc_client;
#[cfg(feature = "v2")]
pub mod payment_methods;
@ -4306,10 +4308,15 @@ where
header_payload.clone(),
)
.await?;
let lineage_ids = grpc_client::LineageIds::new(
business_profile.merchant_id.clone(),
business_profile.get_id().clone(),
);
router_data
.call_unified_connector_service(
state,
&header_payload,
lineage_ids,
merchant_connector_account.clone(),
merchant_context,
)
@ -4845,10 +4852,13 @@ where
payment_data.get_payment_intent().id.get_string_repr(),
payment_data.get_payment_attempt().id.get_string_repr()
);
let lineage_ids = grpc_client::LineageIds::new(business_profile.merchant_id.clone(), business_profile.get_id().clone());
router_data
.call_unified_connector_service(
state,
&header_payload,
lineage_ids,
merchant_connector_account_type_details.clone(),
merchant_context,
)
@ -4942,10 +4952,15 @@ where
header_payload.clone(),
)
.await?;
let lineage_ids = grpc_client::LineageIds::new(
business_profile.merchant_id.clone(),
business_profile.get_id().clone(),
);
router_data
.call_unified_connector_service(
state,
&header_payload,
lineage_ids,
merchant_connector_account_type_details.clone(),
merchant_context,
)
@ -5000,7 +5015,7 @@ pub async fn call_unified_connector_service_for_external_proxy<F, RouterDReq, Ap
_schedule_time: Option<time::PrimitiveDateTime>,
header_payload: HeaderPayload,
frm_suggestion: Option<storage_enums::FrmSuggestion>,
_business_profile: &domain::Profile,
business_profile: &domain::Profile,
_is_retry_payment: bool,
_should_retry_with_pan: bool,
_return_raw_connector_response: Option<bool>,
@ -5036,10 +5051,15 @@ where
header_payload.clone(),
)
.await?;
let lineage_ids = grpc_client::LineageIds::new(
business_profile.merchant_id.clone(),
business_profile.get_id().clone(),
);
router_data
.call_unified_connector_service_with_external_vault_proxy(
state,
&header_payload,
lineage_ids,
merchant_connector_account_type_details.clone(),
external_vault_merchant_connector_account_type_details.clone(),
merchant_context,

View File

@ -17,11 +17,14 @@ pub mod update_metadata_flow;
use async_trait::async_trait;
use common_types::payments::CustomerAcceptance;
use external_services::grpc_client;
#[cfg(all(feature = "v2", feature = "revenue_recovery"))]
use hyperswitch_domain_models::router_flow_types::{
BillingConnectorInvoiceSync, BillingConnectorPaymentsSync, InvoiceRecordBack,
};
use hyperswitch_domain_models::router_request_types::PaymentsCaptureData;
use hyperswitch_domain_models::{
payments as domain_payments, router_request_types::PaymentsCaptureData,
};
use crate::{
core::{
@ -46,7 +49,7 @@ pub trait ConstructFlowSpecificData<F, Req, Res> {
customer: &Option<domain::Customer>,
merchant_connector_account: &helpers::MerchantConnectorAccountType,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<types::RouterData<F, Req, Res>>;
#[cfg(feature = "v2")]
@ -58,7 +61,7 @@ pub trait ConstructFlowSpecificData<F, Req, Res> {
_customer: &Option<domain::Customer>,
_merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
_merchant_recipient_data: Option<types::MerchantRecipientData>,
_header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
_header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<types::RouterData<F, Req, Res>>;
async fn get_merchant_recipient_data<'a>(
@ -82,7 +85,7 @@ pub trait Feature<F, T> {
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
business_profile: &domain::Profile,
header_payload: hyperswitch_domain_models::payments::HeaderPayload,
header_payload: domain_payments::HeaderPayload,
return_raw_connector_response: Option<bool>,
) -> RouterResult<Self>
where
@ -206,6 +209,8 @@ pub trait Feature<F, T> {
async fn call_unified_connector_service<'a>(
&mut self,
_state: &SessionState,
_header_payload: &domain_payments::HeaderPayload,
_lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] _merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")]
_merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
@ -223,6 +228,8 @@ pub trait Feature<F, T> {
async fn call_unified_connector_service_with_external_vault_proxy<'a>(
&mut self,
_state: &SessionState,
_header_payload: &domain_payments::HeaderPayload,
_lineage_ids: grpc_client::LineageIds,
_merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
_external_vault_merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
_merchant_context: &domain::MerchantContext,
@ -278,7 +285,7 @@ pub async fn call_capture_request(
connector: &api::ConnectorData,
call_connector_action: payments::CallConnectorAction,
business_profile: &domain::Profile,
header_payload: hyperswitch_domain_models::payments::HeaderPayload,
header_payload: domain_payments::HeaderPayload,
) -> RouterResult<types::RouterData<api::Capture, PaymentsCaptureData, types::PaymentsResponseData>>
{
// Build capture-specific connector request

View File

@ -5,9 +5,12 @@ use common_enums as enums;
use common_types::payments as common_payments_types;
use common_utils::{id_type, ucs_types};
use error_stack::ResultExt;
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;
use external_services::grpc_client;
#[cfg(feature = "v2")]
use hyperswitch_domain_models::payments::PaymentConfirmData;
use hyperswitch_domain_models::{
errors::api_error_response::ApiErrorResponse, payments as domain_payments,
};
use masking::{ExposeInterface, Secret};
use unified_connector_service_client::payments as payments_grpc;
@ -53,7 +56,7 @@ impl
customer: &Option<domain::Customer>,
merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<
types::RouterData<
api::Authorize,
@ -118,7 +121,7 @@ impl
customer: &Option<domain::Customer>,
merchant_connector_account: &helpers::MerchantConnectorAccountType,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<
types::RouterData<
api::Authorize,
@ -183,7 +186,7 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
business_profile: &domain::Profile,
header_payload: hyperswitch_domain_models::payments::HeaderPayload,
header_payload: domain_payments::HeaderPayload,
return_raw_connector_response: Option<bool>,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
@ -520,6 +523,8 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
async fn call_unified_connector_service<'a>(
&mut self,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")]
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
@ -529,6 +534,8 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
Box::pin(call_unified_connector_service_repeat_payment(
self,
state,
header_payload,
lineage_ids,
merchant_connector_account,
merchant_context,
))
@ -537,6 +544,8 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
Box::pin(call_unified_connector_service_authorize(
self,
state,
header_payload,
lineage_ids,
merchant_connector_account,
merchant_context,
))
@ -799,7 +808,7 @@ async fn process_capture_flow(
connector: &api::ConnectorData,
call_connector_action: payments::CallConnectorAction,
business_profile: &domain::Profile,
header_payload: hyperswitch_domain_models::payments::HeaderPayload,
header_payload: domain_payments::HeaderPayload,
) -> RouterResult<
types::RouterData<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>,
> {
@ -836,6 +845,8 @@ async fn call_unified_connector_service_authorize(
types::PaymentsResponseData,
>,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
merchant_context: &domain::MerchantContext,
@ -856,10 +867,9 @@ async fn call_unified_connector_service_authorize(
build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to construct request metadata")?;
let merchant_order_reference_id = router_data
.header_payload
.as_ref()
.and_then(|payload| payload.x_reference_id.clone())
let merchant_order_reference_id = header_payload
.x_reference_id
.clone()
.map(|id| id_type::PaymentReferenceId::from_str(id.as_str()))
.transpose()
.inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found"))
@ -869,7 +879,8 @@ async fn call_unified_connector_service_authorize(
let headers_builder = state
.get_grpc_headers_ucs()
.external_vault_proxy_metadata(None)
.merchant_reference_id(merchant_order_reference_id);
.merchant_reference_id(merchant_order_reference_id)
.lineage_ids(lineage_ids);
let updated_router_data = Box::pin(ucs_logging_wrapper(
router_data.clone(),
state,
@ -923,6 +934,8 @@ async fn call_unified_connector_service_repeat_payment(
types::PaymentsResponseData,
>,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
merchant_context: &domain::MerchantContext,
@ -943,10 +956,9 @@ async fn call_unified_connector_service_repeat_payment(
build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to construct request metadata")?;
let merchant_order_reference_id = router_data
.header_payload
.as_ref()
.and_then(|payload| payload.x_reference_id.clone())
let merchant_order_reference_id = header_payload
.x_reference_id
.clone()
.map(|id| id_type::PaymentReferenceId::from_str(id.as_str()))
.transpose()
.inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found"))
@ -956,7 +968,8 @@ async fn call_unified_connector_service_repeat_payment(
let headers_builder = state
.get_grpc_headers_ucs()
.external_vault_proxy_metadata(None)
.merchant_reference_id(merchant_order_reference_id);
.merchant_reference_id(merchant_order_reference_id)
.lineage_ids(lineage_ids);
let updated_router_data = Box::pin(ucs_logging_wrapper(
router_data.clone(),
state,

View File

@ -4,9 +4,12 @@ use async_trait::async_trait;
use common_enums as enums;
use common_utils::{id_type, ucs_types, ucs_types::UcsReferenceId};
use error_stack::ResultExt;
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;
use external_services::grpc_client;
#[cfg(feature = "v2")]
use hyperswitch_domain_models::payments::PaymentConfirmData;
use hyperswitch_domain_models::{
errors::api_error_response::ApiErrorResponse, payments as domain_payments,
};
use masking::ExposeInterface;
use unified_connector_service_client::payments as payments_grpc;
@ -47,7 +50,7 @@ impl
customer: &Option<domain::Customer>,
merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<
types::RouterData<
api::ExternalVaultProxy,
@ -82,7 +85,7 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
business_profile: &domain::Profile,
header_payload: hyperswitch_domain_models::payments::HeaderPayload,
header_payload: domain_payments::HeaderPayload,
return_raw_connector_response: Option<bool>,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
@ -366,6 +369,8 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
async fn call_unified_connector_service_with_external_vault_proxy<'a>(
&mut self,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
external_vault_merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
merchant_context: &domain::MerchantContext,
@ -396,10 +401,9 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to construct external vault proxy metadata")?;
let merchant_order_reference_id = self
.header_payload
.as_ref()
.and_then(|payload| payload.x_reference_id.clone())
let merchant_order_reference_id = header_payload
.x_reference_id
.clone()
.map(|id| id_type::PaymentReferenceId::from_str(id.as_str()))
.transpose()
.inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found"))
@ -409,7 +413,8 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
let headers_builder = state
.get_grpc_headers_ucs()
.external_vault_proxy_metadata(Some(external_vault_proxy_metadata))
.merchant_reference_id(merchant_order_reference_id);
.merchant_reference_id(merchant_order_reference_id)
.lineage_ids(lineage_ids);
let updated_router_data = Box::pin(ucs_logging_wrapper(
self.clone(),
state,

View File

@ -3,6 +3,8 @@ use std::{collections::HashMap, str::FromStr};
use async_trait::async_trait;
use common_utils::{id_type, ucs_types};
use error_stack::ResultExt;
use external_services::grpc_client;
use hyperswitch_domain_models::payments as domain_payments;
use masking::Secret;
use unified_connector_service_client::payments as payments_grpc;
@ -35,7 +37,7 @@ impl ConstructFlowSpecificData<api::PSync, types::PaymentsSyncData, types::Payme
customer: &Option<domain::Customer>,
merchant_connector_account: &helpers::MerchantConnectorAccountType,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<
types::RouterData<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>,
> {
@ -69,7 +71,7 @@ impl ConstructFlowSpecificData<api::PSync, types::PaymentsSyncData, types::Payme
customer: &Option<domain::Customer>,
merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<
types::RouterData<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>,
> {
@ -98,7 +100,7 @@ impl Feature<api::PSync, types::PaymentsSyncData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &domain::Profile,
_header_payload: hyperswitch_domain_models::payments::HeaderPayload,
_header_payload: domain_payments::HeaderPayload,
return_raw_connector_response: Option<bool>,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
@ -222,6 +224,8 @@ impl Feature<api::PSync, types::PaymentsSyncData>
async fn call_unified_connector_service<'a>(
&mut self,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")]
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
@ -267,10 +271,9 @@ impl Feature<api::PSync, types::PaymentsSyncData>
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to construct request metadata")?;
let merchant_reference_id = self
.header_payload
.as_ref()
.and_then(|payload| payload.x_reference_id.clone())
let merchant_reference_id = header_payload
.x_reference_id
.clone()
.map(|id| id_type::PaymentReferenceId::from_str(id.as_str()))
.transpose()
.inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found"))
@ -280,7 +283,8 @@ impl Feature<api::PSync, types::PaymentsSyncData>
let header_payload = state
.get_grpc_headers_ucs()
.external_vault_proxy_metadata(None)
.merchant_reference_id(merchant_reference_id);
.merchant_reference_id(merchant_reference_id)
.lineage_ids(lineage_ids);
let updated_router_data = Box::pin(ucs_logging_wrapper(
self.clone(),
state,

View File

@ -4,6 +4,8 @@ use async_trait::async_trait;
use common_types::payments as common_payments_types;
use common_utils::{id_type, ucs_types};
use error_stack::ResultExt;
use external_services::grpc_client;
use hyperswitch_domain_models::payments as domain_payments;
use router_env::logger;
use unified_connector_service_client::payments as payments_grpc;
@ -45,7 +47,7 @@ impl
customer: &Option<domain::Customer>,
merchant_connector_account: &helpers::MerchantConnectorAccountType,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<types::SetupMandateRouterData> {
Box::pin(transformers::construct_payment_router_data::<
api::SetupMandate,
@ -81,7 +83,7 @@ impl
customer: &Option<domain::Customer>,
merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
merchant_recipient_data: Option<types::MerchantRecipientData>,
header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
header_payload: Option<domain_payments::HeaderPayload>,
) -> RouterResult<types::SetupMandateRouterData> {
Box::pin(
transformers::construct_payment_router_data_for_setup_mandate(
@ -108,7 +110,7 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &domain::Profile,
_header_payload: hyperswitch_domain_models::payments::HeaderPayload,
_header_payload: domain_payments::HeaderPayload,
_return_raw_connector_response: Option<bool>,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
@ -262,6 +264,8 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
async fn call_unified_connector_service<'a>(
&mut self,
state: &SessionState,
header_payload: &domain_payments::HeaderPayload,
lineage_ids: grpc_client::LineageIds,
#[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
#[cfg(feature = "v2")]
merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
@ -285,10 +289,9 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to construct request metadata")?;
let merchant_reference_id = self
.header_payload
.as_ref()
.and_then(|payload| payload.x_reference_id.clone())
let merchant_reference_id = header_payload
.x_reference_id
.clone()
.map(|id| id_type::PaymentReferenceId::from_str(id.as_str()))
.transpose()
.inspect_err(|err| logger::warn!(error=?err, "Invalid Merchant ReferenceId found"))
@ -298,7 +301,8 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
let header_payload = state
.get_grpc_headers_ucs()
.external_vault_proxy_metadata(None)
.merchant_reference_id(merchant_reference_id);
.merchant_reference_id(merchant_reference_id)
.lineage_ids(lineage_ids);
let updated_router_data = Box::pin(ucs_logging_wrapper(
self.clone(),
state,

View File

@ -740,12 +740,16 @@ pub async fn call_unified_connector_service_for_webhook(
"Missing merchant connector account for UCS webhook transformation",
)
})?;
let profile_id = merchant_connector_account
.as_ref()
.map(|mca| mca.profile_id.clone())
.unwrap_or(consts::PROFILE_ID_UNAVAILABLE.clone());
// Build gRPC headers
let grpc_headers = state
.get_grpc_headers_ucs()
.lineage_ids(LineageIds::new(
merchant_context.get_merchant_account().get_id().clone(),
profile_id,
))
.external_vault_proxy_metadata(None)
.merchant_reference_id(None)
@ -791,7 +795,7 @@ pub async fn ucs_logging_wrapper<T, F, Fut, Req, Resp, GrpcReq, GrpcResp>(
router_data: RouterData<T, Req, Resp>,
state: &SessionState,
grpc_request: GrpcReq,
grpc_header_builder: external_services::grpc_client::GrpcHeadersUcsBuilderIntermediate,
grpc_header_builder: external_services::grpc_client::GrpcHeadersUcsBuilderFinal,
handler: F,
) -> RouterResult<RouterData<T, Req, Resp>>
where
@ -818,9 +822,7 @@ where
let merchant_id = router_data.merchant_id.clone();
let refund_id = router_data.refund_id.clone();
let dispute_id = router_data.dispute_id.clone();
let grpc_header = grpc_header_builder
.lineage_ids(LineageIds::new(merchant_id.clone()))
.build();
let grpc_header = grpc_header_builder.build();
// Log the actual gRPC request with masking
let grpc_request_body = masking::masked_serialize(&grpc_request)
.unwrap_or_else(|_| serde_json::json!({"error": "failed_to_serialize_grpc_request"}));