From c85b4a3a273ea211084ed26b1eb77f0731ac35ca Mon Sep 17 00:00:00 2001 From: AkshayaFoiger <131388445+AkshayaFoiger@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:45:05 +0530 Subject: [PATCH] fix(router): [Stripe/Itau/Paypal/Bambora/Cybs] prevent partial submission of billing address and add required fields for all payment methods (#5704) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- .../src/connectors/bambora/transformers.rs | 48 +- crates/router/src/configs/defaults.rs | 713 ++++++++++++++++-- .../src/connector/cybersource/transformers.rs | 26 +- .../src/connector/paypal/transformers.rs | 41 +- crates/router/src/connector/stripe.rs | 2 + .../src/connector/stripe/transformers.rs | 156 ++-- crates/router/src/connector/utils.rs | 4 + 7 files changed, 797 insertions(+), 193 deletions(-) diff --git a/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs index 8499aecaed77..b47c741c8d5c 100644 --- a/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs @@ -1,6 +1,9 @@ use base64::Engine; use common_enums::enums; -use common_utils::{ext_traits::ValueExt, pii::IpAddress}; +use common_utils::{ + ext_traits::ValueExt, + pii::{Email, IpAddress}, +}; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::PaymentMethodData, @@ -86,6 +89,7 @@ pub struct BamboraPaymentsRequest { customer_ip: Option>, term_url: Option, card: BamboraCard, + billing: AddressData, } #[derive(Default, Debug, Serialize)] @@ -173,6 +177,29 @@ impl TryFrom> for Bambora complete: item.router_data.request.is_auto_capture()?, }; + let province = item + .router_data + .get_optional_billing_state() + .and_then(|state| { + if state.clone().expose().len() > 2 { + None + } else { + Some(state) + } + }); + + let billing = AddressData { + name: item.router_data.get_optional_billing_full_name(), + address_line1: item.router_data.get_optional_billing_line1(), + address_line2: item.router_data.get_optional_billing_line2(), + city: item.router_data.get_optional_billing_city(), + province, + country: item.router_data.get_optional_billing_country(), + postal_code: item.router_data.get_optional_billing_zip(), + phone_number: item.router_data.get_optional_billing_phone_number(), + email_address: item.router_data.get_optional_billing_email(), + }; + Ok(Self { order_number: item.router_data.connector_request_reference_id.clone(), amount: item.amount, @@ -180,6 +207,7 @@ impl TryFrom> for Bambora card, customer_ip, term_url: item.router_data.request.complete_authorize_url.clone(), + billing, }) } PaymentMethodData::CardRedirect(_) @@ -342,15 +370,15 @@ pub struct AvsObject { #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct AddressData { - name: Secret, - address_line1: Secret, - address_line2: Secret, - city: String, - province: String, - country: String, - postal_code: Secret, - phone_number: Secret, - email_address: Secret, + name: Option>, + address_line1: Option>, + address_line2: Option>, + city: Option, + province: Option>, + country: Option, + postal_code: Option>, + phone_number: Option>, + email_address: Option, } #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)] diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs index 9a2af153ee6e..3031b8c002ea 100644 --- a/crates/router/src/configs/defaults.rs +++ b/crates/router/src/configs/defaults.rs @@ -527,6 +527,15 @@ impl Default for super::settings::RequiredFields { value: None, } ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) ] ), common: HashMap::new(), @@ -999,9 +1008,9 @@ impl Default for super::settings::RequiredFields { } ), ( - "email".to_string(), + "billing.email".to_string(), RequiredFieldInfo { - required_field: "email".to_string(), + required_field: "payment_method_data.billing.email".to_string(), display_name: "email".to_string(), field_type: enums::FieldType::UserEmailAddress, value: None, @@ -3343,6 +3352,15 @@ impl Default for super::settings::RequiredFields { value: None, } ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) ] ), common: HashMap::new(), @@ -3815,9 +3833,9 @@ impl Default for super::settings::RequiredFields { } ), ( - "email".to_string(), + "billing.email".to_string(), RequiredFieldInfo { - required_field: "email".to_string(), + required_field: "payment_method_data.billing.email".to_string(), display_name: "email".to_string(), field_type: enums::FieldType::UserEmailAddress, value: None, @@ -6127,7 +6145,17 @@ impl Default for super::settings::RequiredFields { enums::Connector::Stripe, RequiredFieldFinal { mandate: HashMap::new(), - non_mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), common: HashMap::new(), } )]), @@ -6148,9 +6176,7 @@ impl Default for super::settings::RequiredFields { ( enums::Connector::Stripe, RequiredFieldFinal { - mandate: HashMap::new(), - non_mandate: HashMap::new(), - common: HashMap::from([ + mandate: HashMap::from([ ( "billing.email".to_string(), RequiredFieldInfo { @@ -6159,7 +6185,10 @@ impl Default for super::settings::RequiredFields { field_type: enums::FieldType::UserEmailAddress, value: None, } - ), + ) + ]), + non_mandate: HashMap::new(), + common: HashMap::from([ ( "billing.address.first_name".to_string(), RequiredFieldInfo { @@ -6979,27 +7008,10 @@ impl Default for super::settings::RequiredFields { field_type: enums::FieldType::UserEmailAddress, value: None, } - ), - ( - "billing.address.first_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.first_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } - ), - ( - "billing.address.last_name".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.billing.address.last_name".to_string(), - display_name: "billing_name".to_string(), - field_type: enums::FieldType::UserBillingName, - value: None, - } ) ]), - non_mandate : HashMap::from([ + non_mandate : HashMap::new(), + common: HashMap::from([ ("billing.address.country".to_string(), RequiredFieldInfo { required_field: "payment_method_data.billing.address.country".to_string(), @@ -7015,10 +7027,25 @@ impl Default for super::settings::RequiredFields { }, value: None, } - )]), - common: HashMap::new( - ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "account_holder_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "account_holder_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + )]), } ), ( @@ -7590,9 +7617,9 @@ impl Default for super::settings::RequiredFields { non_mandate: HashMap::from( [ ( - "email".to_string(), + "billing.email".to_string(), RequiredFieldInfo { - required_field: "email".to_string(), + required_field: "payment_method_data.billing.email".to_string(), display_name: "email".to_string(), field_type: enums::FieldType::UserEmailAddress, value: None, @@ -8074,9 +8101,9 @@ impl Default for super::settings::RequiredFields { non_mandate: HashMap::from( [ ( - "email".to_string(), + "billing.email".to_string(), RequiredFieldInfo { - required_field: "email".to_string(), + required_field: "payment_method_data.billing.email".to_string(), display_name: "email".to_string(), field_type: enums::FieldType::UserEmailAddress, value: None, @@ -8404,6 +8431,21 @@ impl Default for super::settings::RequiredFields { ]), }, ), + ( + enums::PaymentMethodType::Cashapp, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::new(), + } + ) + ]), + }, + ), ( enums::PaymentMethodType::MbWay, ConnectorFields { @@ -8595,8 +8637,7 @@ impl Default for super::settings::RequiredFields { enums::Connector::Paypal, RequiredFieldFinal { mandate: HashMap::new(), - non_mandate: HashMap::new( - ), + non_mandate: HashMap::new(), common: HashMap::new(), } ), @@ -8809,20 +8850,153 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate : HashMap::new(), non_mandate: HashMap::from([ - ( "name".to_string(), + ( + "billing.email".to_string(), RequiredFieldInfo { - required_field: "name".to_string(), - display_name: "cust_name".to_string(), - field_type: enums::FieldType::UserFullName, - value: None, - }), - ("payment_method_data.pay_later.afterpay_clearpay_redirect.billing_email".to_string(), - RequiredFieldInfo { - required_field: "payment_method_data.pay_later.afterpay_clearpay_redirect.billing_email".to_string(), - display_name: "billing_email".to_string(), - field_type: enums::FieldType::UserEmailAddress, - value: None, - }) + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "billing_last_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + } + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + } + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry{ + options: vec![ + "GB".to_string(), + "AU".to_string(), + "CA".to_string(), + "US".to_string(), + "NZ".to_string(), + ] + }, + value: None, + } + ), + ( + "billing.address.state".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserAddressState, + value: None, + } + ), + ( + "shipping.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.first_name".to_string(), + display_name: "shipping_first_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.last_name".to_string(), + display_name: "shipping_last_name".to_string(), + field_type: enums::FieldType::UserShippingName, + value: None, + } + ), + ( + "shipping.address.city".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserShippingAddressCity, + value: None, + } + ), + ( + "shipping.address.state".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.state".to_string(), + display_name: "state".to_string(), + field_type: enums::FieldType::UserShippingAddressState, + value: None, + } + ), + ( + "shipping.address.zip".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserShippingAddressPincode, + value: None, + } + ), + ( + "shipping.address.country".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserShippingAddressCountry{ + options: vec![ + "ALL".to_string(), + ] + }, + value: None, + } + ), + ( + "shipping.address.line1".to_string(), + RequiredFieldInfo { + required_field: "shipping.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserShippingAddressLine1, + value: None, + } + ), ]), common : HashMap::new(), } @@ -8995,11 +9169,33 @@ impl Default for super::settings::RequiredFields { required_field: "payment_method_data.pay_later.klarna.billing_country".to_string(), display_name: "billing_country".to_string(), field_type: enums::FieldType::UserAddressCountry{ - options: vec![ - "ALL".to_string(), - ] - }, - value: None, + options: vec![ + "AU".to_string(), + "AT".to_string(), + "BE".to_string(), + "CA".to_string(), + "CZ".to_string(), + "DK".to_string(), + "FI".to_string(), + "FR".to_string(), + "GR".to_string(), + "DE".to_string(), + "IE".to_string(), + "IT".to_string(), + "NL".to_string(), + "NZ".to_string(), + "NO".to_string(), + "PL".to_string(), + "PT".to_string(), + "RO".to_string(), + "ES".to_string(), + "SE".to_string(), + "CH".to_string(), + "GB".to_string(), + "US".to_string(), + ] + }, + value: None, }), ("email".to_string(), RequiredFieldInfo { @@ -10262,7 +10458,7 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate: HashMap::new(), non_mandate: HashMap::new(), - common: HashMap::from([ ( + common: HashMap::from([( "billing.address.first_name".to_string(), RequiredFieldInfo { required_field: "payment_method_data.billing.address.first_name".to_string(), @@ -10270,7 +10466,35 @@ impl Default for super::settings::RequiredFields { field_type: enums::FieldType::UserBillingName, value: None, } - )]), + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "payment_method_data.bank_debit.ach.routing_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.ach.routing_number".to_string(), + display_name: "bank_routing_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), }), ( enums::Connector::Adyen, @@ -10334,7 +10558,35 @@ impl Default for super::settings::RequiredFields { field_type: enums::FieldType::UserBillingName, value: None, } - )]), + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.sepa.iban".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.iban".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), } ), ( @@ -10390,7 +10642,55 @@ impl Default for super::settings::RequiredFields { field_type: enums::FieldType::UserBillingName, value: None, } - )]), + ), + ( + "payment_method_data.bank_debit.bacs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.sort_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), + display_name: "bank_sort_code".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec!["UK".to_string()], + }, + value: None, + }, + ), + ( + "billing.address.zip".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.zip".to_string(), + display_name: "zip".to_string(), + field_type: enums::FieldType::UserAddressPincode, + value: None, + }, + ), + ( + "billing.address.line1".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.line1".to_string(), + display_name: "line1".to_string(), + field_type: enums::FieldType::UserAddressLine1, + value: None, + }, + ) + ]), } ), ( @@ -10437,7 +10737,110 @@ impl Default for super::settings::RequiredFields { }) ]), }, - )]))), + ), + ( + enums::PaymentMethodType::Becs, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "billing_first_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.becs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.becs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "payment_method_data.bank_debit.becs.bsb_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.becs.bsb_number".to_string(), + display_name: "bsb_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), + } + ), + ( + enums::Connector::Adyen, + RequiredFieldFinal { + mandate: HashMap::new(), + non_mandate: HashMap::new(), + common: HashMap::from([ ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + }), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "owner_name".to_string(), + field_type: enums::FieldType::UserBillingName, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.account_number".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.account_number".to_string(), + display_name: "bank_account_number".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ), + ( + "payment_method_data.bank_debit.bacs.sort_code".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.bank_debit.bacs.sort_code".to_string(), + display_name: "bank_sort_code".to_string(), + field_type: enums::FieldType::Text, + value: None, + } + ) + ]), + }) + ]), + }, + ), + ]))), ( enums::PaymentMethod::BankTransfer, PaymentMethodType(HashMap::from([( @@ -10448,7 +10851,17 @@ impl Default for super::settings::RequiredFields { enums::Connector::Stripe, RequiredFieldFinal { mandate: HashMap::new(), - non_mandate: HashMap::new(), + non_mandate: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]), common: HashMap::new(), } ), @@ -10472,7 +10885,17 @@ impl Default for super::settings::RequiredFields { }, value: None, } - )]), + ), + ( + "billing.address.city".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.city".to_string(), + display_name: "city".to_string(), + field_type: enums::FieldType::UserAddressCity, + value: None, + }, + ), + ]), common: HashMap::new(), } ), @@ -10485,7 +10908,17 @@ impl Default for super::settings::RequiredFields { RequiredFieldFinal { mandate: HashMap::new(), non_mandate: HashMap::new(), - common: HashMap::new(), + common: HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ) + ]) } ), ])}), @@ -10526,6 +10959,24 @@ impl Default for super::settings::RequiredFields { value: None, } ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), ] ), } @@ -10840,6 +11291,140 @@ impl Default for super::settings::RequiredFields { ]), }, ), + ( + enums::PaymentMethodType::Sepa, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.country".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.country".to_string(), + display_name: "country".to_string(), + field_type: enums::FieldType::UserAddressCountry { + options: vec![ + "AT".to_string(), + "BE".to_string(), + "BG".to_string(), + "HR".to_string(), + "CY".to_string(), + "CZ".to_string(), + "DK".to_string(), + "EE".to_string(), + "FI".to_string(), + "FR".to_string(), + "DE".to_string(), + "GR".to_string(), + "HU".to_string(), + "IE".to_string(), + "IT".to_string(), + "LV".to_string(), + "LT".to_string(), + "LU".to_string(), + "MT".to_string(), + "NL".to_string(), + "PL".to_string(), + "PT".to_string(), + "RO".to_string(), + "SI".to_string(), + "SK".to_string(), + "ES".to_string(), + "SE".to_string(), + "AD".to_string(), + "IS".to_string(), + "LI".to_string(), + "MC".to_string(), + "NO".to_string(), + "SM".to_string(), + "CH".to_string(), + "GB".to_string(), + "VA".to_string(), + ], + }, + value: None, + }, + ), + ]), + } + ) + ]), + }, + ), + ( + enums::PaymentMethodType::Bacs, + ConnectorFields { + fields: HashMap::from([ + ( + enums::Connector::Stripe, + RequiredFieldFinal { + mandate : HashMap::new(), + non_mandate : HashMap::new(), + common : HashMap::from([ + ( + "billing.email".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.email".to_string(), + display_name: "email".to_string(), + field_type: enums::FieldType::UserEmailAddress, + value: None, + } + ), + ( + "billing.address.first_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.first_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ), + ( + "billing.address.last_name".to_string(), + RequiredFieldInfo { + required_field: "payment_method_data.billing.address.last_name".to_string(), + display_name: "card_holder_name".to_string(), + field_type: enums::FieldType::UserFullName, + value: None, + } + ) + ]), + } + ) + ]), + }, + ), ]))), ( enums::PaymentMethod::GiftCard, @@ -10887,7 +11472,7 @@ impl Default for super::settings::RequiredFields { value: None, } ), - ]), + ]), common: HashMap::new(), } ), diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index 2375dd578b3e..9239a94ad82b 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -17,8 +17,8 @@ use crate::connector::utils::PayoutsData; use crate::{ connector::utils::{ self, AddressDetailsData, ApplePayDecrypt, CardData, PaymentsAuthorizeRequestData, - PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, - PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RecurringMandateData, RouterData, + PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, PaymentsSyncRequestData, + RecurringMandateData, RouterData, }, consts, core::errors, @@ -83,7 +83,7 @@ pub struct CybersourceZeroMandateRequest { impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { type Error = error_stack::Report; fn try_from(item: &types::SetupMandateRouterData) -> Result { - let email = item.request.get_email()?; + let email = item.get_billing_email()?; let bill_to = build_bill_to(item.get_optional_billing(), email)?; let order_information = OrderInformationWithBill { @@ -1033,7 +1033,7 @@ impl domain::Card, ), ) -> Result { - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; let order_information = OrderInformationWithBill::from((item, Some(bill_to))); @@ -1113,7 +1113,7 @@ impl domain::Card, ), ) -> Result { - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; let order_information = OrderInformationWithBill::from((item, bill_to)); @@ -1196,7 +1196,7 @@ impl domain::ApplePayWalletData, ), ) -> Result { - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; let order_information = OrderInformationWithBill::from((item, Some(bill_to))); let processing_information = ProcessingInformation::try_from(( @@ -1265,7 +1265,7 @@ impl domain::GooglePayWalletData, ), ) -> Result { - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; let order_information = OrderInformationWithBill::from((item, Some(bill_to))); @@ -1327,7 +1327,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> } }, None => { - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to( item.router_data.get_optional_billing(), email, @@ -1479,10 +1479,10 @@ impl let payment_instrument = CybersoucrePaymentInstrument { id: connector_mandate_id.into(), }; - let bill_to = - item.router_data.request.get_email().ok().and_then(|email| { - build_bill_to(item.router_data.get_optional_billing(), email).ok() - }); + let bill_to = item + .router_data + .get_optional_billing_email() + .and_then(|email| build_bill_to(item.router_data.get_optional_billing(), email).ok()); let order_information = OrderInformationWithBill::from((item, bill_to)); let payment_information = PaymentInformation::MandatePayment(Box::new(MandatePaymentInformation { @@ -2310,7 +2310,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> })? .1 .to_string(); - let email = item.router_data.request.get_email()?; + let email = item.router_data.get_billing_email()?; let bill_to = build_bill_to(item.router_data.get_optional_billing(), email)?; let order_information = OrderInformationWithBill { amount_details, diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 24b2f2b88e98..fd2b262c7e96 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -150,14 +150,10 @@ pub struct ShippingAddress { name: Option, } -impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ShippingAddress { - type Error = error_stack::Report; - - fn try_from( - item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>, - ) -> Result { - Ok(Self { - address: get_address_info(item.router_data.get_optional_shipping())?, +impl From<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for ShippingAddress { + fn from(item: &PaypalRouterData<&types::PaymentsAuthorizeRouterData>) -> Self { + Self { + address: get_address_info(item.router_data.get_optional_shipping()), name: Some(ShippingName { full_name: item .router_data @@ -165,7 +161,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for Shippin .and_then(|inner_data| inner_data.address.as_ref()) .and_then(|inner_data| inner_data.first_name.clone()), }), - }) + } } } @@ -252,20 +248,17 @@ pub struct PaypalPaymentsRequest { payment_source: Option, } -fn get_address_info( - payment_address: Option<&api_models::payments::Address>, -) -> Result, error_stack::Report> { +fn get_address_info(payment_address: Option<&api_models::payments::Address>) -> Option
{ let address = payment_address.and_then(|payment_address| payment_address.address.as_ref()); - let address = match address { - Some(address) => Some(Address { - country_code: address.get_country()?.to_owned(), + match address { + Some(address) => address.get_optional_country().map(|country| Address { + country_code: country.to_owned(), address_line_1: address.line1.clone(), postal_code: address.zip.clone(), admin_area_2: address.city.clone(), }), None => None, - }; - Ok(address) + } } fn get_payment_source( item: &types::PaymentsAuthorizeRouterData, @@ -279,7 +272,7 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), - shipping_preference: if item.get_optional_shipping().is_some() { + shipping_preference: if item.get_optional_shipping_country().is_some() { ShippingPreference::SetProvidedAddress } else { ShippingPreference::GetFromFile @@ -295,7 +288,7 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), - shipping_preference: if item.get_optional_shipping().is_some() { + shipping_preference: if item.get_optional_shipping_country().is_some() { ShippingPreference::SetProvidedAddress } else { ShippingPreference::GetFromFile @@ -311,7 +304,7 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), - shipping_preference: if item.get_optional_shipping().is_some() { + shipping_preference: if item.get_optional_shipping_country().is_some() { ShippingPreference::SetProvidedAddress } else { ShippingPreference::GetFromFile @@ -328,7 +321,7 @@ fn get_payment_source( experience_context: ContextStruct { return_url: item.request.complete_authorize_url.clone(), cancel_url: item.request.complete_authorize_url.clone(), - shipping_preference: if item.get_optional_shipping().is_some() { + shipping_preference: if item.get_optional_shipping_country().is_some() { ShippingPreference::SetProvidedAddress } else { ShippingPreference::GetFromFile @@ -392,7 +385,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP let connector_request_reference_id = item.router_data.connector_request_reference_id.clone(); - let shipping_address = ShippingAddress::try_from(item)?; + let shipping_address = ShippingAddress::from(item); let item_details = vec![ItemDetails::from(item)]; let purchase_units = vec![PurchaseUnitRequest { @@ -420,7 +413,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP }; let payment_source = Some(PaymentSourceItem::Card(CardRequest { - billing_address: get_address_info(item.router_data.get_optional_billing())?, + billing_address: get_address_info(item.router_data.get_optional_billing()), expiry, name: item .router_data @@ -446,7 +439,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP cancel_url: item.router_data.request.complete_authorize_url.clone(), shipping_preference: if item .router_data - .get_optional_shipping() + .get_optional_shipping_country() .is_some() { ShippingPreference::SetProvidedAddress diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 82ed9577a83c..2af38249e949 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -157,6 +157,8 @@ impl ConnectorValidation for Stripe { PaymentMethodDataType::ApplePay, PaymentMethodDataType::GooglePay, PaymentMethodDataType::AchBankDebit, + PaymentMethodDataType::BacsBankDebit, + PaymentMethodDataType::BecsBankDebit, PaymentMethodDataType::SepaBankDebit, PaymentMethodDataType::Sofort, PaymentMethodDataType::Ideal, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 6b26818c2927..0aed983fba59 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -22,9 +22,7 @@ pub mod connect; pub use self::connect::*; use crate::{ collect_missing_value_keys, - connector::utils::{ - self as connector_util, ApplePay, ApplePayDecrypt, PaymentsPreProcessingData, RouterData, - }, + connector::utils::{self as connector_util, ApplePay, ApplePayDecrypt, RouterData}, consts, core::errors, services, @@ -1093,7 +1091,7 @@ fn get_bank_debit_data( (StripePaymentMethodType::Ach, ach_data) } domain::BankDebitData::SepaBankDebit { iban, .. } => { - let sepa_data = BankDebitData::Sepa { + let sepa_data: BankDebitData = BankDebitData::Sepa { iban: iban.to_owned(), }; (StripePaymentMethodType::Sepa, sepa_data) @@ -1594,35 +1592,36 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent let shipping_address = match item.get_optional_shipping() { Some(shipping_details) => { let shipping_address = shipping_details.address.as_ref(); - Some(StripeShippingAddress { - city: shipping_address.and_then(|a| a.city.clone()), - country: shipping_address.and_then(|a| a.country), - line1: shipping_address.and_then(|a| a.line1.clone()), - line2: shipping_address.and_then(|a| a.line2.clone()), - zip: shipping_address.and_then(|a| a.zip.clone()), - state: shipping_address.and_then(|a| a.state.clone()), - name: shipping_address - .and_then(|a| { - a.first_name.as_ref().map(|first_name| { + shipping_address.and_then(|shipping_detail| { + shipping_detail + .first_name + .as_ref() + .map(|first_name| StripeShippingAddress { + city: shipping_address.and_then(|a| a.city.clone()), + country: shipping_address.and_then(|a| a.country), + line1: shipping_address.and_then(|a| a.line1.clone()), + line2: shipping_address.and_then(|a| a.line2.clone()), + zip: shipping_address.and_then(|a| a.zip.clone()), + state: shipping_address.and_then(|a| a.state.clone()), + name: format!( + "{} {}", + first_name.clone().expose(), + shipping_detail + .last_name + .clone() + .expose_option() + .unwrap_or_default() + ) + .into(), + phone: shipping_details.phone.as_ref().map(|p| { format!( - "{} {}", - first_name.clone().expose(), - a.last_name.clone().expose_option().unwrap_or_default() + "{}{}", + p.country_code.clone().unwrap_or_default(), + p.number.clone().expose_option().unwrap_or_default() ) .into() - }) + }), }) - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "shipping_address.first_name", - })?, - phone: shipping_details.phone.as_ref().map(|p| { - format!( - "{}{}", - p.country_code.clone().unwrap_or_default(), - p.number.clone().expose_option().unwrap_or_default() - ) - .into() - }), }) } None => None, @@ -1785,67 +1784,60 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent _ => payment_data, }; - let setup_mandate_details = item + let customer_acceptance = item.request.customer_acceptance.clone().or(item .request .setup_mandate_details .as_ref() - .and_then(|mandate_details| { - mandate_details - .customer_acceptance - .as_ref() - .map(|customer_acceptance| { - Ok::<_, error_stack::Report>( - match customer_acceptance.acceptance_type { - AcceptanceType::Online => { - let online_mandate = customer_acceptance - .online - .clone() - .get_required_value("online") + .and_then(|mandate_details| mandate_details.customer_acceptance.clone())); + + let setup_mandate_details = customer_acceptance + .as_ref() + .map(|customer_acceptance| { + Ok::<_, error_stack::Report>( + match customer_acceptance.acceptance_type { + AcceptanceType::Online => { + let online_mandate = customer_acceptance + .online + .clone() + .get_required_value("online") + .change_context(errors::ConnectorError::MissingRequiredField { + field_name: "online", + })?; + StripeMandateRequest { + mandate_type: StripeMandateType::Online { + ip_address: online_mandate + .ip_address + .get_required_value("ip_address") .change_context( errors::ConnectorError::MissingRequiredField { - field_name: "online", + field_name: "ip_address", }, - )?; - StripeMandateRequest { - mandate_type: StripeMandateType::Online { - ip_address: online_mandate - .ip_address - .get_required_value("ip_address") - .change_context( - errors::ConnectorError::MissingRequiredField { - field_name: "ip_address", - }, - )?, - user_agent: online_mandate.user_agent, - }, - } - } - AcceptanceType::Offline => StripeMandateRequest { - mandate_type: StripeMandateType::Offline, + )?, + user_agent: online_mandate.user_agent, }, - }, - ) - }) + } + } + AcceptanceType::Offline => StripeMandateRequest { + mandate_type: StripeMandateType::Offline, + }, + }, + ) }) .transpose()? - .or_else(|| { + .or({ //stripe requires us to send mandate_data while making recurring payment through saved bank debit - if payment_method.is_some() { - //check if payment is done through saved payment method - match &payment_method_types { - //check if payment method is bank debit - Some( - StripePaymentMethodType::Ach - | StripePaymentMethodType::Sepa - | StripePaymentMethodType::Becs - | StripePaymentMethodType::Bacs, - ) => Some(StripeMandateRequest { - mandate_type: StripeMandateType::Offline, - }), - _ => None, - } - } else { - None + //check if payment is done through saved payment method + match &payment_method_types { + //check if payment method is bank debit + Some( + StripePaymentMethodType::Ach + | StripePaymentMethodType::Sepa + | StripePaymentMethodType::Becs + | StripePaymentMethodType::Bacs, + ) => Some(StripeMandateRequest { + mandate_type: StripeMandateType::Offline, + }), + _ => None, } }); @@ -3252,7 +3244,7 @@ impl transfer_type: StripeCreditTransferTypes::Multibanco, currency, payment_method_data: MultibancoTransferData { - email: item.request.get_email()?, + email: item.get_billing_email()?, }, amount: Some(amount), return_url: Some(item.get_return_url()?), @@ -3262,7 +3254,7 @@ impl Ok(Self::AchBankTansfer(AchCreditTransferSourceRequest { transfer_type: StripeCreditTransferTypes::AchCreditTransfer, payment_method_data: AchTransferData { - email: item.request.get_email()?, + email: item.get_billing_email()?, }, currency, })) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index d5c01503ed83..6604058a0ae0 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1649,6 +1649,7 @@ pub trait AddressDetailsData { fn to_state_code(&self) -> Result, Error>; fn to_state_code_as_optional(&self) -> Result>, Error>; fn get_optional_line2(&self) -> Option>; + fn get_optional_country(&self) -> Option; } impl AddressDetailsData for api::AddressDetails { @@ -1748,6 +1749,9 @@ impl AddressDetailsData for api::AddressDetails { fn get_optional_line2(&self) -> Option> { self.line2.clone() } + fn get_optional_country(&self) -> Option { + self.country + } } pub trait MandateData {