feat(router): add merchant_connector_account create v2 api flow (#5385)

This commit is contained in:
Sai Harsha Vardhan
2024-07-25 00:57:13 +05:30
committed by GitHub
parent 83dbb7a8da
commit 98349a0c3b
20 changed files with 1761 additions and 776 deletions

View File

@ -574,6 +574,137 @@ pub struct MerchantConnectorId {
pub merchant_connector_id: String,
}
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorCreate {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: api_enums::Connector,
/// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports. Eg: if your profile label is `default`, connector label can be `stripe_default`
#[schema(example = "stripe_US_travel")]
pub connector_label: Option<String>,
/// Identifier for the business profile, if not provided default will be chosen from merchant account
pub profile_id: Option<String>,
/// An object containing the required details/credentials for a Connector account.
#[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
pub connector_account_details: Option<pii::SecretSerdeValue>,
/// An object containing the details about the payment methods that need to be enabled under this merchant connector account
#[schema(example = json!([
{
"payment_method": "wallet",
"payment_method_types": [
"upi_collect",
"upi_intent"
],
"payment_method_issuers": [
"labore magna ipsum",
"aute"
],
"payment_schemes": [
"Discover",
"Discover"
],
"accepted_currencies": {
"type": "enable_only",
"list": ["USD", "EUR"]
},
"accepted_countries": {
"type": "disable_only",
"list": ["FR", "DE","IN"]
},
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]))]
pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,
/// Webhook details of this merchant connector
#[schema(example = json!({
"connector_webhook_details": {
"merchant_secret": "1234567890987654321"
}
}))]
pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,
/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
#[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<pii::SecretSerdeValue>,
/// A boolean value to indicate if the connector is disabled. By default, its value is false.
#[schema(default = false, example = false)]
pub disabled: Option<bool>,
/// Contains the frm configs for the merchant connector
#[schema(example = json!(consts::FRM_CONFIGS_EG))]
pub frm_configs: Option<Vec<FrmConfigs>>,
/// Unique ID of the connector
#[schema(example = "mca_5apGeP94tMts6rg3U3kR")]
pub merchant_connector_id: Option<String>,
/// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
// By default the ConnectorStatus is Active
pub status: Option<api_enums::ConnectorStatus>,
/// The identifier for the Merchant Account
#[schema(value_type = String, max_length = 64, min_length = 1, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
pub merchant_id: id_type::MerchantId,
/// In case the merchant needs to store any additional sensitive data
#[schema(value_type = Option<AdditionalMerchantData>)]
pub additional_merchant_data: Option<AdditionalMerchantData>,
}
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
impl MerchantConnectorCreate {
pub fn get_transaction_type(&self) -> api_enums::TransactionType {
match self.connector_type {
#[cfg(feature = "payouts")]
api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
_ => api_enums::TransactionType::Payment,
}
}
pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
match self.frm_configs.as_ref() {
Some(frm_value) => {
let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
.iter()
.map(|config| config.encode_to_value().map(Secret::new))
.collect::<Result<Vec<_>, _>>()
.ok()?;
Some(configs_for_frm_value)
}
None => None,
}
}
pub fn get_connector_label(&self, profile_name: String) -> String {
match self.connector_label.clone() {
Some(connector_label) => connector_label,
None => format!("{}_{}", self.connector_name, profile_name),
}
}
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "merchant_connector_account_v2")
))]
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
@ -666,7 +797,8 @@ pub struct MerchantConnectorCreate {
#[schema(example = "mca_5apGeP94tMts6rg3U3kR")]
pub merchant_connector_id: Option<String>,
pub pm_auth_config: Option<serde_json::Value>,
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
pub status: Option<api_enums::ConnectorStatus>,
@ -676,6 +808,34 @@ pub struct MerchantConnectorCreate {
pub additional_merchant_data: Option<AdditionalMerchantData>,
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "merchant_connector_account_v2")
))]
impl MerchantConnectorCreate {
pub fn get_transaction_type(&self) -> api_enums::TransactionType {
match self.connector_type {
#[cfg(feature = "payouts")]
api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
_ => api_enums::TransactionType::Payment,
}
}
pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
match self.frm_configs.as_ref() {
Some(frm_value) => {
let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
.iter()
.map(|config| config.encode_to_value().map(Secret::new))
.collect::<Result<Vec<_>, _>>()
.ok()?;
Some(configs_for_frm_value)
}
None => None,
}
}
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AdditionalMerchantData {
@ -764,7 +924,124 @@ pub struct MerchantConnectorInfo {
pub merchant_connector_id: String,
}
impl MerchantConnectorInfo {
pub fn new(connector_label: String, merchant_connector_id: String) -> Self {
Self {
connector_label,
merchant_connector_id,
}
}
}
/// Response of creating a new Merchant Connector for the merchant account."
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorResponse {
/// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
#[schema(value_type = ConnectorType, example = "payment_processor")]
pub connector_type: api_enums::ConnectorType,
/// Name of the Connector
#[schema(value_type = Connector, example = "stripe")]
pub connector_name: String,
/// A unique label to identify the connector account created under a business profile
#[schema(example = "stripe_US_travel")]
pub connector_label: Option<String>,
/// Unique ID of the merchant connector account
#[schema(example = "mca_5apGeP94tMts6rg3U3kR")]
pub connector_id: String,
/// Identifier for the business profile, if not provided default will be chosen from merchant account
#[schema(max_length = 64)]
pub profile_id: Option<String>,
/// An object containing the required details/credentials for a Connector account.
#[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
pub connector_account_details: pii::SecretSerdeValue,
/// An object containing the details about the payment methods that need to be enabled under this merchant connector account
#[schema(example = json!([
{
"payment_method": "wallet",
"payment_method_types": [
"upi_collect",
"upi_intent"
],
"payment_method_issuers": [
"labore magna ipsum",
"aute"
],
"payment_schemes": [
"Discover",
"Discover"
],
"accepted_currencies": {
"type": "enable_only",
"list": ["USD", "EUR"]
},
"accepted_countries": {
"type": "disable_only",
"list": ["FR", "DE","IN"]
},
"minimum_amount": 1,
"maximum_amount": 68607706,
"recurring_enabled": true,
"installment_payment_enabled": true
}
]))]
pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,
/// Webhook details of this merchant connector
#[schema(example = json!({
"connector_webhook_details": {
"merchant_secret": "1234567890987654321"
}
}))]
pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,
/// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
#[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
pub metadata: Option<pii::SecretSerdeValue>,
/// A boolean value to indicate if the connector is disabled. By default, its value is false.
#[schema(default = false, example = false)]
pub disabled: Option<bool>,
/// Contains the frm configs for the merchant connector
#[schema(example = json!(consts::FRM_CONFIGS_EG))]
pub frm_configs: Option<Vec<FrmConfigs>>,
/// identifier for the verified domains of a particular connector account
pub applepay_verified_domains: Option<Vec<String>>,
/// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = ConnectorStatus, example = "inactive")]
pub status: api_enums::ConnectorStatus,
#[schema(value_type = Option<AdditionalMerchantData>)]
pub additional_merchant_data: Option<AdditionalMerchantData>,
}
#[cfg(all(feature = "v2", feature = "merchant_connector_account_v2"))]
impl MerchantConnectorResponse {
pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
MerchantConnectorInfo {
connector_label: connector_label.to_string(),
merchant_connector_id: self.connector_id.clone(),
}
}
}
/// Response of creating a new Merchant Connector for the merchant account."
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "merchant_connector_account_v2")
))]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorResponse {
@ -862,7 +1139,8 @@ pub struct MerchantConnectorResponse {
/// identifier for the verified domains of a particular connector account
pub applepay_verified_domains: Option<Vec<String>>,
pub pm_auth_config: Option<serde_json::Value>,
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = ConnectorStatus, example = "inactive")]
pub status: api_enums::ConnectorStatus,
@ -871,6 +1149,19 @@ pub struct MerchantConnectorResponse {
pub additional_merchant_data: Option<AdditionalMerchantData>,
}
#[cfg(all(
any(feature = "v1", feature = "v2"),
not(feature = "merchant_connector_account_v2")
))]
impl MerchantConnectorResponse {
pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
MerchantConnectorInfo {
connector_label: connector_label.to_string(),
merchant_connector_id: self.merchant_connector_id.clone(),
}
}
}
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
@ -943,7 +1234,9 @@ pub struct MerchantConnectorUpdate {
#[schema(example = json!(consts::FRM_CONFIGS_EG))]
pub frm_configs: Option<Vec<FrmConfigs>>,
pub pm_auth_config: Option<serde_json::Value>,
/// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
#[schema(value_type = Option<Object>)]
pub pm_auth_config: Option<pii::SecretSerdeValue>,
#[schema(value_type = ConnectorStatus, example = "inactive")]
pub status: Option<api_enums::ConnectorStatus>,

View File

@ -1,6 +1,8 @@
use std::str::FromStr;
pub use common_enums::*;
#[cfg(feature = "dummy_connector")]
use common_utils::errors;
use utoipa::ToSchema;
#[derive(
@ -272,6 +274,31 @@ impl Connector {
pub fn is_pre_processing_required_before_authorize(&self) -> bool {
matches!(self, Self::Airwallex)
}
#[cfg(feature = "dummy_connector")]
pub fn validate_dummy_connector_enabled(
&self,
is_dummy_connector_enabled: bool,
) -> errors::CustomResult<(), errors::ValidationError> {
if !is_dummy_connector_enabled
&& matches!(
self,
Self::DummyConnector1
| Self::DummyConnector2
| Self::DummyConnector3
| Self::DummyConnector4
| Self::DummyConnector5
| Self::DummyConnector6
| Self::DummyConnector7
)
{
Err(errors::ValidationError::InvalidValue {
message: "Invalid connector name".to_string(),
}
.into())
} else {
Ok(())
}
}
}
#[derive(

View File

@ -8,12 +8,13 @@ use cards::CardNumber;
use common_utils::{
consts::default_payments_list_limit,
crypto,
ext_traits::{ConfigExt, Encode},
ext_traits::{ConfigExt, Encode, ValueExt},
hashing::HashedString,
id_type,
pii::{self, Email, EmailStrategy},
types::{keymanager::ToEncryptable, MinorUnit, StringMajorUnit},
};
use error_stack::ResultExt;
use euclid::dssa::graph::euclid_graph_prelude::FxHashMap;
use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy, WithType};
use router_derive::Setter;
@ -4521,6 +4522,32 @@ pub struct ConnectorMetadata {
pub noon: Option<NoonData>,
}
impl ConnectorMetadata {
pub fn from_value(
value: pii::SecretSerdeValue,
) -> common_utils::errors::CustomResult<Self, common_utils::errors::ParsingError> {
value
.parse_value::<Self>("ConnectorMetadata")
.change_context(common_utils::errors::ParsingError::StructParseFailure(
"Metadata",
))
}
pub fn get_apple_pay_certificates(self) -> Option<(Secret<String>, Secret<String>)> {
self.apple_pay.and_then(|applepay_metadata| {
applepay_metadata
.session_token_data
.map(|session_token_data| {
let SessionTokenInfo {
certificate,
certificate_keys,
..
} = session_token_data;
(certificate, certificate_keys)
})
})
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct AirwallexData {
/// payload required by airwallex