refactor: move merchant_key_store table to accounts schema (#7746)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Hrithikesh
2025-04-08 17:19:46 +05:30
committed by GitHub
parent 5d5dbe0c26
commit e88672c97c
13 changed files with 180 additions and 38 deletions

View File

@ -19677,7 +19677,6 @@
"redirect_to_merchant_with_http_post",
"is_tax_connector_enabled",
"is_network_tokenization_enabled",
"should_collect_cvv_during_payment",
"is_click_to_pay_enabled",
"is_clear_pan_retries_enabled"
],
@ -19858,7 +19857,8 @@
},
"should_collect_cvv_during_payment": {
"type": "boolean",
"description": "Indicates if CVV should be collected during payment or not."
"description": "Indicates if CVV should be collected during payment or not.",
"nullable": true
},
"is_click_to_pay_enabled": {
"type": "boolean",

View File

@ -1,7 +1,6 @@
use std::collections::{HashMap, HashSet};
#[cfg(feature = "v1")]
use common_types::primitive_wrappers::AlwaysRequestExtendedAuthorization;
use common_types::primitive_wrappers;
use common_utils::{
consts,
crypto::Encryptable,
@ -1966,7 +1965,8 @@ pub struct ProfileCreate {
/// Bool indicating if extended authentication must be requested for all payments
#[schema(value_type = Option<bool>)]
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
/// Indicates if click to pay is enabled or not.
#[serde(default)]
@ -2256,7 +2256,8 @@ pub struct ProfileResponse {
/// Bool indicating if extended authentication must be requested for all payments
#[schema(value_type = Option<bool>)]
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
/// Indicates if click to pay is enabled or not.
#[schema(default = false, example = false)]
@ -2397,7 +2398,9 @@ pub struct ProfileResponse {
pub is_network_tokenization_enabled: bool,
/// Indicates if CVV should be collected during payment or not.
pub should_collect_cvv_during_payment: bool,
#[schema(value_type = Option<bool>)]
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
/// Indicates if click to pay is enabled or not.
#[schema(default = false, example = false)]

View File

@ -4,6 +4,7 @@ use diesel::{
backend::Backend,
deserialize,
deserialize::FromSql,
serialize::ToSql,
sql_types::{Json, Jsonb},
AsExpression, Queryable,
};
@ -28,6 +29,69 @@ pub struct PaymentMethodsEnabled {
pub payment_method_subtypes: Option<Vec<RequestPaymentMethodTypes>>,
}
// Custom FromSql implmentation to handle deserialization of v1 data format
impl FromSql<Json, diesel::pg::Pg> for PaymentMethodsEnabled {
fn from_sql(bytes: <diesel::pg::Pg as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
let helper: PaymentMethodsEnabledHelper = serde_json::from_slice(bytes.as_bytes())
.map_err(|e| Box::new(diesel::result::Error::DeserializationError(Box::new(e))))?;
Ok(helper.into())
}
}
// In this ToSql implementation, we are directly serializing the PaymentMethodsEnabled struct to JSON
impl ToSql<Json, diesel::pg::Pg> for PaymentMethodsEnabled {
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
) -> diesel::serialize::Result {
let value = serde_json::to_value(self)?;
// the function `reborrow` only works in case of `Pg` backend. But, in case of other backends
// please refer to the diesel migration blog:
// https://github.com/Diesel-rs/Diesel/blob/master/guide_drafts/migration_guide.md#changed-tosql-implementations
<serde_json::Value as ToSql<Json, diesel::pg::Pg>>::to_sql(&value, &mut out.reborrow())
}
}
// Intermediate type to handle deserialization of v1 data format of PaymentMethodsEnabled
#[derive(serde::Deserialize)]
#[serde(untagged)]
enum PaymentMethodsEnabledHelper {
V2 {
payment_method_type: common_enums::PaymentMethod,
payment_method_subtypes: Option<Vec<RequestPaymentMethodTypes>>,
},
V1 {
payment_method: common_enums::PaymentMethod,
payment_method_types: Option<Vec<RequestPaymentMethodTypesV1>>,
},
}
impl From<PaymentMethodsEnabledHelper> for PaymentMethodsEnabled {
fn from(helper: PaymentMethodsEnabledHelper) -> Self {
match helper {
PaymentMethodsEnabledHelper::V2 {
payment_method_type,
payment_method_subtypes,
} => Self {
payment_method_type,
payment_method_subtypes,
},
PaymentMethodsEnabledHelper::V1 {
payment_method,
payment_method_types,
} => Self {
payment_method_type: payment_method,
payment_method_subtypes: payment_method_types.map(|subtypes| {
subtypes
.into_iter()
.map(RequestPaymentMethodTypes::from)
.collect()
}),
},
}
}
}
impl PaymentMethodsEnabled {
/// Get payment_method_type
#[cfg(feature = "v2")]
@ -92,6 +156,35 @@ pub struct RequestPaymentMethodTypes {
pub installment_payment_enabled: bool,
}
impl From<RequestPaymentMethodTypesV1> for RequestPaymentMethodTypes {
fn from(value: RequestPaymentMethodTypesV1) -> Self {
Self {
payment_method_subtype: value.payment_method_type,
payment_experience: value.payment_experience,
card_networks: value.card_networks,
accepted_currencies: value.accepted_currencies,
accepted_countries: value.accepted_countries,
minimum_amount: value.minimum_amount,
maximum_amount: value.maximum_amount,
recurring_enabled: value.recurring_enabled,
installment_payment_enabled: value.installment_payment_enabled,
}
}
}
#[derive(serde::Deserialize)]
struct RequestPaymentMethodTypesV1 {
pub payment_method_type: common_enums::PaymentMethodType,
pub payment_experience: Option<common_enums::PaymentExperience>,
pub card_networks: Option<Vec<common_enums::CardNetwork>>,
pub accepted_currencies: Option<AcceptedCurrencies>,
pub accepted_countries: Option<AcceptedCountries>,
pub minimum_amount: Option<common_utils::types::MinorUnit>,
pub maximum_amount: Option<common_utils::types::MinorUnit>,
pub recurring_enabled: bool,
pub installment_payment_enabled: bool,
}
impl RequestPaymentMethodTypes {
///Get payment_method_subtype
pub fn get_payment_method_type(&self) -> Option<common_enums::PaymentMethodType> {
@ -153,8 +246,6 @@ where
}
}
common_utils::impl_to_sql_from_sql_json!(PaymentMethodsEnabled);
/// The network tokenization configuration for creating the payment method session
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct NetworkTokenization {

View File

@ -128,4 +128,46 @@ mod bool_wrappers {
bool::from_sql(value).map(Self)
}
}
/// Bool that represents if Cvv should be collected during payment or not. Default is true
#[derive(
Clone, Copy, Debug, Eq, PartialEq, diesel::expression::AsExpression, Serialize, Deserialize,
)]
#[diesel(sql_type = diesel::sql_types::Bool)]
pub struct ShouldCollectCvvDuringPayment(bool);
impl Deref for ShouldCollectCvvDuringPayment {
type Target = bool;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<DB> diesel::serialize::ToSql<diesel::sql_types::Bool, DB> for ShouldCollectCvvDuringPayment
where
DB: diesel::backend::Backend,
bool: diesel::serialize::ToSql<diesel::sql_types::Bool, DB>,
{
fn to_sql<'b>(
&'b self,
out: &mut diesel::serialize::Output<'b, '_, DB>,
) -> diesel::serialize::Result {
self.0.to_sql(out)
}
}
impl<DB> diesel::deserialize::FromSql<diesel::sql_types::Bool, DB> for ShouldCollectCvvDuringPayment
where
DB: diesel::backend::Backend,
bool: diesel::deserialize::FromSql<diesel::sql_types::Bool, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
bool::from_sql(value).map(Self)
}
}
impl Default for ShouldCollectCvvDuringPayment {
/// Default for `ShouldCollectCvvDuringPayment` is `true`
fn default() -> Self {
Self(true)
}
}
}

View File

@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet};
use common_enums::{AuthenticationConnectors, UIWidgetFormLayout};
use common_types::primitive_wrappers::AlwaysRequestExtendedAuthorization;
use common_types::primitive_wrappers;
use common_utils::{encryption::Encryption, pii};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use masking::Secret;
@ -58,7 +58,8 @@ pub struct Profile {
pub is_network_tokenization_enabled: bool,
pub is_auto_retries_enabled: Option<bool>,
pub max_auto_retries_enabled: Option<i16>,
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
pub is_click_to_pay_enabled: bool,
pub authentication_product_ids:
Option<common_types::payments::AuthenticationConnectorAccountMap>,
@ -162,7 +163,8 @@ pub struct ProfileUpdateInternal {
pub is_network_tokenization_enabled: Option<bool>,
pub is_auto_retries_enabled: Option<bool>,
pub max_auto_retries_enabled: Option<i16>,
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
pub is_click_to_pay_enabled: Option<bool>,
pub authentication_product_ids:
Option<common_types::payments::AuthenticationConnectorAccountMap>,
@ -341,7 +343,8 @@ pub struct Profile {
pub is_network_tokenization_enabled: bool,
pub is_auto_retries_enabled: Option<bool>,
pub max_auto_retries_enabled: Option<i16>,
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
pub is_click_to_pay_enabled: bool,
pub authentication_product_ids:
Option<common_types::payments::AuthenticationConnectorAccountMap>,
@ -359,7 +362,8 @@ pub struct Profile {
pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
pub default_fallback_routing: Option<pii::SecretSerdeValue>,
pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
pub should_collect_cvv_during_payment: bool,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
}
impl Profile {
@ -425,7 +429,8 @@ pub struct ProfileNew {
pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
pub default_fallback_routing: Option<pii::SecretSerdeValue>,
pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
pub should_collect_cvv_during_payment: bool,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
pub id: common_utils::id_type::ProfileId,
}
@ -477,7 +482,8 @@ pub struct ProfileUpdateInternal {
pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
pub default_fallback_routing: Option<pii::SecretSerdeValue>,
pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
pub should_collect_cvv_during_payment: Option<bool>,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
}
#[cfg(feature = "v2")]
@ -584,7 +590,7 @@ impl ProfileUpdateInternal {
.or(source.payout_routing_algorithm_id),
default_fallback_routing: default_fallback_routing.or(source.default_fallback_routing),
should_collect_cvv_during_payment: should_collect_cvv_during_payment
.unwrap_or(source.should_collect_cvv_during_payment),
.or(source.should_collect_cvv_during_payment),
version: source.version,
dynamic_routing_algorithm: None,
is_network_tokenization_enabled: is_network_tokenization_enabled

View File

@ -231,7 +231,7 @@ diesel::table! {
payout_routing_algorithm_id -> Nullable<Varchar>,
default_fallback_routing -> Nullable<Jsonb>,
three_ds_decision_manager_config -> Nullable<Jsonb>,
should_collect_cvv_during_payment -> Bool,
should_collect_cvv_during_payment -> Nullable<Bool>,
}
}

View File

@ -1,5 +1,5 @@
use common_enums::enums as api_enums;
use common_types::primitive_wrappers::AlwaysRequestExtendedAuthorization;
use common_types::primitive_wrappers;
use common_utils::{
crypto::{OptionalEncryptableName, OptionalEncryptableValue},
date_time,
@ -57,7 +57,8 @@ pub struct Profile {
pub is_network_tokenization_enabled: bool,
pub is_auto_retries_enabled: bool,
pub max_auto_retries_enabled: Option<i16>,
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
pub is_click_to_pay_enabled: bool,
pub authentication_product_ids:
Option<common_types::payments::AuthenticationConnectorAccountMap>,
@ -107,7 +108,8 @@ pub struct ProfileSetter {
pub is_network_tokenization_enabled: bool,
pub is_auto_retries_enabled: bool,
pub max_auto_retries_enabled: Option<i16>,
pub always_request_extended_authorization: Option<AlwaysRequestExtendedAuthorization>,
pub always_request_extended_authorization:
Option<primitive_wrappers::AlwaysRequestExtendedAuthorization>,
pub is_click_to_pay_enabled: bool,
pub authentication_product_ids:
Option<common_types::payments::AuthenticationConnectorAccountMap>,
@ -884,7 +886,8 @@ pub struct Profile {
pub frm_routing_algorithm_id: Option<String>,
pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
pub default_fallback_routing: Option<pii::SecretSerdeValue>,
pub should_collect_cvv_during_payment: bool,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
pub tax_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub is_tax_connector_enabled: bool,
pub version: common_enums::ApiVersion,
@ -934,7 +937,8 @@ pub struct ProfileSetter {
pub frm_routing_algorithm_id: Option<String>,
pub payout_routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
pub default_fallback_routing: Option<pii::SecretSerdeValue>,
pub should_collect_cvv_during_payment: bool,
pub should_collect_cvv_during_payment:
Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
pub tax_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub is_tax_connector_enabled: bool,
pub is_network_tokenization_enabled: bool,
@ -1083,7 +1087,7 @@ pub enum ProfileUpdate {
is_network_tokenization_enabled: bool,
},
CollectCvvDuringPaymentUpdate {
should_collect_cvv_during_payment: bool,
should_collect_cvv_during_payment: primitive_wrappers::ShouldCollectCvvDuringPayment,
},
DecisionManagerRecordUpdate {
three_ds_decision_manager_config: common_types::payments::DecisionManagerRecord,

View File

@ -3946,7 +3946,7 @@ impl ProfileCreateBridge for api::ProfileCreate {
.or(Some(common_utils::consts::DEFAULT_ORDER_FULFILLMENT_TIME)),
order_fulfillment_time_origin: self.order_fulfillment_time_origin,
default_fallback_routing: None,
should_collect_cvv_during_payment: false,
should_collect_cvv_during_payment: None,
tax_connector_id: self.tax_connector_id,
is_tax_connector_enabled: self.is_tax_connector_enabled,
is_network_tokenization_enabled: self.is_network_tokenization_enabled,

View File

@ -168,6 +168,7 @@ pub trait AccountsStorageInterface:
+ merchant_account::MerchantAccountInterface
+ business_profile::ProfileInterface
+ merchant_connector_account::MerchantConnectorAccountInterface
+ merchant_key_store::MerchantKeyStoreInterface
+ 'static
{
}

View File

@ -63,7 +63,7 @@ impl MerchantKeyStoreInterface for Store {
merchant_key_store: domain::MerchantKeyStore,
key: &Secret<Vec<u8>>,
) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
let conn = connection::pg_connection_write(self).await?;
let conn = connection::pg_accounts_connection_write(self).await?;
let merchant_id = merchant_key_store.merchant_id.clone();
merchant_key_store
.construct_new()
@ -85,7 +85,7 @@ impl MerchantKeyStoreInterface for Store {
key: &Secret<Vec<u8>>,
) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
let fetch_func = || async {
let conn = connection::pg_connection_read(self).await?;
let conn = connection::pg_accounts_connection_read(self).await?;
diesel_models::merchant_key_store::MerchantKeyStore::find_by_merchant_id(
&conn,
@ -127,7 +127,7 @@ impl MerchantKeyStoreInterface for Store {
merchant_id: &common_utils::id_type::MerchantId,
) -> CustomResult<bool, errors::StorageError> {
let delete_func = || async {
let conn = connection::pg_connection_write(self).await?;
let conn = connection::pg_accounts_connection_write(self).await?;
diesel_models::merchant_key_store::MerchantKeyStore::delete_by_merchant_id(
&conn,
merchant_id,
@ -163,7 +163,7 @@ impl MerchantKeyStoreInterface for Store {
key: &Secret<Vec<u8>>,
) -> CustomResult<Vec<domain::MerchantKeyStore>, errors::StorageError> {
let fetch_func = || async {
let conn = connection::pg_connection_read(self).await?;
let conn = connection::pg_accounts_connection_read(self).await?;
diesel_models::merchant_key_store::MerchantKeyStore::list_multiple_key_stores(
&conn,
@ -190,7 +190,7 @@ impl MerchantKeyStoreInterface for Store {
from: u32,
to: u32,
) -> CustomResult<Vec<domain::MerchantKeyStore>, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
let conn = connection::pg_accounts_connection_read(self).await?;
let stores = diesel_models::merchant_key_store::MerchantKeyStore::list_all_key_stores(
&conn, from, to,
)

View File

@ -9,6 +9,8 @@ use cards::CardNumber;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use cards::{CardNumber, NetworkToken};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use common_types::primitive_wrappers;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use common_utils::generate_id;
use common_utils::id_type;
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@ -123,7 +125,7 @@ impl VaultingInterface for VaultDelete {
pub struct SavedPMLPaymentsInfo {
pub payment_intent: storage::PaymentIntent,
pub profile: domain::Profile,
pub collect_cvv_during_payment: bool,
pub collect_cvv_during_payment: Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
pub off_session_payment_flag: bool,
pub is_connector_agnostic_mit_enabled: bool,
}

View File

@ -3,10 +3,6 @@ ALTER TABLE customers
ALTER COLUMN status DROP NOT NULL,
ALTER COLUMN status DROP DEFAULT;
---------------------business_profile---------------------
ALTER TABLE business_profile ALTER COLUMN should_collect_cvv_during_payment DROP NOT NULL;
ALTER TABLE merchant_connector_account
ALTER COLUMN profile_id DROP NOT NULL;

View File

@ -4,9 +4,6 @@ ALTER TABLE customers
ALTER COLUMN status SET NOT NULL,
ALTER COLUMN status SET DEFAULT 'active';
---------------------business_profile---------------------
ALTER TABLE business_profile ALTER COLUMN should_collect_cvv_during_payment SET NOT NULL;
-- This migration is to make profile_id mandatory in mca table
ALTER TABLE merchant_connector_account
ALTER COLUMN profile_id SET NOT NULL;