feat: Add network_token creds on merchant/profile tables

This commit is contained in:
Sarthak Soni
2026-03-12 16:18:07 +05:30
parent 747ed7e459
commit 1dfad52b07
13 changed files with 216 additions and 1 deletions

View File

@@ -117,6 +117,10 @@ pub struct MerchantAccountCreate {
/// Merchant Account Type of this merchant account
#[schema(value_type = Option<MerchantAccountType>, example = "standard")]
pub merchant_account_type: Option<api_enums::MerchantAccountType>,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[cfg(feature = "v1")]
@@ -393,6 +397,10 @@ pub struct MerchantAccountUpdate {
/// Default payment method collect link config
#[schema(value_type = Option<BusinessCollectLinkConfig>)]
pub pm_collect_link_config: Option<BusinessCollectLinkConfig>,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[cfg(feature = "v1")]
@@ -595,6 +603,10 @@ pub struct MerchantAccountResponse {
/// Merchant Account Type of this merchant account
#[schema(value_type = MerchantAccountType, example = "standard")]
pub merchant_account_type: api_enums::MerchantAccountType,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[cfg(feature = "v2")]
@@ -677,6 +689,34 @@ pub struct MerchantDetails {
#[schema(value_type = Option<String>, example = "123456789")]
pub merchant_tax_registration_id: Option<Secret<String>>,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "snake_case")]
pub enum NetworkTokeizationProviderCredentials {
JuspayTokenService(JuspayNetworkTokenizationCredentials),
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
#[serde(rename_all = "snake_case")]
pub struct JuspayNetworkTokenizationCredentials {
/// The API key to contact the network tokenization provider
#[schema(value_type = String, max_length = 255, example = "AH3423bkjbkjdsfbkj")]
pub token_service_api_key: Secret<String>,
/// The public key to encrypt the card details before sending to the network tokenization provider
#[schema(value_type = String, max_length = 255, example = "AH3423bkjbkjdsfbkj")]
pub public_key: Secret<String>,
/// The private key to decrypt the tokenized card details received from the network tokenization provider
#[schema(value_type = String, max_length = 255, example = "AH3423bkjbkjdsfbkj")]
pub private_key: Secret<String>,
/// The key_id used in encryption
#[schema(value_type = String, max_length = 255, example = "AH3423bkjbkjdsfbkj")]
pub key_id: Secret<String>,
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct PrimaryBusinessDetails {
@@ -2276,6 +2316,10 @@ pub struct ProfileCreate {
/// Flag to enable Level 2 and Level 3 processing data for card transactions
#[schema(value_type = Option<bool>)]
pub is_l2_l3_enabled: Option<bool>,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[nutype::nutype(
@@ -2649,6 +2693,10 @@ pub struct ProfileResponse {
/// Flag to enable Level 2 and Level 3 processing data for card transactions
#[schema(value_type = Option<bool>)]
pub is_l2_l3_enabled: Option<bool>,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[cfg(feature = "v2")]
@@ -3025,6 +3073,10 @@ pub struct ProfileUpdate {
/// Flag to enable Level 2 and Level 3 processing data for card transactions
#[schema(value_type = Option<bool>)]
pub is_l2_l3_enabled: Option<bool>,
/// Network tokenization credentials for this merchant account
#[schema(value_type = Option<NetworkTokeizationProviderCredentials>)]
pub network_tokenization_credentials: Option<NetworkTokeizationProviderCredentials>,
}
#[cfg(feature = "v2")]

View File

@@ -84,6 +84,7 @@ pub struct Profile {
pub is_external_vault_enabled: Option<bool>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
pub is_l2_l3_enabled: Option<bool>,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -147,6 +148,7 @@ pub struct ProfileNew {
pub is_external_vault_enabled: Option<bool>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
pub is_l2_l3_enabled: Option<bool>,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -211,6 +213,7 @@ pub struct ProfileUpdateInternal {
pub billing_processor_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub is_external_vault_enabled: Option<bool>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -272,6 +275,7 @@ impl ProfileUpdateInternal {
is_external_vault_enabled,
external_vault_connector_details,
billing_processor_id,
network_tokenization_credentials,
} = self;
Profile {
profile_id: source.profile_id,
@@ -367,6 +371,8 @@ impl ProfileUpdateInternal {
external_vault_connector_details: external_vault_connector_details
.or(source.external_vault_connector_details),
billing_processor_id: billing_processor_id.or(source.billing_processor_id),
network_tokenization_credentials: network_tokenization_credentials
.or(source.network_tokenization_credentials),
}
}
}

View File

@@ -55,6 +55,7 @@ pub struct MerchantAccount {
pub id: Option<common_utils::id_type::MerchantId>,
pub product_type: Option<common_enums::MerchantProductType>,
pub merchant_account_type: Option<common_enums::MerchantAccountType>,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -90,6 +91,7 @@ pub struct MerchantAccountSetter {
pub is_platform_account: bool,
pub product_type: Option<common_enums::MerchantProductType>,
pub merchant_account_type: common_enums::MerchantAccountType,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -128,6 +130,7 @@ impl From<MerchantAccountSetter> for MerchantAccount {
is_platform_account: item.is_platform_account,
product_type: item.product_type,
merchant_account_type: Some(item.merchant_account_type),
network_tokenization_credentials: item.network_tokenization_credentials,
}
}
}
@@ -252,6 +255,7 @@ pub struct MerchantAccountNew {
pub id: Option<common_utils::id_type::MerchantId>,
pub product_type: Option<common_enums::MerchantProductType>,
pub merchant_account_type: common_enums::MerchantAccountType,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v2")]
@@ -355,6 +359,7 @@ pub struct MerchantAccountUpdateInternal {
pub pm_collect_link_config: Option<serde_json::Value>,
pub is_platform_account: Option<bool>,
pub product_type: Option<common_enums::MerchantProductType>,
pub network_tokenization_credentials: Option<Encryption>,
}
#[cfg(feature = "v1")]
@@ -388,6 +393,7 @@ impl MerchantAccountUpdateInternal {
pm_collect_link_config,
is_platform_account,
product_type,
network_tokenization_credentials,
} = self;
MerchantAccount {
@@ -427,6 +433,8 @@ impl MerchantAccountUpdateInternal {
id: source.id,
product_type: product_type.or(source.product_type),
merchant_account_type: source.merchant_account_type,
network_tokenization_credentials: network_tokenization_credentials
.or(source.network_tokenization_credentials),
}
}
}

View File

@@ -295,6 +295,7 @@ diesel::table! {
is_external_vault_enabled -> Nullable<Bool>,
external_vault_connector_details -> Nullable<Jsonb>,
is_l2_l3_enabled -> Nullable<Bool>,
network_tokenization_credentials -> Nullable<Bytea>,
}
}
@@ -933,6 +934,7 @@ diesel::table! {
product_type -> Nullable<Varchar>,
#[max_length = 64]
merchant_account_type -> Nullable<Varchar>,
network_tokenization_credentials -> Nullable<Bytea>,
}
}

View File

@@ -91,6 +91,7 @@ pub struct Profile {
pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
pub external_vault_details: ExternalVaultDetails,
pub billing_processor_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub network_tokenization_credentials: OptionalEncryptableValue,
}
#[cfg(feature = "v1")]
@@ -249,6 +250,7 @@ pub struct ProfileSetter {
pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
pub external_vault_details: ExternalVaultDetails,
pub billing_processor_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub network_tokenization_credentials: OptionalEncryptableValue,
}
#[cfg(feature = "v1")]
@@ -317,6 +319,7 @@ impl From<ProfileSetter> for Profile {
always_enable_overcapture: value.always_enable_overcapture,
external_vault_details: value.external_vault_details,
billing_processor_id: value.billing_processor_id,
network_tokenization_credentials: value.network_tokenization_credentials,
}
}
}
@@ -388,6 +391,7 @@ pub struct ProfileGeneralUpdate {
pub is_external_vault_enabled: Option<common_enums::ExternalVaultEnabled>,
pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
pub billing_processor_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub network_tokenization_credentials: OptionalEncryptableValue,
}
#[cfg(feature = "v1")]
@@ -410,6 +414,7 @@ pub enum ProfileUpdate {
},
NetworkTokenizationUpdate {
is_network_tokenization_enabled: bool,
network_tokenization_credentials: OptionalEncryptableValue,
},
CardTestingSecretKeyUpdate {
card_testing_secret_key: OptionalEncryptableName,
@@ -477,6 +482,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
is_external_vault_enabled,
external_vault_connector_details,
billing_processor_id,
network_tokenization_credentials,
} = *update;
let is_external_vault_enabled = match is_external_vault_enabled {
@@ -544,6 +550,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
is_external_vault_enabled,
external_vault_connector_details,
billing_processor_id,
network_tokenization_credentials: network_tokenization_credentials
.map(Encryption::from),
}
}
ProfileUpdate::RoutingAlgorithmUpdate {
@@ -606,6 +614,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
ProfileUpdate::DynamicRoutingAlgorithmUpdate {
dynamic_routing_algorithm,
@@ -665,6 +674,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
ProfileUpdate::ExtendedCardInfoUpdate {
is_extended_card_info_enabled,
@@ -724,6 +734,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
ProfileUpdate::ConnectorAgnosticMitUpdate {
is_connector_agnostic_mit_enabled,
@@ -783,9 +794,11 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
ProfileUpdate::NetworkTokenizationUpdate {
is_network_tokenization_enabled,
network_tokenization_credentials,
} => Self {
profile_name: None,
modified_at: now,
@@ -842,6 +855,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: network_tokenization_credentials
.map(Encryption::from),
},
ProfileUpdate::CardTestingSecretKeyUpdate {
card_testing_secret_key,
@@ -901,6 +916,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
ProfileUpdate::AcquirerConfigMapUpdate {
acquirer_config_map,
@@ -960,6 +976,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
external_vault_connector_details: None,
billing_processor_id: None,
is_l2_l3_enabled: None,
network_tokenization_credentials: None,
},
}
}
@@ -1042,6 +1059,9 @@ impl Conversion for Profile {
is_external_vault_enabled,
external_vault_connector_details,
billing_processor_id: self.billing_processor_id,
network_tokenization_credentials: self
.network_tokenization_credentials
.map(|name| name.into()),
})
}
@@ -1055,7 +1075,11 @@ impl Conversion for Profile {
Self: Sized,
{
// Decrypt encrypted fields first
let (outgoing_webhook_custom_http_headers, card_testing_secret_key) = async {
let (
outgoing_webhook_custom_http_headers,
card_testing_secret_key,
network_tokenization_credentials,
) = async {
let outgoing_webhook_custom_http_headers = item
.outgoing_webhook_custom_http_headers
.async_lift(|inner| async {
@@ -1086,9 +1110,25 @@ impl Conversion for Profile {
})
.await?;
let network_tokenization_credentials = item
.network_tokenization_credentials
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?;
Ok::<_, error_stack::Report<common_utils::errors::CryptoError>>((
outgoing_webhook_custom_http_headers,
card_testing_secret_key,
network_tokenization_credentials,
))
}
.await
@@ -1167,6 +1207,7 @@ impl Conversion for Profile {
always_enable_overcapture: item.always_enable_overcapture,
external_vault_details,
billing_processor_id: item.billing_processor_id,
network_tokenization_credentials,
})
}
@@ -1236,6 +1277,9 @@ impl Conversion for Profile {
is_external_vault_enabled,
external_vault_connector_details,
billing_processor_id: self.billing_processor_id,
network_tokenization_credentials: self
.network_tokenization_credentials
.map(|name| name.into()),
})
}
}

View File

@@ -54,6 +54,7 @@ pub struct MerchantAccount {
pub is_platform_account: bool,
pub product_type: Option<common_enums::MerchantProductType>,
pub merchant_account_type: common_enums::MerchantAccountType,
pub network_tokenization_credentials: OptionalEncryptableValue,
}
#[cfg(feature = "v1")]
@@ -91,6 +92,7 @@ pub struct MerchantAccountSetter {
pub is_platform_account: bool,
pub product_type: Option<common_enums::MerchantProductType>,
pub merchant_account_type: common_enums::MerchantAccountType,
pub network_tokenization_credentials: OptionalEncryptableValue,
}
#[cfg(feature = "v1")]
@@ -128,6 +130,7 @@ impl From<MerchantAccountSetter> for MerchantAccount {
is_platform_account: item.is_platform_account,
product_type: item.product_type,
merchant_account_type: item.merchant_account_type,
network_tokenization_credentials: item.network_tokenization_credentials,
}
}
}
@@ -283,6 +286,7 @@ pub enum MerchantAccountUpdate {
default_profile: Option<Option<common_utils::id_type::ProfileId>>,
payment_link_config: Option<serde_json::Value>,
pm_collect_link_config: Option<serde_json::Value>,
network_tokenization_credentials: OptionalEncryptableValue,
},
StorageSchemeUpdate {
storage_scheme: MerchantStorageScheme,
@@ -339,6 +343,7 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
default_profile,
payment_link_config,
pm_collect_link_config,
network_tokenization_credentials,
} => Self {
merchant_name: merchant_name.map(Encryption::from),
merchant_details: merchant_details.map(Encryption::from),
@@ -367,6 +372,8 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
recon_status: None,
is_platform_account: None,
product_type: None,
network_tokenization_credentials: network_tokenization_credentials
.map(Encryption::from),
},
MerchantAccountUpdate::StorageSchemeUpdate { storage_scheme } => Self {
storage_scheme: Some(storage_scheme),
@@ -396,6 +403,7 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
pm_collect_link_config: None,
is_platform_account: None,
product_type: None,
network_tokenization_credentials: None,
},
MerchantAccountUpdate::ReconUpdate { recon_status } => Self {
recon_status: Some(recon_status),
@@ -425,6 +433,7 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
pm_collect_link_config: None,
is_platform_account: None,
product_type: None,
network_tokenization_credentials: None,
},
MerchantAccountUpdate::UnsetDefaultProfile => Self {
default_profile: Some(None),
@@ -454,6 +463,7 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
pm_collect_link_config: None,
is_platform_account: None,
product_type: None,
network_tokenization_credentials: None,
},
MerchantAccountUpdate::ModifiedAtUpdate => Self {
modified_at: now,
@@ -483,6 +493,7 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
pm_collect_link_config: None,
is_platform_account: None,
product_type: None,
network_tokenization_credentials: None,
},
}
}
@@ -705,6 +716,9 @@ impl Conversion for MerchantAccount {
is_platform_account: self.is_platform_account,
product_type: self.product_type,
merchant_account_type: self.merchant_account_type,
network_tokenization_credentials: self
.network_tokenization_credentials
.map(|credentials| credentials.into()),
};
Ok(diesel_models::MerchantAccount::from(setter))
@@ -785,6 +799,20 @@ impl Conversion for MerchantAccount {
is_platform_account: item.is_platform_account,
product_type: item.product_type,
merchant_account_type: item.merchant_account_type.unwrap_or_default(),
network_tokenization_credentials: item
.network_tokenization_credentials
.async_lift(|inner| async {
crypto_operation(
state,
type_name!(Self::DstType),
CryptoOperation::DecryptOptional(inner),
key_manager_identifier.clone(),
key.peek(),
)
.await
.and_then(|val| val.try_into_optionaloperation())
})
.await?,
})
}
.await
@@ -829,6 +857,9 @@ impl Conversion for MerchantAccount {
.product_type
.or(Some(common_enums::MerchantProductType::Orchestration)),
merchant_account_type: self.merchant_account_type,
network_tokenization_credentials: self
.network_tokenization_credentials
.map(|credentials| credentials.into()),
})
}
}

View File

@@ -216,6 +216,7 @@ fn create_platform_merchant_account_request(
payout_routing_algorithm: None,
pm_collect_link_config: None,
product_type: Some(consts::user::DEFAULT_PRODUCT_TYPE),
network_tokenization_credentials: None, // should this be none?
}
}
@@ -567,6 +568,14 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate {
let key = key_store.key.clone().into_inner();
let key_manager_state = state.into();
let network_tokenization_credentials = self
.network_tokenization_credentials
.async_map(|value| cards::create_encrypted_data(&key_manager_state, &key_store, value))
.await
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt network_tokenization_credentials")?;
let merchant_account = async {
Ok::<_, error_stack::Report<common_utils::errors::CryptoError>>(
domain::MerchantAccountSetter {
@@ -634,6 +643,7 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate {
is_platform_account: false,
product_type: self.product_type,
merchant_account_type,
network_tokenization_credentials,
},
)
}
@@ -1188,6 +1198,14 @@ impl MerchantAccountUpdateBridge for api::MerchantAccountUpdate {
})
.await;
let network_tokenization_credentials = self
.network_tokenization_credentials
.async_map(|value| cards::create_encrypted_data(&key_manager_state, &key_store, value))
.await
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt network_tokenization_credentials")?;
let identifier = km_types::Identifier::Merchant(key_store.merchant_id.clone());
Ok(storage::MerchantAccountUpdate::Update {
merchant_name: self
@@ -1243,6 +1261,7 @@ impl MerchantAccountUpdateBridge for api::MerchantAccountUpdate {
payment_link_config: None,
pm_collect_link_config,
routing_algorithm: self.routing_algorithm,
network_tokenization_credentials,
})
}
}
@@ -3383,6 +3402,16 @@ impl ProfileCreateBridge for api::ProfileCreate {
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?;
let network_tokenization_credentials = self
.network_tokenization_credentials
.async_map(|headers| {
cards::create_encrypted_data(&key_manager_state, processor.get_key_store(), headers)
})
.await
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt network_tokenization_credentials")?;
let payout_link_config = self
.payout_link_config
.map(|payout_conf| match payout_conf.config.validate() {
@@ -3543,6 +3572,7 @@ impl ProfileCreateBridge for api::ProfileCreate {
.attach_printable("error while generating external vault details")?,
billing_processor_id: self.billing_processor_id,
is_l2_l3_enabled: self.is_l2_l3_enabled.unwrap_or(false),
network_tokenization_credentials,
}))
}
@@ -3903,6 +3933,14 @@ impl ProfileUpdateBridge for api::ProfileUpdate {
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt outgoing webhook custom HTTP headers")?;
let network_tokenization_credentials = self
.network_tokenization_credentials
.async_map(|value| cards::create_encrypted_data(&key_manager_state, &key_store, value))
.await
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to encrypt network_tokenization_credentials")?;
let payout_link_config = self
.payout_link_config
.map(|payout_conf| match payout_conf.config.validate() {
@@ -4046,6 +4084,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate {
.map(ForeignInto::foreign_into),
billing_processor_id: self.billing_processor_id,
is_l2_l3_enabled: self.is_l2_l3_enabled,
network_tokenization_credentials,
},
)))
}

View File

@@ -210,6 +210,7 @@ pub async fn update_merchant_active_algorithm_ref(
default_profile: None,
payment_link_config: None,
pm_collect_link_config: None,
network_tokenization_credentials: None,
};
let db = &*state.store;

View File

@@ -95,6 +95,16 @@ impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
.map(|config| config.parse_value("pm_collect_link_config"))
.transpose()?;
let network_tokenization_credentials = item
.network_tokenization_credentials
.map(|headers| {
headers
.into_inner()
.expose()
.parse_value("network_tokenization_credentials")
})
.transpose()?;
Ok(Self {
merchant_id,
merchant_name: item.merchant_name,
@@ -121,6 +131,7 @@ impl ForeignTryFrom<domain::MerchantAccount> for MerchantAccountResponse {
pm_collect_link_config,
product_type: item.product_type,
merchant_account_type: item.merchant_account_type,
network_tokenization_credentials,
})
}
}
@@ -167,6 +178,17 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
)
})
.transpose()?;
let network_tokenization_credentials = item
.network_tokenization_credentials
.map(|headers| {
headers
.into_inner()
.expose()
.parse_value("network_tokenization_credentials")
})
.transpose()?;
let masked_outgoing_webhook_custom_http_headers =
outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);
@@ -243,6 +265,7 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
.map(ForeignFrom::foreign_from),
billing_processor_id: item.billing_processor_id,
is_l2_l3_enabled: Some(item.is_l2_l3_enabled),
network_tokenization_credentials,
})
}
}
@@ -515,5 +538,6 @@ pub async fn create_profile_from_merchant_account(
.attach_printable("error while generating external_vault_details")?,
billing_processor_id: request.billing_processor_id,
is_l2_l3_enabled: request.is_l2_l3_enabled.unwrap_or(false),
network_tokenization_credentials: None, // since credentials are at merchant level, they should not be in the profile
}))
}

View File

@@ -513,6 +513,7 @@ impl NewUserMerchant {
pm_collect_link_config: None,
product_type: self.get_product_type(),
merchant_account_type: self.merchant_account_type,
network_tokenization_credentials: None,
})
}

View File

@@ -332,6 +332,7 @@ pub fn create_merchant_account_request_for_org(
pm_collect_link_config: None,
product_type: Some(product_type),
merchant_account_type: None,
network_tokenization_credentials: None,
})
}

View File

@@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE merchant_account DROP COLUMN IF EXISTS network_tokenization_credentials;
ALTER TABLE business_profile DROP COLUMN IF EXISTS network_tokenization_credentials;

View File

@@ -0,0 +1,3 @@
-- Your SQL goes here
ALTER TABLE merchant_account ADD COLUMN IF NOT EXISTS network_tokenization_credentials BYTEA;
ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS network_tokenization_credentials BYTEA;