mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 17:19:15 +08:00
refactor(core): accept customer data in customer object (#1447)
Co-authored-by: Abhishek Marrivagu <68317979+Abhicodes-crypto@users.noreply.github.com>
This commit is contained in:
@ -45,6 +45,28 @@ pub struct BankCodeResponse {
|
|||||||
pub eligible_connectors: Vec<String>,
|
pub eligible_connectors: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
|
||||||
|
pub struct CustomerDetails {
|
||||||
|
/// The identifier for the customer.
|
||||||
|
pub id: String,
|
||||||
|
|
||||||
|
/// The customer's name
|
||||||
|
#[schema(max_length = 255, value_type = Option<String>, example = "John Doe")]
|
||||||
|
pub name: Option<Secret<String>>,
|
||||||
|
|
||||||
|
/// The customer's email address
|
||||||
|
#[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
|
||||||
|
pub email: Option<Email>,
|
||||||
|
|
||||||
|
/// The customer's phone number
|
||||||
|
#[schema(value_type = Option<String>, max_length = 10, example = "3141592653")]
|
||||||
|
pub phone: Option<Secret<String>>,
|
||||||
|
|
||||||
|
/// The country code for the customer's phone number
|
||||||
|
#[schema(max_length = 2, example = "+1")]
|
||||||
|
pub phone_country_code: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Default,
|
Default,
|
||||||
Debug,
|
Debug,
|
||||||
@ -114,23 +136,33 @@ pub struct PaymentsRequest {
|
|||||||
#[schema(default = false, example = true)]
|
#[schema(default = false, example = true)]
|
||||||
pub confirm: Option<bool>,
|
pub confirm: Option<bool>,
|
||||||
|
|
||||||
/// The identifier for the customer object. If not provided the customer ID will be autogenerated.
|
/// The details of a customer for this payment
|
||||||
|
/// This will create the customer if `customer.id` does not exist
|
||||||
|
/// If customer id already exists, it will update the details of the customer
|
||||||
|
pub customer: Option<CustomerDetails>,
|
||||||
|
|
||||||
|
/// The identifier for the customer object.
|
||||||
|
/// This field will be deprecated soon, use the customer object instead
|
||||||
#[schema(max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
|
#[schema(max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
|
||||||
pub customer_id: Option<String>,
|
pub customer_id: Option<String>,
|
||||||
|
|
||||||
/// description: The customer's email address
|
/// The customer's email address
|
||||||
|
/// This field will be deprecated soon, use the customer object instead
|
||||||
#[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
|
#[schema(max_length = 255, value_type = Option<String>, example = "johntest@test.com")]
|
||||||
pub email: Option<Email>,
|
pub email: Option<Email>,
|
||||||
|
|
||||||
/// description: The customer's name
|
/// description: The customer's name
|
||||||
|
/// This field will be deprecated soon, use the customer object instead
|
||||||
#[schema(value_type = Option<String>, max_length = 255, example = "John Test")]
|
#[schema(value_type = Option<String>, max_length = 255, example = "John Test")]
|
||||||
pub name: Option<Secret<String>>,
|
pub name: Option<Secret<String>>,
|
||||||
|
|
||||||
/// The customer's phone number
|
/// The customer's phone number
|
||||||
|
/// This field will be deprecated soon, use the customer object instead
|
||||||
#[schema(value_type = Option<String>, max_length = 255, example = "3141592653")]
|
#[schema(value_type = Option<String>, max_length = 255, example = "3141592653")]
|
||||||
pub phone: Option<Secret<String>>,
|
pub phone: Option<Secret<String>>,
|
||||||
|
|
||||||
/// The country code for the customer phone number
|
/// The country code for the customer phone number
|
||||||
|
/// This field will be deprecated soon, use the customer object instead
|
||||||
#[schema(max_length = 255, example = "+1")]
|
#[schema(max_length = 255, example = "+1")]
|
||||||
pub phone_country_code: Option<String>,
|
pub phone_country_code: Option<String>,
|
||||||
|
|
||||||
@ -303,27 +335,6 @@ pub struct VerifyRequest {
|
|||||||
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
|
pub merchant_connector_details: Option<admin::MerchantConnectorDetailsWrap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PaymentsRequest> for VerifyRequest {
|
|
||||||
fn from(item: PaymentsRequest) -> Self {
|
|
||||||
Self {
|
|
||||||
client_secret: item.client_secret,
|
|
||||||
merchant_id: item.merchant_id,
|
|
||||||
customer_id: item.customer_id,
|
|
||||||
email: item.email,
|
|
||||||
name: item.name,
|
|
||||||
phone: item.phone,
|
|
||||||
phone_country_code: item.phone_country_code,
|
|
||||||
payment_method: item.payment_method,
|
|
||||||
payment_method_data: item.payment_method_data,
|
|
||||||
payment_token: item.payment_token,
|
|
||||||
mandate_data: item.mandate_data,
|
|
||||||
setup_future_usage: item.setup_future_usage,
|
|
||||||
off_session: item.off_session,
|
|
||||||
merchant_connector_details: item.merchant_connector_details,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum MandateTxnType {
|
pub enum MandateTxnType {
|
||||||
@ -1478,7 +1489,12 @@ impl From<&PaymentsRequest> for MandateValidationFields {
|
|||||||
Self {
|
Self {
|
||||||
mandate_id: req.mandate_id.clone(),
|
mandate_id: req.mandate_id.clone(),
|
||||||
confirm: req.confirm,
|
confirm: req.confirm,
|
||||||
customer_id: req.customer_id.clone(),
|
customer_id: req
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.map(|customer_details| &customer_details.id)
|
||||||
|
.or(req.customer_id.as_ref())
|
||||||
|
.map(ToOwned::to_owned),
|
||||||
mandate_data: req.mandate_data.clone(),
|
mandate_data: req.mandate_data.clone(),
|
||||||
setup_future_usage: req.setup_future_usage,
|
setup_future_usage: req.setup_future_usage,
|
||||||
off_session: req.off_session,
|
off_session: req.off_session,
|
||||||
|
|||||||
@ -96,7 +96,7 @@ pub async fn get_address_for_payment_request(
|
|||||||
req_address: Option<&api::Address>,
|
req_address: Option<&api::Address>,
|
||||||
address_id: Option<&str>,
|
address_id: Option<&str>,
|
||||||
merchant_id: &str,
|
merchant_id: &str,
|
||||||
customer_id: &Option<String>,
|
customer_id: Option<&String>,
|
||||||
) -> CustomResult<Option<domain::Address>, errors::ApiErrorResponse> {
|
) -> CustomResult<Option<domain::Address>, errors::ApiErrorResponse> {
|
||||||
let key = types::get_merchant_enc_key(db, merchant_id.to_string())
|
let key = types::get_merchant_enc_key(db, merchant_id.to_string())
|
||||||
.await
|
.await
|
||||||
@ -179,7 +179,7 @@ pub async fn get_address_for_payment_request(
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// generate a new address here
|
// generate a new address here
|
||||||
let customer_id = customer_id.as_deref().get_required_value("customer_id")?;
|
let customer_id = customer_id.get_required_value("customer_id")?;
|
||||||
|
|
||||||
let address_details = address.address.clone().unwrap_or_default();
|
let address_details = address.address.clone().unwrap_or_default();
|
||||||
Some(
|
Some(
|
||||||
@ -460,7 +460,7 @@ fn validate_new_mandate_request(
|
|||||||
is_confirm_operation: bool,
|
is_confirm_operation: bool,
|
||||||
) -> RouterResult<()> {
|
) -> RouterResult<()> {
|
||||||
// We need not check for customer_id in the confirm request if it is already passed
|
// We need not check for customer_id in the confirm request if it is already passed
|
||||||
//in create request
|
// in create request
|
||||||
|
|
||||||
fp_utils::when(!is_confirm_operation && req.customer_id.is_none(), || {
|
fp_utils::when(!is_confirm_operation && req.customer_id.is_none(), || {
|
||||||
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
@ -810,6 +810,109 @@ pub async fn get_customer_from_details<F: Clone>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if the inner values of two options are not equal and throws appropriate error
|
||||||
|
fn validate_options_for_inequality<T: PartialEq>(
|
||||||
|
first_option: Option<&T>,
|
||||||
|
second_option: Option<&T>,
|
||||||
|
field_name: &str,
|
||||||
|
) -> Result<(), errors::ApiErrorResponse> {
|
||||||
|
fp_utils::when(
|
||||||
|
first_option
|
||||||
|
.zip(second_option)
|
||||||
|
.map(|(value1, value2)| value1 != value2)
|
||||||
|
.unwrap_or(false),
|
||||||
|
|| {
|
||||||
|
Err(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
|
message: format!("The field name `{field_name}` sent in both places is ambiguous"),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if the customer details are passed in both places
|
||||||
|
// If so, raise an error
|
||||||
|
pub fn validate_customer_details_in_request(
|
||||||
|
request: &api_models::payments::PaymentsRequest,
|
||||||
|
) -> Result<(), errors::ApiErrorResponse> {
|
||||||
|
if let Some(customer_details) = request.customer.as_ref() {
|
||||||
|
validate_options_for_inequality(
|
||||||
|
request.customer_id.as_ref(),
|
||||||
|
Some(&customer_details.id),
|
||||||
|
"customer_id",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
validate_options_for_inequality(
|
||||||
|
request.email.as_ref(),
|
||||||
|
customer_details.email.as_ref(),
|
||||||
|
"email",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
validate_options_for_inequality(
|
||||||
|
request.name.as_ref(),
|
||||||
|
customer_details.name.as_ref(),
|
||||||
|
"name",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
validate_options_for_inequality(
|
||||||
|
request.phone.as_ref(),
|
||||||
|
customer_details.phone.as_ref(),
|
||||||
|
"phone",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
validate_options_for_inequality(
|
||||||
|
request.phone_country_code.as_ref(),
|
||||||
|
customer_details.phone_country_code.as_ref(),
|
||||||
|
"phone_country_code",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the customer details from customer field if present
|
||||||
|
/// or from the individual fields in `PaymentsRequest`
|
||||||
|
pub fn get_customer_details_from_request(
|
||||||
|
request: &api_models::payments::PaymentsRequest,
|
||||||
|
) -> CustomerDetails {
|
||||||
|
let customer_id = request
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.map(|customer_details| customer_details.id.clone())
|
||||||
|
.or(request.customer_id.clone());
|
||||||
|
|
||||||
|
let customer_name = request
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|customer_details| customer_details.name.clone())
|
||||||
|
.or(request.name.clone());
|
||||||
|
|
||||||
|
let customer_email = request
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|customer_details| customer_details.email.clone())
|
||||||
|
.or(request.email.clone());
|
||||||
|
|
||||||
|
let customer_phone = request
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|customer_details| customer_details.phone.clone())
|
||||||
|
.or(request.phone.clone());
|
||||||
|
|
||||||
|
let customer_phone_code = request
|
||||||
|
.customer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|customer_details| customer_details.phone_country_code.clone())
|
||||||
|
.or(request.phone_country_code.clone());
|
||||||
|
|
||||||
|
CustomerDetails {
|
||||||
|
customer_id,
|
||||||
|
name: customer_name,
|
||||||
|
email: customer_email,
|
||||||
|
phone: customer_phone,
|
||||||
|
phone_country_code: customer_phone_code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_connector_default(
|
pub async fn get_connector_default(
|
||||||
_state: &AppState,
|
_state: &AppState,
|
||||||
request_connector: Option<serde_json::Value>,
|
request_connector: Option<serde_json::Value>,
|
||||||
|
|||||||
@ -80,7 +80,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
|||||||
None,
|
None,
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let billing_address = helpers::get_address_for_payment_request(
|
let billing_address = helpers::get_address_for_payment_request(
|
||||||
@ -88,7 +88,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
|||||||
None,
|
None,
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -99,7 +99,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
|||||||
None,
|
None,
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
|||||||
None,
|
None,
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -135,7 +135,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
|
|||||||
request.shipping.as_ref(),
|
request.shipping.as_ref(),
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let billing_address = helpers::get_address_for_payment_request(
|
let billing_address = helpers::get_address_for_payment_request(
|
||||||
@ -143,7 +143,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
|
|||||||
request.billing.as_ref(),
|
request.billing.as_ref(),
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -122,6 +122,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
field_name: "browser_info",
|
field_name: "browser_info",
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let customer_details = helpers::get_customer_details_from_request(request);
|
||||||
|
|
||||||
let token = token.or_else(|| payment_attempt.payment_token.clone());
|
let token = token.or_else(|| payment_attempt.payment_token.clone());
|
||||||
|
|
||||||
helpers::validate_pm_or_token_given(
|
helpers::validate_pm_or_token_given(
|
||||||
@ -159,7 +161,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
&payment_intent
|
&payment_intent
|
||||||
.customer_id
|
.customer_id
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| request.customer_id.clone()),
|
.or_else(|| customer_details.customer_id.clone()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let shipping_address = helpers::get_address_for_payment_request(
|
let shipping_address = helpers::get_address_for_payment_request(
|
||||||
@ -167,7 +169,10 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
request.shipping.as_ref(),
|
request.shipping.as_ref(),
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent
|
||||||
|
.customer_id
|
||||||
|
.as_ref()
|
||||||
|
.or(customer_details.customer_id.as_ref()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let billing_address = helpers::get_address_for_payment_request(
|
let billing_address = helpers::get_address_for_payment_request(
|
||||||
@ -175,7 +180,10 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
request.billing.as_ref(),
|
request.billing.as_ref(),
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent
|
||||||
|
.customer_id
|
||||||
|
.as_ref()
|
||||||
|
.or(customer_details.customer_id.as_ref()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -255,13 +263,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
ephemeral_key: None,
|
ephemeral_key: None,
|
||||||
redirect_response: None,
|
redirect_response: None,
|
||||||
},
|
},
|
||||||
Some(CustomerDetails {
|
Some(customer_details),
|
||||||
customer_id: request.customer_id.clone(),
|
|
||||||
name: request.name.clone(),
|
|
||||||
email: request.email.clone(),
|
|
||||||
phone: request.phone.clone(),
|
|
||||||
phone_country_code: request.phone_country_code.clone(),
|
|
||||||
}),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,6 +474,9 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentConfir
|
|||||||
{
|
{
|
||||||
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
helpers::validate_customer_details_in_request(request)?;
|
||||||
|
|
||||||
let given_payment_id = match &request.payment_id {
|
let given_payment_id = match &request.payment_id {
|
||||||
Some(id_type) => Some(
|
Some(id_type) => Some(
|
||||||
id_type
|
id_type
|
||||||
|
|||||||
@ -74,12 +74,14 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let customer_details = helpers::get_customer_details_from_request(request);
|
||||||
|
|
||||||
let shipping_address = helpers::get_address_for_payment_request(
|
let shipping_address = helpers::get_address_for_payment_request(
|
||||||
db,
|
db,
|
||||||
request.shipping.as_ref(),
|
request.shipping.as_ref(),
|
||||||
None,
|
None,
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&request.customer_id,
|
customer_details.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
request.billing.as_ref(),
|
request.billing.as_ref(),
|
||||||
None,
|
None,
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&request.customer_id,
|
customer_details.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -256,13 +258,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
ephemeral_key,
|
ephemeral_key,
|
||||||
redirect_response: None,
|
redirect_response: None,
|
||||||
},
|
},
|
||||||
Some(CustomerDetails {
|
Some(customer_details),
|
||||||
customer_id: request.customer_id.clone(),
|
|
||||||
name: request.name.clone(),
|
|
||||||
email: request.email.clone(),
|
|
||||||
phone: request.phone.clone(),
|
|
||||||
phone_country_code: request.phone_country_code.clone(),
|
|
||||||
}),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -423,6 +419,9 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
|
|||||||
{
|
{
|
||||||
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
helpers::validate_customer_details_in_request(request)?;
|
||||||
|
|
||||||
let given_payment_id = match &request.payment_id {
|
let given_payment_id = match &request.payment_id {
|
||||||
Some(id_type) => Some(
|
Some(id_type) => Some(
|
||||||
id_type
|
id_type
|
||||||
|
|||||||
@ -87,7 +87,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
|||||||
None,
|
None,
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
|||||||
None,
|
None,
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
None,
|
None,
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let billing_address = helpers::get_address_for_payment_request(
|
let billing_address = helpers::get_address_for_payment_request(
|
||||||
@ -89,7 +89,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
None,
|
None,
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent.customer_id.as_ref(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@ -107,6 +107,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
};
|
};
|
||||||
|
|
||||||
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
payment_attempt.payment_method = payment_method_type.or(payment_attempt.payment_method);
|
||||||
|
let customer_details = helpers::get_customer_details_from_request(request);
|
||||||
|
|
||||||
let amount = request
|
let amount = request
|
||||||
.amount
|
.amount
|
||||||
@ -120,7 +121,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
&payment_intent
|
&payment_intent
|
||||||
.customer_id
|
.customer_id
|
||||||
.clone()
|
.clone()
|
||||||
.or_else(|| request.customer_id.clone()),
|
.or_else(|| customer_details.customer_id.clone()),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +130,10 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
request.shipping.as_ref(),
|
request.shipping.as_ref(),
|
||||||
payment_intent.shipping_address_id.as_deref(),
|
payment_intent.shipping_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent
|
||||||
|
.customer_id
|
||||||
|
.as_ref()
|
||||||
|
.or(customer_details.customer_id.as_ref()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
let billing_address = helpers::get_address_for_payment_request(
|
let billing_address = helpers::get_address_for_payment_request(
|
||||||
@ -137,7 +141,10 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
request.billing.as_ref(),
|
request.billing.as_ref(),
|
||||||
payment_intent.billing_address_id.as_deref(),
|
payment_intent.billing_address_id.as_deref(),
|
||||||
merchant_id,
|
merchant_id,
|
||||||
&payment_intent.customer_id,
|
payment_intent
|
||||||
|
.customer_id
|
||||||
|
.as_ref()
|
||||||
|
.or(customer_details.customer_id.as_ref()),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -281,6 +288,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.clone()
|
.clone()
|
||||||
.map(ForeignInto::foreign_into)),
|
.map(ForeignInto::foreign_into)),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
next_operation,
|
next_operation,
|
||||||
PaymentData {
|
PaymentData {
|
||||||
@ -312,13 +320,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
ephemeral_key: None,
|
ephemeral_key: None,
|
||||||
redirect_response: None,
|
redirect_response: None,
|
||||||
},
|
},
|
||||||
Some(CustomerDetails {
|
Some(customer_details),
|
||||||
customer_id: request.customer_id.clone(),
|
|
||||||
name: request.name.clone(),
|
|
||||||
email: request.email.clone(),
|
|
||||||
phone: request.phone.clone(),
|
|
||||||
phone_country_code: request.phone_country_code.clone(),
|
|
||||||
}),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,6 +528,9 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
|
|||||||
{
|
{
|
||||||
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
helpers::validate_customer_details_in_request(request)?;
|
||||||
|
|
||||||
let given_payment_id = match &request.payment_id {
|
let given_payment_id = match &request.payment_id {
|
||||||
Some(id_type) => Some(
|
Some(id_type) => Some(
|
||||||
id_type
|
id_type
|
||||||
|
|||||||
@ -241,6 +241,7 @@ Never share your secret api keys. Keep them guarded and secure.
|
|||||||
api_models::mandates::MandateResponse,
|
api_models::mandates::MandateResponse,
|
||||||
api_models::mandates::MandateCardDetails,
|
api_models::mandates::MandateCardDetails,
|
||||||
api_models::ephemeral_key::EphemeralKeyCreateResponse,
|
api_models::ephemeral_key::EphemeralKeyCreateResponse,
|
||||||
|
api_models::payments::CustomerDetails,
|
||||||
crate::types::api::admin::MerchantAccountResponse,
|
crate::types::api::admin::MerchantAccountResponse,
|
||||||
crate::types::api::admin::MerchantConnectorId,
|
crate::types::api::admin::MerchantConnectorId,
|
||||||
crate::types::api::admin::MerchantDetails,
|
crate::types::api::admin::MerchantDetails,
|
||||||
|
|||||||
Reference in New Issue
Block a user