feat(core): billing_details inclusion in Payment Intent (#5090)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Prajjwal Kumar
2024-07-05 18:43:46 +05:30
committed by GitHub
parent c642d9dcf5
commit ec01788bc4
42 changed files with 212 additions and 144 deletions

View File

@ -151,7 +151,7 @@ impl TryFrom<&RapydRouterData<&types::PaymentsAuthorizeRouterData>> for RapydPay
}
_ => None,
}
.get_required_value("payment_method not implemnted")
.get_required_value("payment_method not implemented")
.change_context(errors::ConnectorError::NotImplemented(
"payment_method".to_owned(),
))?;

View File

@ -341,7 +341,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.first_name.clone())
.and_then(|billing_details| billing_details.first_name.clone())
})
.ok_or_else(missing_field_err(
"payment_method_data.billing.address.first_name",
@ -364,7 +364,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.last_name.clone())
.and_then(|billing_details| billing_details.last_name.clone())
})
.ok_or_else(missing_field_err(
"payment_method_data.billing.address.last_name",
@ -378,7 +378,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.line1.clone())
.and_then(|billing_details| billing_details.line1.clone())
})
.ok_or_else(missing_field_err(
"payment_method_data.billing.address.line1",
@ -391,7 +391,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.city)
.and_then(|billing_details| billing_details.city)
})
.ok_or_else(missing_field_err(
"payment_method_data.billing.address.city",
@ -421,7 +421,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.line1)
.and_then(|billing_details| billing_details.line1)
})
}
@ -432,7 +432,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.line2)
.and_then(|billing_details| billing_details.line2)
})
}
@ -443,7 +443,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.city)
.and_then(|billing_details| billing_details.city)
})
}
@ -454,7 +454,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.country)
.and_then(|billing_details| billing_details.country)
})
}
@ -465,7 +465,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.zip)
.and_then(|billing_details| billing_details.zip)
})
}
@ -476,7 +476,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.state)
.and_then(|billing_details| billing_details.state)
})
}
@ -487,7 +487,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.first_name)
.and_then(|billing_details| billing_details.first_name)
})
}
@ -498,7 +498,7 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
billing_address
.clone()
.address
.and_then(|billing_address_details| billing_address_details.last_name)
.and_then(|billing_details| billing_details.last_name)
})
}
@ -615,7 +615,7 @@ impl AddressData for api::Address {
fn get_optional_country(&self) -> Option<enums::CountryAlpha2> {
self.address
.as_ref()
.and_then(|billing_address_details| billing_address_details.country)
.and_then(|billing_details| billing_details.country)
}
fn get_optional_full_name(&self) -> Option<Secret<String>> {

View File

@ -3151,6 +3151,7 @@ mod tests {
charges: None,
frm_metadata: None,
customer_details: None,
billing_details: None,
merchant_order_reference_id: None,
};
let req_cs = Some("1".to_string());
@ -3212,6 +3213,7 @@ mod tests {
charges: None,
frm_metadata: None,
customer_details: None,
billing_details: None,
merchant_order_reference_id: None,
};
let req_cs = Some("1".to_string());
@ -3272,6 +3274,7 @@ mod tests {
charges: None,
frm_metadata: None,
customer_details: None,
billing_details: None,
merchant_order_reference_id: None,
};
let req_cs = Some("1".to_string());

View File

@ -22,6 +22,7 @@ use crate::{
blocklist::utils as blocklist_utils,
errors::{self, CustomResult, RouterResult, StorageErrorExt},
mandate::helpers as m_helpers,
payment_methods::cards::create_encrypted_data,
payments::{
self, helpers, operations, populate_surcharge_details, CustomerDetails, PaymentAddress,
PaymentData,
@ -1218,6 +1219,10 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.in_current_span(),
);
let billing_address = payment_data.address.get_payment_billing();
let billing_details = billing_address
.async_and_then(|_| async { create_encrypted_data(key_store, billing_address).await })
.await;
let m_payment_data_payment_intent = payment_data.payment_intent.clone();
let m_customer_id = customer_id.clone();
let m_shipping_address_id = shipping_address_id.clone();
@ -1263,6 +1268,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
frm_metadata: m_frm_metadata,
customer_details,
merchant_order_reference_id: None,
billing_details,
},
&m_key_store,
storage_scheme,

View File

@ -1045,6 +1045,16 @@ impl PaymentCreate {
.change_context(errors::ApiErrorResponse::InternalServerError)?
.map(Secret::new);
// Derivation of directly supplied Billing Address data in our Payment Create Request
// Encrypting our Billing Address Details to be stored in Payment Intent
let billing_details = request
.billing
.clone()
.async_and_then(|_| async {
create_encrypted_data(key_store, request.billing.clone()).await
})
.await;
// Derivation of directly supplied Customer data in our Payment Create Request
let raw_customer_details = if request.customer_id.is_none()
&& (request.name.is_some()
@ -1116,6 +1126,7 @@ impl PaymentCreate {
.request_external_three_ds_authentication,
charges,
frm_metadata: request.frm_metadata.clone(),
billing_details,
customer_details,
merchant_order_reference_id: request.merchant_order_reference_id.clone(),
})

View File

@ -1,7 +1,9 @@
use std::marker::PhantomData;
use api_models::{
enums::FrmSuggestion, mandates::RecurringDetails, payments::RequestSurchargeDetails,
enums::FrmSuggestion,
mandates::RecurringDetails,
payments::{Address, RequestSurchargeDetails},
};
use async_trait::async_trait;
use common_utils::{
@ -18,6 +20,7 @@ use crate::{
core::{
errors::{self, CustomResult, RouterResult, StorageErrorExt},
mandate::helpers as m_helpers,
payment_methods::cards::create_encrypted_data,
payments::{self, helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
utils as core_utils,
},
@ -218,6 +221,14 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
)
.await?;
let billing_details: Option<Address> = billing_address.as_ref().map(From::from);
payment_intent.billing_details = billing_details
.clone()
.async_and_then(|_| async {
create_encrypted_data(key_store, billing_details.clone()).await
})
.await;
let payment_method_billing = helpers::create_or_update_address_for_payment_by_request(
db,
request
@ -438,7 +449,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
customer_acceptance,
address: PaymentAddress::new(
shipping_address.as_ref().map(From::from),
billing_address.as_ref().map(From::from),
billing_details,
payment_method_billing.as_ref().map(From::from),
business_profile.use_billing_as_payment_method_billing,
),
@ -716,7 +727,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
.payment_intent
.merchant_order_reference_id
.clone();
let billing_details = payment_data.payment_intent.billing_details.clone();
payment_data.payment_intent = state
.store
.update_payment_intent(
@ -747,6 +758,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
frm_metadata,
customer_details,
merchant_order_reference_id,
billing_details,
},
key_store,
storage_scheme,

View File

@ -1,6 +1,7 @@
use common_utils::{id_type, types::MinorUnit};
use common_utils::{crypto::Encryptable, id_type, types::MinorUnit};
use diesel_models::enums as storage_enums;
use hyperswitch_domain_models::payments::PaymentIntent;
use masking::Secret;
use time::OffsetDateTime;
#[derive(serde::Serialize, Debug)]
@ -31,6 +32,7 @@ pub struct KafkaPaymentIntent<'a> {
pub business_label: Option<&'a String>,
pub attempt_count: i16,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
}
impl<'a> KafkaPaymentIntent<'a> {
@ -59,6 +61,7 @@ impl<'a> KafkaPaymentIntent<'a> {
business_label: intent.business_label.as_ref(),
attempt_count: intent.attempt_count,
payment_confirm_source: intent.payment_confirm_source,
billing_details: intent.billing_details.clone(),
}
}
}

View File

@ -1,6 +1,7 @@
use common_utils::{id_type, types::MinorUnit};
use common_utils::{crypto::Encryptable, id_type, types::MinorUnit};
use diesel_models::enums as storage_enums;
use hyperswitch_domain_models::payments::PaymentIntent;
use masking::Secret;
use time::OffsetDateTime;
#[serde_with::skip_serializing_none]
@ -32,6 +33,7 @@ pub struct KafkaPaymentIntentEvent<'a> {
pub business_label: Option<&'a String>,
pub attempt_count: i16,
pub payment_confirm_source: Option<storage_enums::PaymentSource>,
pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
}
impl<'a> KafkaPaymentIntentEvent<'a> {
@ -60,6 +62,7 @@ impl<'a> KafkaPaymentIntentEvent<'a> {
business_label: intent.business_label.as_ref(),
attempt_count: intent.attempt_count,
payment_confirm_source: intent.payment_confirm_source,
billing_details: intent.billing_details.clone(),
}
}
}

View File

@ -226,6 +226,7 @@ pub async fn generate_sample_data(
charges: None,
frm_metadata: Default::default(),
customer_details: None,
billing_details: None,
merchant_order_reference_id: Default::default(),
};
let payment_attempt = PaymentAttemptBatchNew {