feat(router): add generic merchant static routing config (#362)

This commit is contained in:
ItsMeShashank
2023-01-17 13:04:54 +05:30
committed by GitHub
parent 72c4b06860
commit 22f32cd4d7
22 changed files with 190 additions and 188 deletions

View File

@ -32,12 +32,8 @@ pub struct CreateMerchantAccount {
/// Webhook related details
pub webhook_details: Option<WebhookDetails>,
/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[schema(value_type = Option<RoutingAlgorithm>, max_length = 255, example = "custom")]
pub routing_algorithm: Option<api_enums::RoutingAlgorithm>,
/// The custom routing rules to be used for various payment methods and conditions
pub custom_routing_rules: Option<Vec<CustomRoutingRules>>,
/// The routing algorithm to be used for routing payments to desired connectors
pub routing_algorithm: Option<serde_json::Value>,
/// A boolean value to indicate if the merchant is a sub-merchant under a master or a parent merchant. By default, its value is false.
#[schema(default = false, example = false)]
@ -113,6 +109,12 @@ pub struct MerchantDetails {
pub address: Option<AddressDetails>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(tag = "type", content = "data", rename_all = "snake_case")]
pub enum RoutingAlgorithm {
Single(api_enums::RoutableConnectors),
}
#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WebhookDetails {
@ -145,70 +147,6 @@ pub struct WebhookDetails {
pub payment_failed_enabled: Option<bool>,
}
#[derive(Default, Clone, Debug, Deserialize, ToSchema, Serialize)]
#[serde(deny_unknown_fields)]
pub struct CustomRoutingRules {
/// The List of payment methods to include for this routing rule
#[schema(value_type = Option<Vec<PaymentMethodType>>, example = json!(["card", "upi"]))]
pub payment_methods_incl: Option<Vec<api_enums::PaymentMethodType>>,
/// The List of payment methods to exclude for this routing rule. If there is conflict between include and exclude lists, include list overrides the exclude list.
#[schema(value_type = Option<Vec<PaymentMethodType>>, example = json!(["card", "upi"]))]
pub payment_methods_excl: Option<Vec<api_enums::PaymentMethodType>>,
/// The List of payment method types to include for this routing rule
#[schema(value_type = Option<Vec<PaymentMethodSubType>>, example = json!(["credit_card", "debit_card"]))]
pub payment_method_types_incl: Option<Vec<api_enums::PaymentMethodSubType>>,
/// The List of payment method types to exclude for this routing rule. If there is conflict between include and exclude lists, include list overrides the exclude list.
#[schema(value_type = Option<Vec<PaymentMethodSubType>>, example = json!(["credit_card", "debit_card"]))]
pub payment_method_types_excl: Option<Vec<api_enums::PaymentMethodSubType>>,
/// The List of payment method issuers to include for this routing rule
#[schema(example = json!(["Citibank", "JPMorgan"]))]
pub payment_method_issuers_incl: Option<Vec<String>>,
/// The List of payment method issuers to exclude for this routing rule. If there is conflict between include and exclude lists, include list overrides the exclude list.
#[schema(example = json!(["Citibank", "JPMorgan"]))]
pub payment_method_issuers_excl: Option<Vec<String>>,
/// The List of countries to include for this routing rule
#[schema(example = json!(["US", "UK"]))]
pub countries_incl: Option<Vec<String>>,
/// The List of countries to exclude for this routing rule. If there is conflict between include and exclude lists, include list overrides the exclude list.
#[schema(example = json!(["US", "UK"]))]
pub countries_excl: Option<Vec<String>>,
/// The List of currencies to include for this routing rule
#[schema(value_type = Option<Vec<Currency>>, example = json!(["EUR","USD"]))]
pub currencies_incl: Option<Vec<api_enums::Currency>>,
/// The List of currencies to exclude for this routing rule. If there is conflict between include and exclude lists, include list overrides the exclude list.
#[schema(value_type = Option<Vec<Currency>>, example = json!(["EUR","USD"]))]
pub currencies_excl: Option<Vec<api_enums::Currency>>,
/// List of Metadata Filter keys to apply for the Routing Rule. The filters are presented as 2 arrays of keys and value. This property contains all the keys.
#[schema(example = json!(["platform","Category"]))]
pub metadata_filters_keys: Option<Vec<String>>,
/// List of Metadata Filters to apply for the Routing Rule. The filters are presented as 2 arrays of keys and value. This property contains all the values.
#[schema(example = json!(["android", "Category_Electronics"]))]
pub metadata_filters_values: Option<Vec<String>>,
/// The pecking order of payment connectors (or processors) to be used for routing. The first connector in the array will be attempted for routing. If it fails, the second connector will be used till the list is exhausted.
#[schema(example = json!([ "stripe", "adyen", "brain_tree"]))]
pub connectors_pecking_order: Option<Vec<String>>,
///An Array of Connectors (as Keys) with the associated percentage of traffic to be routed through the given connector (Expressed as an array of values)
#[schema(example = json!([ "stripe", "adyen", "brain_tree"]))]
pub connectors_traffic_weightage_key: Option<Vec<String>>,
/// An Array of Weightage (expressed in percentage) that needs to be associated with the respective connectors (Expressed as an array of keys)
#[schema(example = json!([ 50, 30, 20 ]))]
pub connectors_traffic_weightage_value: Option<Vec<i32>>,
}
#[derive(Debug, Serialize)]
pub struct DeleteResponse {
pub merchant_id: String,

View File

@ -527,6 +527,37 @@ pub enum Connector {
Worldpay,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
serde::Serialize,
serde::Deserialize,
strum::Display,
strum::EnumString,
frunk::LabelledGeneric,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RoutableConnectors {
Aci,
Adyen,
Authorizedotnet,
Braintree,
Checkout,
Cybersource,
Fiserv,
Globalpay,
Klarna,
Payu,
Shift4,
Stripe,
Worldline,
Worldpay,
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum SupportedWallets {

View File

@ -44,11 +44,16 @@ pub async fn create_merchant_account(
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "webhook details",
})?;
let custom_routing_rules =
utils::Encode::<api::CustomRoutingRules>::encode_to_value(&req.custom_routing_rules)
if let Some(ref routing_algorithm) = req.routing_algorithm {
let _: api::RoutingAlgorithm = routing_algorithm
.clone()
.parse_value("RoutingAlgorithm")
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "custom routing rules",
})?;
field_name: "routing_algorithm",
})
.attach_printable("Invalid routing algorithm given")?;
}
let merchant_account = storage::MerchantAccountNew {
merchant_id: req.merchant_id,
@ -57,8 +62,7 @@ pub async fn create_merchant_account(
merchant_details: Some(merchant_details),
return_url: req.return_url,
webhook_details: Some(webhook_details),
routing_algorithm: req.routing_algorithm.map(ForeignInto::foreign_into),
custom_routing_rules: Some(custom_routing_rules),
routing_algorithm: req.routing_algorithm,
sub_merchants_enabled: req.sub_merchants_enabled,
parent_merchant_id: get_parent_merchant(
db,
@ -99,13 +103,6 @@ pub async fn get_merchant_account(
.webhook_details
.parse_value("WebhookDetails")
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let vec_val = merchant_account
.custom_routing_rules
.parse_value("CustomRoutingRulesVector")
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let custom_routing_rules = serde_json::Value::Array(vec_val)
.parse_value("CustomRoutingRules")
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let response = api::MerchantAccountResponse {
merchant_id: req.merchant_id,
merchant_name: merchant_account.merchant_name,
@ -113,10 +110,7 @@ pub async fn get_merchant_account(
merchant_details,
return_url: merchant_account.return_url,
webhook_details,
routing_algorithm: merchant_account
.routing_algorithm
.map(ForeignInto::foreign_into),
custom_routing_rules,
routing_algorithm: merchant_account.routing_algorithm,
sub_merchants_enabled: merchant_account.sub_merchants_enabled,
parent_merchant_id: merchant_account.parent_merchant_id,
enable_payment_response_hash: Some(merchant_account.enable_payment_response_hash),
@ -142,6 +136,7 @@ pub async fn merchant_account_update(
.map_err(|error| {
error.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)
})?;
if &req.merchant_id != merchant_id {
Err(report!(errors::ValidationError::IncorrectValueProvided {
field_name: "parent_merchant_id"
@ -153,6 +148,17 @@ pub async fn merchant_account_update(
field_name: "parent_merchant_id",
}))?;
}
if let Some(ref routing_algorithm) = req.routing_algorithm {
let _: api::RoutingAlgorithm = routing_algorithm
.clone()
.parse_value("RoutingAlgorithm")
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "routing_algorithm",
})
.attach_printable("Invalid routing algorithm given")?;
}
let mut response = req.clone();
let updated_merchant_account = storage::MerchantAccountUpdate::Update {
merchant_id: merchant_id.to_string(),
@ -181,18 +187,7 @@ pub async fn merchant_account_update(
},
routing_algorithm: req
.routing_algorithm
.map(ForeignInto::foreign_into)
.or(merchant_account.routing_algorithm),
custom_routing_rules: if req.custom_routing_rules.is_some() {
Some(
utils::Encode::<api::CustomRoutingRules>::encode_to_value(
&req.custom_routing_rules,
)
.change_context(errors::ApiErrorResponse::InternalServerError)?,
)
} else {
merchant_account.custom_routing_rules.to_owned()
},
.or_else(|| merchant_account.routing_algorithm.clone()),
sub_merchants_enabled: req
.sub_merchants_enabled
.or(merchant_account.sub_merchants_enabled),

View File

@ -102,10 +102,13 @@ where
.get_connector(&merchant_account, state, &req)
.await?;
if let api::ConnectorCallType::Single(ref connector) = connector_details {
payment_data.payment_attempt.connector =
Some(connector.connector_name.to_owned().to_string());
}
let connector_details = route_connector(
state,
&merchant_account,
&mut payment_data,
connector_details,
)
.await?;
let (operation, mut payment_data) = operation
.to_update_tracker()?
@ -149,6 +152,34 @@ where
)
.await?
}
api::ConnectorCallType::Routing => {
let connector = payment_data
.payment_attempt
.connector
.clone()
.get_required_value("connector")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("No connector selected for routing")?;
let connector_data = api::ConnectorData::get_connector_by_name(
&state.conf.connectors,
&connector,
api::GetToken::Connector,
)
.change_context(errors::ApiErrorResponse::InternalServerError)?;
call_connector_service(
state,
&merchant_account,
&validate_result.payment_id,
connector_data,
&operation,
payment_data,
&customer,
call_connector_action,
)
.await?
}
};
vault::Vault::delete_locker_payment_method_by_lookup_key(state, &payment_data.token).await
}
@ -605,3 +636,48 @@ pub async fn add_process_sync_task(
db.insert_process(process_tracker_entry).await?;
Ok(())
}
pub async fn route_connector<F>(
state: &AppState,
merchant_account: &storage::MerchantAccount,
payment_data: &mut PaymentData<F>,
connector_call_type: api::ConnectorCallType,
) -> RouterResult<api::ConnectorCallType>
where
F: Send + Clone,
{
match connector_call_type {
api::ConnectorCallType::Single(connector) => {
payment_data.payment_attempt.connector = Some(connector.connector_name.to_string());
Ok(api::ConnectorCallType::Single(connector))
}
api::ConnectorCallType::Routing => {
let routing_algorithm: api::RoutingAlgorithm = merchant_account
.routing_algorithm
.clone()
.parse_value("RoutingAlgorithm")
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Could not decode merchant routing rules")?;
let connector_name = match routing_algorithm {
api::RoutingAlgorithm::Single(conn) => conn.to_string(),
};
let connector_data = api::ConnectorData::get_connector_by_name(
&state.conf.connectors,
&connector_name,
api::GetToken::Connector,
)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Routing algorithm gave invalid connector")?;
payment_data.payment_attempt.connector = Some(connector_name);
Ok(api::ConnectorCallType::Single(connector_data))
}
call_type @ api::ConnectorCallType::Multiple(_) => Ok(call_type),
}
}

View File

@ -23,7 +23,6 @@ use crate::{
scheduler::{metrics, workflows::payment_sync},
services,
types::{
self,
api::{self, enums as api_enums, CustomerAcceptanceExt, MandateValidationFieldsExt},
storage::{self, enums as storage_enums, ephemeral_key},
transformers::ForeignInto,
@ -594,7 +593,6 @@ pub async fn get_customer_from_details(
}
pub async fn get_connector_default(
merchant_account: &storage::MerchantAccount,
state: &AppState,
request_connector: Option<api_enums::Connector>,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
@ -607,41 +605,7 @@ pub async fn get_connector_default(
)?;
Ok(api::ConnectorCallType::Single(connector_data))
} else {
let vec_val: Vec<serde_json::Value> = merchant_account
.custom_routing_rules
.clone()
.parse_value("CustomRoutingRulesVec")
.change_context(errors::ConnectorError::RoutingRulesParsingError)
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let custom_routing_rules: api::CustomRoutingRules = vec_val
.into_iter()
.next()
.parse_value("CustomRoutingRules")
.change_context(errors::ConnectorError::RoutingRulesParsingError)
.change_context(errors::ApiErrorResponse::InternalServerError)?;
let connector_names = custom_routing_rules
.connectors_pecking_order
.unwrap_or_else(|| vec!["stripe".to_string()]);
//use routing rules if configured by merchant else query MCA as per PM
let connector_list: types::ConnectorsList = types::ConnectorsList {
connectors: connector_names,
};
let connector_name = connector_list
.connectors
.first()
.get_required_value("connectors")
.change_context(errors::ConnectorError::FailedToObtainPreferredConnector)
.change_context(errors::ApiErrorResponse::InternalServerError)?
.as_str();
let connector_data = api::ConnectorData::get_connector_by_name(
connectors,
connector_name,
api::GetToken::Connector,
)?;
Ok(api::ConnectorCallType::Single(connector_data))
Ok(api::ConnectorCallType::Routing)
}
}

View File

@ -189,11 +189,11 @@ where
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsRetrieveRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
#[instrument(skip_all)]
@ -255,11 +255,11 @@ where
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsCaptureRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}
@ -309,10 +309,10 @@ where
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsCancelRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}

View File

@ -250,11 +250,11 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentConfirm {
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
request: &api::PaymentsRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, request.connector).await
helpers::get_connector_default(state, request.connector).await
}
}

View File

@ -254,11 +254,11 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentCreate {
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
request: &api::PaymentsRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, request.connector).await
helpers::get_connector_default(state, request.connector).await
}
}

View File

@ -250,11 +250,11 @@ where
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::VerifyRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}

View File

@ -246,10 +246,10 @@ where
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsStartRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}

View File

@ -98,11 +98,11 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentStatus {
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}

View File

@ -267,11 +267,11 @@ impl<F: Clone + Send> Domain<F, api::PaymentsRequest> for PaymentUpdate {
async fn get_connector<'a>(
&'a self,
merchant_account: &storage::MerchantAccount,
_merchant_account: &storage::MerchantAccount,
state: &AppState,
_request: &api::PaymentsRequest,
) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
helpers::get_connector_default(merchant_account, state, None).await
helpers::get_connector_default(state, None).await
}
}

View File

@ -138,7 +138,6 @@ impl MerchantAccountInterface for MockDb {
merchant_details: merchant_account.merchant_details,
webhook_details: merchant_account.webhook_details,
routing_algorithm: merchant_account.routing_algorithm,
custom_routing_rules: merchant_account.custom_routing_rules,
sub_merchants_enabled: merchant_account.sub_merchants_enabled,
parent_merchant_id: merchant_account.parent_merchant_id,
publishable_key: merchant_account.publishable_key,

View File

@ -53,7 +53,6 @@ Never share your secret api keys. Keep them guarded and secure.
crate::types::api::refunds::RefundResponse,
crate::types::api::refunds::RefundStatus,
crate::types::api::admin::CreateMerchantAccount,
crate::types::api::admin::CustomRoutingRules,
api_models::enums::RoutingAlgorithm,
api_models::enums::PaymentMethodType,
api_models::enums::PaymentMethodSubType,

View File

@ -105,8 +105,9 @@ pub struct ConnectorData {
}
pub enum ConnectorCallType {
Single(ConnectorData),
Routing,
Multiple(Vec<ConnectorData>),
Single(ConnectorData),
}
impl ConnectorCallType {

View File

@ -1,7 +1,6 @@
pub use api_models::admin::{
CreateMerchantAccount, CustomRoutingRules, DeleteMcaResponse, DeleteResponse,
MerchantConnectorId, MerchantDetails, MerchantId, PaymentConnectorCreate, PaymentMethods,
WebhookDetails,
CreateMerchantAccount, DeleteMcaResponse, DeleteResponse, MerchantConnectorId, MerchantDetails,
MerchantId, PaymentConnectorCreate, PaymentMethods, RoutingAlgorithm, WebhookDetails,
};
//use serde::{Serialize, Deserialize};

View File

@ -276,12 +276,9 @@ async fn payments_create_core() {
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let mut merchant_account = services::authenticate_by_api_key(&*state.store, "MySecretApiKey")
let merchant_account = services::authenticate_by_api_key(&*state.store, "MySecretApiKey")
.await
.unwrap();
merchant_account.custom_routing_rules = Some(serde_json::json!([
crate::api::CustomRoutingRules::default()
]));
let req = api::PaymentsRequest {
payment_id: Some(api::PaymentIdType::PaymentIntentId(
@ -436,12 +433,9 @@ async fn payments_create_core_adyen_no_redirect() {
let merchant_id = "arunraj".to_string();
let payment_id = "pay_mbabizu24mvu3mela5njyhpit10".to_string();
let mut merchant_account = services::authenticate_by_api_key(&*state.store, "321")
let merchant_account = services::authenticate_by_api_key(&*state.store, "321")
.await
.unwrap();
merchant_account.custom_routing_rules = Some(serde_json::json!([
crate::api::CustomRoutingRules::default()
]));
let req = api::PaymentsRequest {
payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())),

View File

@ -37,12 +37,9 @@ async fn payments_create_core() {
let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
let mut merchant_account = services::authenticate_by_api_key(&*state.store, "MySecretApiKey")
let merchant_account = services::authenticate_by_api_key(&*state.store, "MySecretApiKey")
.await
.unwrap();
merchant_account.custom_routing_rules = Some(serde_json::json!([
crate::api::CustomRoutingRules::default()
]));
let req = api::PaymentsRequest {
payment_id: Some(api::PaymentIdType::PaymentIntentId(

View File

@ -16,13 +16,12 @@ pub struct MerchantAccount {
pub merchant_name: Option<String>,
pub merchant_details: Option<serde_json::Value>,
pub webhook_details: Option<serde_json::Value>,
pub routing_algorithm: Option<storage_enums::RoutingAlgorithm>,
pub custom_routing_rules: Option<serde_json::Value>,
pub sub_merchants_enabled: Option<bool>,
pub parent_merchant_id: Option<String>,
pub publishable_key: Option<String>,
pub storage_scheme: storage_enums::MerchantStorageScheme,
pub locker_id: Option<String>,
pub routing_algorithm: Option<serde_json::Value>,
}
#[derive(Clone, Debug, Default, Insertable, router_derive::DebugAsDisplay)]
@ -34,8 +33,6 @@ pub struct MerchantAccountNew {
pub merchant_details: Option<serde_json::Value>,
pub return_url: Option<String>,
pub webhook_details: Option<serde_json::Value>,
pub routing_algorithm: Option<storage_enums::RoutingAlgorithm>,
pub custom_routing_rules: Option<serde_json::Value>,
pub sub_merchants_enabled: Option<bool>,
pub parent_merchant_id: Option<String>,
pub enable_payment_response_hash: Option<bool>,
@ -43,6 +40,7 @@ pub struct MerchantAccountNew {
pub redirect_to_merchant_with_http_post: Option<bool>,
pub publishable_key: Option<String>,
pub locker_id: Option<String>,
pub routing_algorithm: Option<serde_json::Value>,
}
#[derive(Debug)]
@ -54,8 +52,6 @@ pub enum MerchantAccountUpdate {
merchant_details: Option<serde_json::Value>,
return_url: Option<String>,
webhook_details: Option<serde_json::Value>,
routing_algorithm: Option<storage_enums::RoutingAlgorithm>,
custom_routing_rules: Option<serde_json::Value>,
sub_merchants_enabled: Option<bool>,
parent_merchant_id: Option<String>,
enable_payment_response_hash: Option<bool>,
@ -63,6 +59,7 @@ pub enum MerchantAccountUpdate {
redirect_to_merchant_with_http_post: Option<bool>,
publishable_key: Option<String>,
locker_id: Option<String>,
routing_algorithm: Option<serde_json::Value>,
},
}
@ -75,8 +72,6 @@ pub struct MerchantAccountUpdateInternal {
merchant_details: Option<serde_json::Value>,
return_url: Option<String>,
webhook_details: Option<serde_json::Value>,
routing_algorithm: Option<storage_enums::RoutingAlgorithm>,
custom_routing_rules: Option<serde_json::Value>,
sub_merchants_enabled: Option<bool>,
parent_merchant_id: Option<String>,
enable_payment_response_hash: Option<bool>,
@ -84,6 +79,7 @@ pub struct MerchantAccountUpdateInternal {
redirect_to_merchant_with_http_post: Option<bool>,
publishable_key: Option<String>,
locker_id: Option<String>,
routing_algorithm: Option<serde_json::Value>,
}
impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
@ -97,7 +93,6 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
return_url,
webhook_details,
routing_algorithm,
custom_routing_rules,
sub_merchants_enabled,
parent_merchant_id,
enable_payment_response_hash,
@ -113,7 +108,6 @@ impl From<MerchantAccountUpdate> for MerchantAccountUpdateInternal {
return_url,
webhook_details,
routing_algorithm,
custom_routing_rules,
sub_merchants_enabled,
parent_merchant_id,
enable_payment_response_hash,

View File

@ -153,13 +153,12 @@ diesel::table! {
merchant_name -> Nullable<Varchar>,
merchant_details -> Nullable<Json>,
webhook_details -> Nullable<Json>,
routing_algorithm -> Nullable<RoutingAlgorithm>,
custom_routing_rules -> Nullable<Json>,
sub_merchants_enabled -> Nullable<Bool>,
parent_merchant_id -> Nullable<Varchar>,
publishable_key -> Nullable<Varchar>,
storage_scheme -> MerchantStorageScheme,
locker_id -> Nullable<Varchar>,
routing_algorithm -> Nullable<Json>,
}
}

View File

@ -0,0 +1,11 @@
-- This file should undo anything in `up.sql`
CREATE TYPE "RoutingAlgorithm" AS ENUM (
'round_robin',
'max_conversion',
'min_cost',
'custom'
);
ALTER TABLE merchant_account DROP COLUMN routing_algorithm;
ALTER TABLE merchant_account ADD COLUMN custom_routing_rules JSON;
ALTER TABLE merchant_account ADD COLUMN routing_algorithm "RoutingAlgorithm";

View File

@ -0,0 +1,5 @@
-- Your SQL goes here
ALTER TABLE merchant_account DROP COLUMN routing_algorithm;
ALTER TABLE merchant_account DROP COLUMN custom_routing_rules;
ALTER TABLE merchant_account ADD COLUMN routing_algorithm JSON;
DROP TYPE "RoutingAlgorithm";