feat(router): collect customer address details based on business profile config regardless of connector required fields (#5418)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Shankar Singh C
2024-08-22 17:09:14 +05:30
committed by GitHub
parent d3521e7e76
commit bda29cb1b5
18 changed files with 597 additions and 726 deletions

View File

@ -3498,6 +3498,10 @@ impl BusinessProfileCreateBridge for api::BusinessProfileCreate {
.or(Some(false)),
outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers
.map(Into::into),
always_collect_billing_details_from_wallet_connector: self
.always_collect_billing_details_from_wallet_connector,
always_collect_shipping_details_from_wallet_connector: self
.always_collect_shipping_details_from_wallet_connector,
})
}
@ -3578,13 +3582,17 @@ impl BusinessProfileCreateBridge for api::BusinessProfileCreate {
.use_billing_as_payment_method_billing
.or(Some(true)),
collect_shipping_details_from_wallet_connector: self
.collect_shipping_details_from_wallet_connector
.collect_shipping_details_from_wallet_connector_if_required
.or(Some(false)),
collect_billing_details_from_wallet_connector: self
.collect_billing_details_from_wallet_connector
.collect_billing_details_from_wallet_connector_if_required
.or(Some(false)),
outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers
.map(Into::into),
always_collect_billing_details_from_wallet_connector: self
.always_collect_billing_details_from_wallet_connector,
always_collect_shipping_details_from_wallet_connector: self
.always_collect_shipping_details_from_wallet_connector,
routing_algorithm_id: None,
frm_routing_algorithm_id: None,
payout_routing_algorithm_id: None,
@ -3856,6 +3864,10 @@ impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate {
is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled,
outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers
.map(Into::into),
always_collect_billing_details_from_wallet_connector: self
.always_collect_billing_details_from_wallet_connector,
always_collect_shipping_details_from_wallet_connector: self
.always_collect_shipping_details_from_wallet_connector,
},
)))
}
@ -3934,9 +3946,9 @@ impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate {
extended_card_info_config,
use_billing_as_payment_method_billing: self.use_billing_as_payment_method_billing,
collect_shipping_details_from_wallet_connector: self
.collect_shipping_details_from_wallet_connector,
.collect_shipping_details_from_wallet_connector_if_required,
collect_billing_details_from_wallet_connector: self
.collect_billing_details_from_wallet_connector,
.collect_billing_details_from_wallet_connector_if_required,
is_connector_agnostic_mit_enabled: self.is_connector_agnostic_mit_enabled,
outgoing_webhook_custom_http_headers: outgoing_webhook_custom_http_headers
.map(Into::into),
@ -3944,6 +3956,10 @@ impl BusinessProfileUpdateBridge for api::BusinessProfileUpdate {
.order_fulfillment_time
.map(|order_fulfillment_time| order_fulfillment_time.into_inner()),
order_fulfillment_time_origin: self.order_fulfillment_time_origin,
always_collect_billing_details_from_wallet_connector: self
.always_collect_billing_details_from_wallet_connector,
always_collect_shipping_details_from_wallet_connector: self
.always_collect_shipping_details_from_wallet_connector,
},
)))
}

View File

@ -60,7 +60,10 @@ use crate::types::domain::types::AsyncLift;
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
use crate::utils::{self};
use crate::{
configs::settings,
configs::{
defaults::{get_billing_required_fields, get_shipping_required_fields},
settings,
},
core::{
errors::{self, StorageErrorExt},
payment_methods::{
@ -2898,29 +2901,12 @@ pub async fn list_payment_methods(
}
}
let should_send_shipping_details =
business_profile.clone().and_then(|business_profile| {
business_profile
.collect_shipping_details_from_wallet_connector
});
// Remove shipping fields from required fields based on business profile configuration
if should_send_shipping_details != Some(true) {
let shipping_variants =
api_enums::FieldType::get_shipping_variants();
let keys_to_be_removed = required_fields_hs
.iter()
.filter(|(_key, value)| {
shipping_variants.contains(&value.field_type)
})
.map(|(key, _value)| key.to_string())
.collect::<Vec<_>>();
keys_to_be_removed.iter().for_each(|key_to_be_removed| {
required_fields_hs.remove(key_to_be_removed);
});
}
required_fields_hs = should_collect_shipping_or_billing_details_from_wallet_connector(
&payment_method,
element.payment_experience.as_ref(),
business_profile.as_ref(),
required_fields_hs.clone(),
);
// get the config, check the enums while adding
{
@ -3271,11 +3257,22 @@ pub async fn list_payment_methods(
let collect_shipping_details_from_wallets = business_profile
.as_ref()
.and_then(|bp| bp.collect_shipping_details_from_wallet_connector);
.and_then(|business_profile| {
business_profile.always_collect_shipping_details_from_wallet_connector
})
.or(business_profile.as_ref().and_then(|business_profile| {
business_profile.collect_shipping_details_from_wallet_connector
}));
let collect_billing_details_from_wallets = business_profile
.as_ref()
.and_then(|bp| bp.collect_billing_details_from_wallet_connector);
.and_then(|business_profile| {
business_profile.always_collect_billing_details_from_wallet_connector
})
.or(business_profile.as_ref().and_then(|business_profile| {
business_profile.collect_billing_details_from_wallet_connector
}));
Ok(services::ApplicationResponse::Json(
api::PaymentMethodListResponse {
redirect_url: business_profile
@ -3320,6 +3317,37 @@ pub async fn list_payment_methods(
))
}
fn should_collect_shipping_or_billing_details_from_wallet_connector(
payment_method: &api_enums::PaymentMethod,
payment_experience_optional: Option<&api_enums::PaymentExperience>,
business_profile: Option<&BusinessProfile>,
mut required_fields_hs: HashMap<String, RequiredFieldInfo>,
) -> HashMap<String, RequiredFieldInfo> {
match (payment_method, payment_experience_optional) {
(api_enums::PaymentMethod::Wallet, Some(api_enums::PaymentExperience::InvokeSdkClient)) => {
let always_send_billing_details = business_profile.and_then(|business_profile| {
business_profile.always_collect_billing_details_from_wallet_connector
});
let always_send_shipping_details = business_profile.and_then(|business_profile| {
business_profile.always_collect_shipping_details_from_wallet_connector
});
if always_send_billing_details == Some(true) {
let billing_details = get_billing_required_fields();
required_fields_hs.extend(billing_details)
};
if always_send_shipping_details == Some(true) {
let shipping_details = get_shipping_required_fields();
required_fields_hs.extend(shipping_details)
};
required_fields_hs
}
_ => required_fields_hs,
}
}
async fn validate_payment_method_and_client_secret(
cs: &String,
db: &dyn db::StorageInterface,

View File

@ -316,43 +316,61 @@ async fn create_applepay_session_token(
router_data.request.to_owned(),
)?;
let required_billing_contact_fields = business_profile
let required_billing_contact_fields = if business_profile
.always_collect_billing_details_from_wallet_connector
.unwrap_or(false)
{
Some(payment_types::ApplePayBillingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
]))
} else if business_profile
.collect_billing_details_from_wallet_connector
.unwrap_or(false)
.then_some({
let billing_variants = enums::FieldType::get_billing_variants();
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::ApplePay,
&connector.connector_name,
billing_variants,
)
.then_some(payment_types::ApplePayBillingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
]))
})
.flatten();
{
let billing_variants = enums::FieldType::get_billing_variants();
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::ApplePay,
&connector.connector_name,
billing_variants,
)
.then_some(payment_types::ApplePayBillingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
]))
} else {
None
};
let required_shipping_contact_fields = business_profile
let required_shipping_contact_fields = if business_profile
.always_collect_shipping_details_from_wallet_connector
.unwrap_or(false)
{
Some(payment_types::ApplePayShippingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
payment_types::ApplePayAddressParameters::Phone,
payment_types::ApplePayAddressParameters::Email,
]))
} else if business_profile
.collect_shipping_details_from_wallet_connector
.unwrap_or(false)
.then_some({
let shipping_variants = enums::FieldType::get_shipping_variants();
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::ApplePay,
&connector.connector_name,
shipping_variants,
)
.then_some(payment_types::ApplePayShippingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
payment_types::ApplePayAddressParameters::Phone,
payment_types::ApplePayAddressParameters::Email,
]))
})
.flatten();
{
let shipping_variants = enums::FieldType::get_shipping_variants();
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::ApplePay,
&connector.connector_name,
shipping_variants,
)
.then_some(payment_types::ApplePayShippingContactFields(vec![
payment_types::ApplePayAddressParameters::PostalAddress,
payment_types::ApplePayAddressParameters::Phone,
payment_types::ApplePayAddressParameters::Email,
]))
} else {
None
};
// If collect_shipping_details_from_wallet_connector is false, we check if
// collect_billing_details_from_wallet_connector is true. If it is, then we pass the Email and Phone in
@ -655,20 +673,27 @@ fn create_gpay_session_token(
expected_format: "gpay_metadata_format".to_string(),
})?;
let is_billing_details_required =
if business_profile.collect_billing_details_from_wallet_connector == Some(true) {
let billing_variants = enums::FieldType::get_billing_variants();
let always_collect_billing_details_from_wallet_connector = business_profile
.always_collect_billing_details_from_wallet_connector
.unwrap_or(false);
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::GooglePay,
&connector.connector_name,
billing_variants,
)
} else {
false
};
let is_billing_details_required = if always_collect_billing_details_from_wallet_connector {
always_collect_billing_details_from_wallet_connector
} else if business_profile
.collect_billing_details_from_wallet_connector
.unwrap_or(false)
{
let billing_variants = enums::FieldType::get_billing_variants();
is_dynamic_fields_required(
&state.conf.required_fields,
enums::PaymentMethod::Wallet,
enums::PaymentMethodType::GooglePay,
&connector.connector_name,
billing_variants,
)
} else {
false
};
let billing_address_parameters =
is_billing_details_required.then_some(payment_types::GpayBillingAddressParameters {
@ -708,8 +733,17 @@ fn create_gpay_session_token(
total_price: google_pay_amount,
};
let always_collect_shipping_details_from_wallet_connector = business_profile
.always_collect_shipping_details_from_wallet_connector
.unwrap_or(false);
let required_shipping_contact_fields =
if business_profile.collect_shipping_details_from_wallet_connector == Some(true) {
if always_collect_shipping_details_from_wallet_connector {
true
} else if business_profile
.collect_shipping_details_from_wallet_connector
.unwrap_or(false)
{
let shipping_variants = enums::FieldType::get_shipping_variants();
is_dynamic_fields_required(

View File

@ -18,6 +18,7 @@ use crate::{
connector::{Helcim, Nexinets},
core::{
errors::{self, RouterResponse, RouterResult},
payment_methods::cards::decrypt_generic_data,
payments::{self, helpers},
utils as core_utils,
},
@ -25,8 +26,8 @@ use crate::{
routes::{metrics, SessionState},
services::{self, RedirectForm},
types::{
self, api,
api::ConnectorTransactionId,
self,
api::{self, ConnectorTransactionId},
domain,
storage::{self, enums},
transformers::{ForeignFrom, ForeignInto, ForeignTryFrom},
@ -137,14 +138,13 @@ where
let unified_address =
if let Some(payment_method_info) = payment_data.payment_method_info.clone() {
let payment_method_billing =
crate::core::payment_methods::cards::decrypt_generic_data::<Address>(
state,
payment_method_info.payment_method_billing_address,
key_store,
)
.await
.attach_printable("unable to decrypt payment method billing address details")?;
let payment_method_billing = decrypt_generic_data::<Address>(
state,
payment_method_info.payment_method_billing_address,
key_store,
)
.await
.attach_printable("unable to decrypt payment method billing address details")?;
payment_data
.address
.clone()