mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(payment_methods): Added value Field in required Field for Pre-filling (#1827)
Co-authored-by: Sarthak Soni <sarthak.soni@juspay.in> Co-authored-by: AkshayaFoiger <akshaya.shankar@juspay.in> Co-authored-by: Chethan Rao <70657455+Chethan-rao@users.noreply.github.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
use std::collections::HashSet;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use cards::CardNumber;
|
||||
use common_utils::{crypto::OptionalEncryptableName, pii};
|
||||
@ -220,7 +220,7 @@ pub struct ResponsePaymentMethodTypes {
|
||||
pub bank_transfers: Option<BankTransferTypes>,
|
||||
|
||||
/// Required fields for the payment_method_type.
|
||||
pub required_fields: Option<HashSet<RequiredFieldInfo>>,
|
||||
pub required_fields: Option<HashMap<String, RequiredFieldInfo>>,
|
||||
}
|
||||
|
||||
/// Required fields info used while listing the payment_method_data
|
||||
@ -235,6 +235,8 @@ pub struct RequiredFieldInfo {
|
||||
/// Possible field type of required field
|
||||
#[schema(value_type = FieldType)]
|
||||
pub field_type: api_enums::FieldType,
|
||||
|
||||
pub value: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -276,7 +276,14 @@ pub struct PaymentMethodType(pub HashMap<enums::PaymentMethodType, ConnectorFiel
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct ConnectorFields {
|
||||
pub fields: HashMap<enums::Connector, Vec<RequiredFieldInfo>>,
|
||||
pub fields: HashMap<enums::Connector, RequiredFieldFinal>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct RequiredFieldFinal {
|
||||
pub mandate: HashMap<String, RequiredFieldInfo>,
|
||||
pub non_mandate: HashMap<String, RequiredFieldInfo>,
|
||||
pub common: HashMap<String, RequiredFieldInfo>,
|
||||
}
|
||||
|
||||
fn string_set_deser<'a, D>(
|
||||
|
||||
@ -48,7 +48,7 @@ use crate::{
|
||||
api::{self, PaymentMethodCreateExt},
|
||||
domain::{self, types::decrypt},
|
||||
storage::{self, enums},
|
||||
transformers::ForeignInto,
|
||||
transformers::{ForeignFrom, ForeignInto},
|
||||
},
|
||||
utils::{self, ConnectorResponseExt, OptionExt},
|
||||
};
|
||||
@ -727,6 +727,13 @@ pub fn get_banks(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_val(str: String, val: &serde_json::Value) -> Option<String> {
|
||||
str.split('.')
|
||||
.fold(Some(val), |acc, x| acc.and_then(|v| v.get(x)))
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
}
|
||||
|
||||
pub async fn list_payment_methods(
|
||||
state: &routes::AppState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
@ -743,7 +750,7 @@ pub async fn list_payment_methods(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let address = payment_intent
|
||||
let shipping_address = payment_intent
|
||||
.as_ref()
|
||||
.async_map(|pi| async {
|
||||
helpers::get_address_by_id(db, pi.shipping_address_id.clone(), &key_store).await
|
||||
@ -752,6 +759,34 @@ pub async fn list_payment_methods(
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
let billing_address = payment_intent
|
||||
.as_ref()
|
||||
.async_map(|pi| async {
|
||||
helpers::get_address_by_id(db, pi.billing_address_id.clone(), &key_store).await
|
||||
})
|
||||
.await
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
let customer = payment_intent
|
||||
.as_ref()
|
||||
.async_and_then(|pi| async {
|
||||
pi.customer_id
|
||||
.as_ref()
|
||||
.async_and_then(|cust| async {
|
||||
db.find_customer_by_customer_id_merchant_id(
|
||||
cust.as_str(),
|
||||
&pi.merchant_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)
|
||||
.ok()
|
||||
})
|
||||
.await
|
||||
})
|
||||
.await;
|
||||
|
||||
let payment_attempt = payment_intent
|
||||
.as_ref()
|
||||
.async_map(|pi| async {
|
||||
@ -795,7 +830,7 @@ pub async fn list_payment_methods(
|
||||
&mut response,
|
||||
payment_intent.as_ref(),
|
||||
payment_attempt.as_ref(),
|
||||
address.as_ref(),
|
||||
shipping_address.as_ref(),
|
||||
mca.connector_name,
|
||||
pm_config_mapping,
|
||||
&state.conf.mandates.supported_payment_methods,
|
||||
@ -803,6 +838,13 @@ pub async fn list_payment_methods(
|
||||
.await?;
|
||||
}
|
||||
|
||||
let req = api_models::payments::PaymentsRequest::foreign_from((
|
||||
payment_attempt.as_ref(),
|
||||
shipping_address.as_ref(),
|
||||
billing_address.as_ref(),
|
||||
customer.as_ref(),
|
||||
));
|
||||
let req_val = serde_json::to_value(req).ok();
|
||||
logger::debug!(filtered_payment_methods=?response);
|
||||
|
||||
let mut payment_experiences_consolidated_hm: HashMap<
|
||||
@ -826,7 +868,7 @@ pub async fn list_payment_methods(
|
||||
|
||||
let mut required_fields_hm = HashMap::<
|
||||
api_enums::PaymentMethod,
|
||||
HashMap<api_enums::PaymentMethodType, HashSet<RequiredFieldInfo>>,
|
||||
HashMap<api_enums::PaymentMethodType, HashMap<String, RequiredFieldInfo>>,
|
||||
>::new();
|
||||
|
||||
for element in response.clone() {
|
||||
@ -853,15 +895,34 @@ pub async fn list_payment_methods(
|
||||
required_fields_hm_for_each_connector
|
||||
.fields
|
||||
.get(&connector_variant)
|
||||
.map(|required_fields_vec| {
|
||||
// If payment_method_type already exist in required_fields_hm, extend the required_fields hs to existing hs.
|
||||
let required_fields_hs =
|
||||
HashSet::from_iter(required_fields_vec.iter().cloned());
|
||||
.map(|required_fields_final| {
|
||||
let mut required_fields_hs = required_fields_final.common.clone();
|
||||
if let Some(pa) = payment_attempt.as_ref() {
|
||||
if let Some(_mandate) = &pa.mandate_details {
|
||||
required_fields_hs
|
||||
.extend(required_fields_final.mandate.clone());
|
||||
} else {
|
||||
required_fields_hs
|
||||
.extend(required_fields_final.non_mandate.clone());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (key, val) in &mut required_fields_hs {
|
||||
let temp = req_val
|
||||
.as_ref()
|
||||
.and_then(|r| get_val(key.to_owned(), r));
|
||||
if let Some(s) = temp {
|
||||
val.value = Some(s)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let existing_req_fields_hs = required_fields_hm
|
||||
.get_mut(&payment_method)
|
||||
.and_then(|inner_hm| inner_hm.get_mut(&payment_method_type));
|
||||
|
||||
// If payment_method_type already exist in required_fields_hm, extend the required_fields hs to existing hs.
|
||||
if let Some(inner_hs) = existing_req_fields_hs {
|
||||
inner_hs.extend(required_fields_hs);
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use api_models::enums as api_enums;
|
||||
use common_utils::{crypto::Encryptable, ext_traits::ValueExt};
|
||||
use common_utils::{crypto::Encryptable, ext_traits::ValueExt, pii};
|
||||
use diesel_models::enums as storage_enums;
|
||||
use error_stack::ResultExt;
|
||||
use masking::{ExposeInterface, PeekInterface};
|
||||
@ -573,3 +573,34 @@ impl ForeignFrom<api_models::enums::PayoutType> for api_enums::PaymentMethod {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
ForeignFrom<(
|
||||
Option<&storage::PaymentAttempt>,
|
||||
Option<&domain::Address>,
|
||||
Option<&domain::Address>,
|
||||
Option<&domain::Customer>,
|
||||
)> for api_models::payments::PaymentsRequest
|
||||
{
|
||||
fn foreign_from(
|
||||
value: (
|
||||
Option<&storage::PaymentAttempt>,
|
||||
Option<&domain::Address>,
|
||||
Option<&domain::Address>,
|
||||
Option<&domain::Customer>,
|
||||
),
|
||||
) -> Self {
|
||||
let (payment_attempt, shipping, billing, customer) = value;
|
||||
Self {
|
||||
currency: payment_attempt.map(|pa| pa.currency.unwrap_or_default()),
|
||||
shipping: shipping.map(api_types::Address::from),
|
||||
billing: billing.map(api_types::Address::from),
|
||||
amount: payment_attempt.map(|pa| api_types::Amount::from(pa.amount)),
|
||||
email: customer
|
||||
.and_then(|cust| cust.email.as_ref().map(|em| pii::Email::from(em.clone()))),
|
||||
phone: customer.and_then(|cust| cust.phone.as_ref().map(|p| p.clone().into_inner())),
|
||||
name: customer.and_then(|cust| cust.name.as_ref().map(|n| n.clone().into_inner())),
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9529,6 +9529,10 @@
|
||||
},
|
||||
"field_type": {
|
||||
"$ref": "#/components/schemas/FieldType"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user