From 4651584ecc25e40a285b3544315901145d8c6b4b Mon Sep 17 00:00:00 2001 From: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:37:55 +0530 Subject: [PATCH] feat(connector): [BOA/CYB] Make billTo fields optional (#4951) Co-authored-by: Deepanshu Bansal --- .../connector/bankofamerica/transformers.rs | 134 +++++++++++------- .../src/connector/cybersource/transformers.rs | 134 +++++++++++------- 2 files changed, 166 insertions(+), 102 deletions(-) diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index 671cc40e05cb..143c1a4c6faf 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -260,15 +260,15 @@ pub struct Amount { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct BillTo { - first_name: Secret, - last_name: Secret, - address1: Secret, - locality: Secret, + first_name: Option>, + last_name: Option>, + address1: Option>, + locality: Option, #[serde(skip_serializing_if = "Option::is_none")] administrative_area: Option>, #[serde(skip_serializing_if = "Option::is_none")] postal_code: Option>, - country: api_enums::CountryAlpha2, + country: Option, email: pii::Email, } @@ -442,47 +442,77 @@ impl } // for bankofamerica each item in Billing is mandatory +// fn build_bill_to( +// address_details: &payments::Address, +// email: pii::Email, +// ) -> Result> { +// let address = address_details +// .address +// .as_ref() +// .ok_or_else(utils::missing_field_err("billing.address"))?; + +// let country = address.get_country()?.to_owned(); +// let first_name = address.get_first_name()?; + +// let (administrative_area, postal_code) = +// if country == api_enums::CountryAlpha2::US || country == api_enums::CountryAlpha2::CA { +// let mut state = address.to_state_code()?.peek().clone(); +// state.truncate(20); +// ( +// Some(Secret::from(state)), +// Some(address.get_zip()?.to_owned()), +// ) +// } else { +// let zip = address.zip.clone(); +// let mut_state = address.state.clone().map(|state| state.expose()); +// match mut_state { +// Some(mut state) => { +// state.truncate(20); +// (Some(Secret::from(state)), zip) +// } +// None => (None, zip), +// } +// }; +// Ok(BillTo { +// first_name: first_name.clone(), +// last_name: address.get_last_name().unwrap_or(first_name).clone(), +// address1: address.get_line1()?.to_owned(), +// locality: Secret::new(address.get_city()?.to_owned()), +// administrative_area, +// postal_code, +// country, +// email, +// }) +// } + fn build_bill_to( - address_details: &payments::Address, + address_details: Option<&payments::Address>, email: pii::Email, ) -> Result> { - let address = address_details - .address - .as_ref() - .ok_or_else(utils::missing_field_err("billing.address"))?; - - let country = address.get_country()?.to_owned(); - let first_name = address.get_first_name()?; - - let (administrative_area, postal_code) = - if country == api_enums::CountryAlpha2::US || country == api_enums::CountryAlpha2::CA { - let mut state = address.to_state_code()?.peek().clone(); - state.truncate(20); - ( - Some(Secret::from(state)), - Some(address.get_zip()?.to_owned()), - ) - } else { - let zip = address.zip.clone(); - let mut_state = address.state.clone().map(|state| state.expose()); - match mut_state { - Some(mut state) => { - state.truncate(20); - (Some(Secret::from(state)), zip) - } - None => (None, zip), - } - }; - Ok(BillTo { - first_name: first_name.clone(), - last_name: address.get_last_name().unwrap_or(first_name).clone(), - address1: address.get_line1()?.to_owned(), - locality: Secret::new(address.get_city()?.to_owned()), - administrative_area, - postal_code, - country, - email, - }) + let default_address = BillTo { + first_name: None, + last_name: None, + address1: None, + locality: None, + administrative_area: None, + postal_code: None, + country: None, + email: email.clone(), + }; + Ok(address_details + .and_then(|addr| { + addr.address.as_ref().map(|addr| BillTo { + first_name: addr.first_name.clone(), + last_name: addr.last_name.clone(), + address1: addr.line1.clone(), + locality: addr.city.clone(), + administrative_area: addr.to_state_code_as_optional().ok().flatten(), + postal_code: addr.zip.clone(), + country: addr.country, + email, + }) + }) + .unwrap_or(default_address)) } impl From for String { @@ -876,7 +906,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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)); let payment_information = PaymentInformation::try_from(&ccard)?; @@ -939,7 +969,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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 payment_information = PaymentInformation::try_from(&ccard)?; let processing_information = ProcessingInformation::try_from((item, None, None))?; @@ -976,7 +1006,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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(( item, @@ -1030,7 +1060,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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 payment_information = PaymentInformation::from(&google_pay_data); let processing_information = @@ -1081,8 +1111,10 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> }, None => { let email = item.router_data.request.get_email()?; - let bill_to = - build_bill_to(item.router_data.get_billing()?, email)?; + let bill_to = build_bill_to( + item.router_data.get_optional_billing(), + email, + )?; let order_information: OrderInformationWithBill = OrderInformationWithBill::from((item, Some(bill_to))); let processing_information = @@ -1897,7 +1929,7 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsPreProcessingRouterData>> .1 .to_string(); let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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, bill_to: Some(bill_to), @@ -3098,7 +3130,7 @@ impl TryFrom<&types::SetupMandateRouterData> for OrderInformationWithBill { fn try_from(item: &types::SetupMandateRouterData) -> Result { let email = item.request.get_email()?; - let bill_to = build_bill_to(item.get_billing()?, email)?; + let bill_to = build_bill_to(item.get_optional_billing(), email)?; Ok(Self { amount_details: Amount { diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index edc5c0cac1d9..346f66b5d2e1 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -65,7 +65,7 @@ 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 bill_to = build_bill_to(item.get_billing()?, email)?; + let bill_to = build_bill_to(item.get_optional_billing(), email)?; let order_information = OrderInformationWithBill { amount_details: Amount { @@ -478,15 +478,15 @@ impl From for String { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct BillTo { - first_name: Secret, - last_name: Secret, - address1: Secret, - locality: String, + first_name: Option>, + last_name: Option>, + address1: Option>, + locality: Option, #[serde(skip_serializing_if = "Option::is_none")] administrative_area: Option>, #[serde(skip_serializing_if = "Option::is_none")] postal_code: Option>, - country: api_enums::CountryAlpha2, + country: Option, email: pii::Email, } @@ -862,47 +862,77 @@ impl } // for cybersource each item in Billing is mandatory +// fn build_bill_to( +// address_details: &payments::Address, +// email: pii::Email, +// ) -> Result> { +// let address = address_details +// .address +// .as_ref() +// .ok_or_else(utils::missing_field_err("billing.address"))?; + +// let country = address.get_country()?.to_owned(); +// let first_name = address.get_first_name()?; + +// let (administrative_area, postal_code) = +// if country == api_enums::CountryAlpha2::US || country == api_enums::CountryAlpha2::CA { +// let mut state = address.to_state_code()?.peek().clone(); +// state.truncate(20); +// ( +// Some(Secret::from(state)), +// Some(address.get_zip()?.to_owned()), +// ) +// } else { +// let zip = address.zip.clone(); +// let mut_state = address.state.clone().map(|state| state.expose()); +// match mut_state { +// Some(mut state) => { +// state.truncate(20); +// (Some(Secret::from(state)), zip) +// } +// None => (None, zip), +// } +// }; +// Ok(BillTo { +// first_name: first_name.clone(), +// last_name: address.get_last_name().unwrap_or(first_name).clone(), +// address1: address.get_line1()?.to_owned(), +// locality: address.get_city()?.to_owned(), +// administrative_area, +// postal_code, +// country, +// email, +// }) +// } + fn build_bill_to( - address_details: &payments::Address, + address_details: Option<&payments::Address>, email: pii::Email, ) -> Result> { - let address = address_details - .address - .as_ref() - .ok_or_else(utils::missing_field_err("billing.address"))?; - - let country = address.get_country()?.to_owned(); - let first_name = address.get_first_name()?; - - let (administrative_area, postal_code) = - if country == api_enums::CountryAlpha2::US || country == api_enums::CountryAlpha2::CA { - let mut state = address.to_state_code()?.peek().clone(); - state.truncate(20); - ( - Some(Secret::from(state)), - Some(address.get_zip()?.to_owned()), - ) - } else { - let zip = address.zip.clone(); - let mut_state = address.state.clone().map(|state| state.expose()); - match mut_state { - Some(mut state) => { - state.truncate(20); - (Some(Secret::from(state)), zip) - } - None => (None, zip), - } - }; - Ok(BillTo { - first_name: first_name.clone(), - last_name: address.get_last_name().unwrap_or(first_name).clone(), - address1: address.get_line1()?.to_owned(), - locality: address.get_city()?.to_owned(), - administrative_area, - postal_code, - country, - email, - }) + let default_address = BillTo { + first_name: None, + last_name: None, + address1: None, + locality: None, + administrative_area: None, + postal_code: None, + country: None, + email: email.clone(), + }; + Ok(address_details + .and_then(|addr| { + addr.address.as_ref().map(|addr| BillTo { + first_name: addr.first_name.clone(), + last_name: addr.last_name.clone(), + address1: addr.line1.clone(), + locality: addr.city.clone(), + administrative_area: addr.to_state_code_as_optional().ok().flatten(), + postal_code: addr.zip.clone(), + country: addr.country, + email, + }) + }) + .unwrap_or(default_address)) } impl ForeignFrom for Vec { @@ -937,7 +967,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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 card_issuer = ccard.get_card_issuer(); @@ -1015,7 +1045,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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)); let card_issuer = ccard.get_card_issuer(); @@ -1096,7 +1126,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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(( item, @@ -1163,7 +1193,7 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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 payment_information = @@ -1223,8 +1253,10 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> }, None => { let email = item.router_data.request.get_email()?; - let bill_to = - build_bill_to(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 = @@ -2212,7 +2244,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsPreProcessingRouterData>> .1 .to_string(); let email = item.router_data.request.get_email()?; - let bill_to = build_bill_to(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, bill_to: Some(bill_to),