mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat: add an api for toggling extended card info feature (#4444)
This commit is contained in:
@ -1088,3 +1088,10 @@ pub struct PaymentLinkConfig {
|
||||
/// Enable saved payment method option for payment link
|
||||
pub enabled_saved_payment_method: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||
pub struct ExtendedCardInfoChoice {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl common_utils::events::ApiEventMetric for ExtendedCardInfoChoice {}
|
||||
|
||||
@ -35,6 +35,7 @@ pub struct BusinessProfile {
|
||||
pub payment_link_config: Option<serde_json::Value>,
|
||||
pub session_expiry: Option<i64>,
|
||||
pub authentication_connector_details: Option<serde_json::Value>,
|
||||
pub is_extended_card_info_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
|
||||
@ -61,6 +62,7 @@ pub struct BusinessProfileNew {
|
||||
pub payment_link_config: Option<serde_json::Value>,
|
||||
pub session_expiry: Option<i64>,
|
||||
pub authentication_connector_details: Option<serde_json::Value>,
|
||||
pub is_extended_card_info_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
|
||||
@ -84,6 +86,84 @@ pub struct BusinessProfileUpdateInternal {
|
||||
pub payment_link_config: Option<serde_json::Value>,
|
||||
pub session_expiry: Option<i64>,
|
||||
pub authentication_connector_details: Option<serde_json::Value>,
|
||||
pub is_extended_card_info_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum BusinessProfileUpdate {
|
||||
Update {
|
||||
profile_name: Option<String>,
|
||||
modified_at: Option<time::PrimitiveDateTime>,
|
||||
return_url: Option<String>,
|
||||
enable_payment_response_hash: Option<bool>,
|
||||
payment_response_hash_key: Option<String>,
|
||||
redirect_to_merchant_with_http_post: Option<bool>,
|
||||
webhook_details: Option<serde_json::Value>,
|
||||
metadata: Option<pii::SecretSerdeValue>,
|
||||
routing_algorithm: Option<serde_json::Value>,
|
||||
intent_fulfillment_time: Option<i64>,
|
||||
frm_routing_algorithm: Option<serde_json::Value>,
|
||||
payout_routing_algorithm: Option<serde_json::Value>,
|
||||
is_recon_enabled: Option<bool>,
|
||||
applepay_verified_domains: Option<Vec<String>>,
|
||||
payment_link_config: Option<serde_json::Value>,
|
||||
session_expiry: Option<i64>,
|
||||
authentication_connector_details: Option<serde_json::Value>,
|
||||
},
|
||||
ExtendedCardInfoUpdate {
|
||||
is_extended_card_info_enabled: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<BusinessProfileUpdate> for BusinessProfileUpdateInternal {
|
||||
fn from(business_profile_update: BusinessProfileUpdate) -> Self {
|
||||
match business_profile_update {
|
||||
BusinessProfileUpdate::Update {
|
||||
profile_name,
|
||||
modified_at,
|
||||
return_url,
|
||||
enable_payment_response_hash,
|
||||
payment_response_hash_key,
|
||||
redirect_to_merchant_with_http_post,
|
||||
webhook_details,
|
||||
metadata,
|
||||
routing_algorithm,
|
||||
intent_fulfillment_time,
|
||||
frm_routing_algorithm,
|
||||
payout_routing_algorithm,
|
||||
is_recon_enabled,
|
||||
applepay_verified_domains,
|
||||
payment_link_config,
|
||||
session_expiry,
|
||||
authentication_connector_details,
|
||||
} => Self {
|
||||
profile_name,
|
||||
modified_at,
|
||||
return_url,
|
||||
enable_payment_response_hash,
|
||||
payment_response_hash_key,
|
||||
redirect_to_merchant_with_http_post,
|
||||
webhook_details,
|
||||
metadata,
|
||||
routing_algorithm,
|
||||
intent_fulfillment_time,
|
||||
frm_routing_algorithm,
|
||||
payout_routing_algorithm,
|
||||
is_recon_enabled,
|
||||
applepay_verified_domains,
|
||||
payment_link_config,
|
||||
session_expiry,
|
||||
authentication_connector_details,
|
||||
..Default::default()
|
||||
},
|
||||
BusinessProfileUpdate::ExtendedCardInfoUpdate {
|
||||
is_extended_card_info_enabled,
|
||||
} => Self {
|
||||
is_extended_card_info_enabled,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BusinessProfileNew> for BusinessProfile {
|
||||
@ -109,13 +189,14 @@ impl From<BusinessProfileNew> for BusinessProfile {
|
||||
payment_link_config: new.payment_link_config,
|
||||
session_expiry: new.session_expiry,
|
||||
authentication_connector_details: new.authentication_connector_details,
|
||||
is_extended_card_info_enabled: new.is_extended_card_info_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BusinessProfileUpdateInternal {
|
||||
impl BusinessProfileUpdate {
|
||||
pub fn apply_changeset(self, source: BusinessProfile) -> BusinessProfile {
|
||||
let Self {
|
||||
let BusinessProfileUpdateInternal {
|
||||
profile_name,
|
||||
modified_at: _,
|
||||
return_url,
|
||||
@ -133,7 +214,8 @@ impl BusinessProfileUpdateInternal {
|
||||
payment_link_config,
|
||||
session_expiry,
|
||||
authentication_connector_details,
|
||||
} = self;
|
||||
is_extended_card_info_enabled,
|
||||
} = self.into();
|
||||
BusinessProfile {
|
||||
profile_name: profile_name.unwrap_or(source.profile_name),
|
||||
modified_at: common_utils::date_time::now(),
|
||||
@ -154,6 +236,7 @@ impl BusinessProfileUpdateInternal {
|
||||
payment_link_config,
|
||||
session_expiry,
|
||||
authentication_connector_details,
|
||||
is_extended_card_info_enabled,
|
||||
..source
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@ use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, T
|
||||
|
||||
use super::generics;
|
||||
use crate::{
|
||||
business_profile::{BusinessProfile, BusinessProfileNew, BusinessProfileUpdateInternal},
|
||||
business_profile::{
|
||||
BusinessProfile, BusinessProfileNew, BusinessProfileUpdate, BusinessProfileUpdateInternal,
|
||||
},
|
||||
errors,
|
||||
schema::business_profile::dsl,
|
||||
PgPooledConn, StorageResult,
|
||||
@ -18,12 +20,12 @@ impl BusinessProfile {
|
||||
pub async fn update_by_profile_id(
|
||||
self,
|
||||
conn: &PgPooledConn,
|
||||
business_profile: BusinessProfileUpdateInternal,
|
||||
business_profile: BusinessProfileUpdate,
|
||||
) -> StorageResult<Self> {
|
||||
match generics::generic_update_by_id::<<Self as HasTable>::Table, _, _, _>(
|
||||
conn,
|
||||
self.profile_id.clone(),
|
||||
business_profile,
|
||||
BusinessProfileUpdateInternal::from(business_profile),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@ -193,6 +193,7 @@ diesel::table! {
|
||||
payment_link_config -> Nullable<Jsonb>,
|
||||
session_expiry -> Nullable<Int8>,
|
||||
authentication_connector_details -> Nullable<Jsonb>,
|
||||
is_extended_card_info_enabled -> Nullable<Bool>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1648,7 +1648,7 @@ pub async fn update_business_profile(
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let business_profile_update = storage::business_profile::BusinessProfileUpdateInternal {
|
||||
let business_profile_update = storage::business_profile::BusinessProfileUpdate::Update {
|
||||
profile_name: request.profile_name,
|
||||
modified_at: Some(date_time::now()),
|
||||
return_url: request.return_url.map(|return_url| return_url.to_string()),
|
||||
@ -1691,6 +1691,39 @@ pub async fn update_business_profile(
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn extended_card_info_toggle(
|
||||
state: AppState,
|
||||
profile_id: &str,
|
||||
ext_card_info_choice: admin_types::ExtendedCardInfoChoice,
|
||||
) -> RouterResponse<admin_types::ExtendedCardInfoChoice> {
|
||||
let db = state.store.as_ref();
|
||||
let business_profile = db
|
||||
.find_business_profile_by_profile_id(profile_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id.to_string(),
|
||||
})?;
|
||||
|
||||
if business_profile.is_extended_card_info_enabled.is_none()
|
||||
|| business_profile
|
||||
.is_extended_card_info_enabled
|
||||
.is_some_and(|existing_config| existing_config != ext_card_info_choice.enabled)
|
||||
{
|
||||
let business_profile_update =
|
||||
storage::business_profile::BusinessProfileUpdate::ExtendedCardInfoUpdate {
|
||||
is_extended_card_info_enabled: Some(ext_card_info_choice.enabled),
|
||||
};
|
||||
|
||||
db.update_business_profile_by_profile_id(business_profile, business_profile_update)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id.to_owned(),
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(service_api::ApplicationResponse::Json(ext_card_info_choice))
|
||||
}
|
||||
|
||||
pub(crate) fn validate_auth_and_metadata_type(
|
||||
connector_name: api_models::enums::Connector,
|
||||
val: &types::ConnectorAuthType,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use api_models::routing as routing_types;
|
||||
use common_utils::ext_traits::Encode;
|
||||
use diesel_models::{
|
||||
business_profile::{BusinessProfile, BusinessProfileUpdateInternal},
|
||||
business_profile::{BusinessProfile, BusinessProfileUpdate},
|
||||
configs,
|
||||
};
|
||||
use error_stack::ResultExt;
|
||||
@ -245,7 +245,7 @@ pub async fn update_business_profile_active_algorithm_ref(
|
||||
storage::enums::TransactionType::Payout => (None, Some(ref_val)),
|
||||
};
|
||||
|
||||
let business_profile_update = BusinessProfileUpdateInternal {
|
||||
let business_profile_update = BusinessProfileUpdate::Update {
|
||||
profile_name: None,
|
||||
return_url: None,
|
||||
enable_payment_response_hash: None,
|
||||
|
||||
@ -30,7 +30,7 @@ pub trait BusinessProfileInterface {
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
business_profile_update: business_profile::BusinessProfileUpdate,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError>;
|
||||
|
||||
async fn delete_business_profile_by_profile_id_merchant_id(
|
||||
@ -90,7 +90,7 @@ impl BusinessProfileInterface for Store {
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
business_profile_update: business_profile::BusinessProfileUpdate,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
storage::business_profile::BusinessProfile::update_by_profile_id(
|
||||
@ -169,7 +169,7 @@ impl BusinessProfileInterface for MockDb {
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
business_profile_update: business_profile::BusinessProfileUpdate,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
self.business_profiles
|
||||
.lock()
|
||||
|
||||
@ -2039,7 +2039,7 @@ impl BusinessProfileInterface for KafkaStore {
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
business_profile_update: business_profile::BusinessProfileUpdate,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
self.diesel_store
|
||||
.update_business_profile_by_profile_id(current_state, business_profile_update)
|
||||
|
||||
@ -612,3 +612,25 @@ pub async fn merchant_account_kv_status(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::ToggleExtendedCardInfo))]
|
||||
pub async fn toggle_extended_card_info(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(String, String)>,
|
||||
json_payload: web::Json<api_models::admin::ExtendedCardInfoChoice>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::ToggleExtendedCardInfo;
|
||||
let (_, profile_id) = path.into_inner();
|
||||
|
||||
Box::pin(api::server_wrap(
|
||||
flow,
|
||||
state,
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req, _| extended_card_info_toggle(state, &profile_id, req),
|
||||
&auth::AdminApiAuth,
|
||||
api_locking::LockAction::NotApplicable,
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
@ -1104,10 +1104,17 @@ impl BusinessProfile {
|
||||
.route(web::get().to(business_profiles_list)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/{profile_id}")
|
||||
.route(web::get().to(business_profile_retrieve))
|
||||
.route(web::post().to(business_profile_update))
|
||||
.route(web::delete().to(business_profile_delete)),
|
||||
web::scope("/{profile_id}")
|
||||
.service(
|
||||
web::resource("")
|
||||
.route(web::get().to(business_profile_retrieve))
|
||||
.route(web::post().to(business_profile_update))
|
||||
.route(web::delete().to(business_profile_delete)),
|
||||
)
|
||||
.service(
|
||||
web::resource("/toggle_extended_card_info")
|
||||
.route(web::post().to(toggle_extended_card_info)),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +166,8 @@ impl From<Flow> for ApiIdentifier {
|
||||
| Flow::BusinessProfileUpdate
|
||||
| Flow::BusinessProfileRetrieve
|
||||
| Flow::BusinessProfileDelete
|
||||
| Flow::BusinessProfileList => Self::Business,
|
||||
| Flow::BusinessProfileList
|
||||
| Flow::ToggleExtendedCardInfo => Self::Business,
|
||||
|
||||
Flow::PaymentLinkRetrieve
|
||||
| Flow::PaymentLinkInitiate
|
||||
|
||||
@ -175,6 +175,7 @@ impl ForeignTryFrom<(domain::MerchantAccount, BusinessProfileCreate)>
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "authentication_connector_details",
|
||||
})?,
|
||||
is_extended_card_info_enabled: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
pub use diesel_models::business_profile::{
|
||||
BusinessProfile, BusinessProfileNew, BusinessProfileUpdateInternal,
|
||||
BusinessProfile, BusinessProfileNew, BusinessProfileUpdate, BusinessProfileUpdateInternal,
|
||||
};
|
||||
|
||||
@ -406,6 +406,8 @@ pub enum Flow {
|
||||
WebhookEventDeliveryRetry,
|
||||
/// Retrieve status of the Poll
|
||||
RetrievePollStatus,
|
||||
/// Toggles the extended card info feature in profile level
|
||||
ToggleExtendedCardInfo,
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
|
||||
ALTER TABLE business_profile DROP COLUMN IF EXISTS is_extended_card_info_enabled;
|
||||
@ -0,0 +1,3 @@
|
||||
-- Your SQL goes here
|
||||
|
||||
ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_extended_card_info_enabled BOOLEAN DEFAULT FALSE;
|
||||
Reference in New Issue
Block a user