mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 19:42:27 +08:00
feat(business_profile): add business profile table and CRUD endpoints (#1928)
This commit is contained in:
@ -59,7 +59,8 @@ pub struct MerchantAccountCreate {
|
||||
#[schema(default = false, example = true)]
|
||||
pub enable_payment_response_hash: Option<bool>,
|
||||
|
||||
/// Refers to the hash key used for payment response
|
||||
/// Refers to the hash key used for calculating the signature for webhooks and redirect response
|
||||
/// If the value is not provided, a default value is used
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
|
||||
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
|
||||
@ -927,3 +928,172 @@ pub enum PayoutRoutingAlgorithm {
|
||||
pub enum PayoutStraightThroughAlgorithm {
|
||||
Single(api_enums::PayoutConnectors),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, ToSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct BusinessProfileCreate {
|
||||
/// A short name to identify the business profile
|
||||
#[schema(max_length = 64)]
|
||||
pub profile_name: Option<String>,
|
||||
|
||||
/// The URL to redirect after the completion of the operation, This will be applied to all the
|
||||
/// connector accounts under this profile
|
||||
#[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
|
||||
pub return_url: Option<url::Url>,
|
||||
|
||||
/// A boolean value to indicate if payment response hash needs to be enabled
|
||||
#[schema(default = true, example = true)]
|
||||
pub enable_payment_response_hash: Option<bool>,
|
||||
|
||||
/// Refers to the hash key used for calculating the signature for webhooks and redirect response
|
||||
/// If the value is not provided, a default value is used
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
|
||||
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
|
||||
#[schema(default = false, example = true)]
|
||||
pub redirect_to_merchant_with_http_post: Option<bool>,
|
||||
|
||||
/// Webhook related details
|
||||
pub webhook_details: Option<WebhookDetails>,
|
||||
|
||||
/// 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>, example = r#"{ "city": "NY", "unit": "245" }"#)]
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
|
||||
/// The routing algorithm to be used for routing payments to desired connectors
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "stripe"}))]
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
///Will be used to expire client secret after certain amount of time to be supplied in seconds
|
||||
///(900) for 15 mins
|
||||
#[schema(example = 900)]
|
||||
pub intent_fulfillment_time: Option<u32>,
|
||||
|
||||
/// The frm routing algorithm to be used for routing payments to desired FRM's
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "signifyd"}))]
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
/// The routing algorithm to be used for routing payouts to desired connectors
|
||||
#[cfg(feature = "payouts")]
|
||||
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "payout_routing_algorithm::deserialize_option"
|
||||
)]
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, ToSchema, Serialize)]
|
||||
pub struct BusinessProfileResponse {
|
||||
/// The identifier for Merchant Account
|
||||
#[schema(max_length = 64, example = "y3oqhf46pyzuxjbcn2giaqnb44")]
|
||||
pub merchant_id: String,
|
||||
|
||||
/// The unique identifier for Business Profile
|
||||
#[schema(max_length = 64, example = "pro_abcdefghijklmnopqrstuvwxyz")]
|
||||
pub profile_id: String,
|
||||
|
||||
/// A short name to identify the business profile
|
||||
#[schema(max_length = 64)]
|
||||
pub profile_name: String,
|
||||
|
||||
/// The URL to redirect after the completion of the operation, This will be applied to all the
|
||||
/// connector accounts under this profile
|
||||
#[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
|
||||
pub return_url: Option<String>,
|
||||
|
||||
/// A boolean value to indicate if payment response hash needs to be enabled
|
||||
#[schema(default = true, example = true)]
|
||||
pub enable_payment_response_hash: bool,
|
||||
|
||||
/// Refers to the hash key used for calculating the signature for webhooks and redirect response
|
||||
/// If the value is not provided, a default value is used
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
|
||||
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
|
||||
#[schema(default = false, example = true)]
|
||||
pub redirect_to_merchant_with_http_post: bool,
|
||||
|
||||
/// Webhook related details
|
||||
pub webhook_details: Option<pii::SecretSerdeValue>,
|
||||
|
||||
/// 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>, example = r#"{ "city": "NY", "unit": "245" }"#)]
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
|
||||
/// The routing algorithm to be used for routing payments to desired connectors
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "stripe"}))]
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
///Will be used to expire client secret after certain amount of time to be supplied in seconds
|
||||
///(900) for 15 mins
|
||||
#[schema(example = 900)]
|
||||
pub intent_fulfillment_time: Option<i64>,
|
||||
|
||||
/// The frm routing algorithm to be used for routing payments to desired FRM's
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "signifyd"}))]
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
/// The routing algorithm to be used for routing payouts to desired connectors
|
||||
#[cfg(feature = "payouts")]
|
||||
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "payout_routing_algorithm::deserialize_option"
|
||||
)]
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, ToSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct BusinessProfileUpdate {
|
||||
/// A short name to identify the business profile
|
||||
#[schema(max_length = 64)]
|
||||
pub profile_name: Option<String>,
|
||||
|
||||
/// The URL to redirect after the completion of the operation, This will be applied to all the
|
||||
/// connector accounts under this profile
|
||||
#[schema(value_type = Option<String>, max_length = 255, example = "https://www.example.com/success")]
|
||||
pub return_url: Option<url::Url>,
|
||||
|
||||
/// A boolean value to indicate if payment response hash needs to be enabled
|
||||
#[schema(default = true, example = true)]
|
||||
pub enable_payment_response_hash: Option<bool>,
|
||||
|
||||
/// Refers to the hash key used for calculating the signature for webhooks and redirect response
|
||||
/// If the value is not provided, a default value is used
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
|
||||
/// A boolean value to indicate if redirect to merchant with http post needs to be enabled
|
||||
#[schema(default = false, example = true)]
|
||||
pub redirect_to_merchant_with_http_post: Option<bool>,
|
||||
|
||||
/// Webhook related details
|
||||
pub webhook_details: Option<WebhookDetails>,
|
||||
|
||||
/// 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>, example = r#"{ "city": "NY", "unit": "245" }"#)]
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
|
||||
/// The routing algorithm to be used for routing payments to desired connectors
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "stripe"}))]
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
///Will be used to expire client secret after certain amount of time to be supplied in seconds
|
||||
///(900) for 15 mins
|
||||
#[schema(example = 900)]
|
||||
pub intent_fulfillment_time: Option<u32>,
|
||||
|
||||
/// The frm routing algorithm to be used for routing payments to desired FRM's
|
||||
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "signifyd"}))]
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
|
||||
/// The routing algorithm to be used for routing payouts to desired connectors
|
||||
#[cfg(feature = "payouts")]
|
||||
#[schema(value_type = Option<RoutingAlgorithm>,example = json!({"type": "single", "data": "wise"}))]
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "payout_routing_algorithm::deserialize_option"
|
||||
)]
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
72
crates/diesel_models/src/business_profile.rs
Normal file
72
crates/diesel_models/src/business_profile.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use common_utils::pii;
|
||||
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
|
||||
|
||||
use crate::schema::business_profile;
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
Identifiable,
|
||||
Queryable,
|
||||
router_derive::DebugAsDisplay,
|
||||
)]
|
||||
#[diesel(table_name = business_profile, primary_key(profile_id))]
|
||||
pub struct BusinessProfile {
|
||||
pub profile_id: String,
|
||||
pub merchant_id: String,
|
||||
pub profile_name: String,
|
||||
pub created_at: time::PrimitiveDateTime,
|
||||
pub modified_at: time::PrimitiveDateTime,
|
||||
pub return_url: Option<String>,
|
||||
pub enable_payment_response_hash: bool,
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
pub redirect_to_merchant_with_http_post: bool,
|
||||
pub webhook_details: Option<serde_json::Value>,
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
pub intent_fulfillment_time: Option<i64>,
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
pub is_recon_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = business_profile, primary_key(profile_id))]
|
||||
pub struct BusinessProfileNew {
|
||||
pub profile_id: String,
|
||||
pub merchant_id: String,
|
||||
pub profile_name: String,
|
||||
pub created_at: time::PrimitiveDateTime,
|
||||
pub modified_at: time::PrimitiveDateTime,
|
||||
pub return_url: Option<String>,
|
||||
pub enable_payment_response_hash: bool,
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
pub redirect_to_merchant_with_http_post: bool,
|
||||
pub webhook_details: Option<serde_json::Value>,
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
pub intent_fulfillment_time: Option<i64>,
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
pub is_recon_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
|
||||
#[diesel(table_name = business_profile)]
|
||||
pub struct BusinessProfileUpdateInternal {
|
||||
pub profile_name: Option<String>,
|
||||
pub modified_at: Option<time::PrimitiveDateTime>,
|
||||
pub return_url: Option<String>,
|
||||
pub enable_payment_response_hash: Option<bool>,
|
||||
pub payment_response_hash_key: Option<String>,
|
||||
pub redirect_to_merchant_with_http_post: Option<bool>,
|
||||
pub webhook_details: Option<serde_json::Value>,
|
||||
pub metadata: Option<pii::SecretSerdeValue>,
|
||||
pub routing_algorithm: Option<serde_json::Value>,
|
||||
pub intent_fulfillment_time: Option<i64>,
|
||||
pub frm_routing_algorithm: Option<serde_json::Value>,
|
||||
pub payout_routing_algorithm: Option<serde_json::Value>,
|
||||
pub is_recon_enabled: Option<bool>,
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod address;
|
||||
pub mod api_keys;
|
||||
pub mod business_profile;
|
||||
pub mod capture;
|
||||
pub mod cards_info;
|
||||
pub mod configs;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod address;
|
||||
pub mod api_keys;
|
||||
pub mod business_profile;
|
||||
mod capture;
|
||||
pub mod cards_info;
|
||||
pub mod configs;
|
||||
|
||||
82
crates/diesel_models/src/query/business_profile.rs
Normal file
82
crates/diesel_models/src/query/business_profile.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods, Table};
|
||||
use router_env::{instrument, tracing};
|
||||
|
||||
use super::generics;
|
||||
use crate::{
|
||||
business_profile::{BusinessProfile, BusinessProfileNew, BusinessProfileUpdateInternal},
|
||||
errors,
|
||||
schema::business_profile::dsl,
|
||||
PgPooledConn, StorageResult,
|
||||
};
|
||||
|
||||
impl BusinessProfileNew {
|
||||
#[instrument(skip(conn))]
|
||||
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<BusinessProfile> {
|
||||
generics::generic_insert(conn, self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl BusinessProfile {
|
||||
#[instrument(skip(conn))]
|
||||
pub async fn update_by_profile_id(
|
||||
self,
|
||||
conn: &PgPooledConn,
|
||||
business_profile: BusinessProfileUpdateInternal,
|
||||
) -> StorageResult<Self> {
|
||||
match generics::generic_update_by_id::<<Self as HasTable>::Table, _, _, _>(
|
||||
conn,
|
||||
self.profile_id.clone(),
|
||||
business_profile,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Err(error) => match error.current_context() {
|
||||
errors::DatabaseError::NoFieldsToUpdate => Ok(self),
|
||||
_ => Err(error),
|
||||
},
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(conn))]
|
||||
pub async fn find_by_profile_id(conn: &PgPooledConn, profile_id: &str) -> StorageResult<Self> {
|
||||
generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
|
||||
conn,
|
||||
dsl::profile_id.eq(profile_id.to_owned()),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn list_business_profile_by_merchant_id(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &str,
|
||||
) -> StorageResult<Vec<Self>> {
|
||||
generics::generic_filter::<
|
||||
<Self as HasTable>::Table,
|
||||
_,
|
||||
<<Self as HasTable>::Table as Table>::PrimaryKey,
|
||||
_,
|
||||
>(
|
||||
conn,
|
||||
dsl::merchant_id.eq(merchant_id.to_string()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_by_profile_id_merchant_id(
|
||||
conn: &PgPooledConn,
|
||||
profile_id: &str,
|
||||
merchant_id: &str,
|
||||
) -> StorageResult<bool> {
|
||||
generics::generic_delete::<<Self as HasTable>::Table, _>(
|
||||
conn,
|
||||
dsl::profile_id
|
||||
.eq(profile_id.to_owned())
|
||||
.and(dsl::merchant_id.eq(merchant_id.to_string())),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@ -53,6 +53,34 @@ diesel::table! {
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use crate::enums::diesel_exports::*;
|
||||
|
||||
business_profile (profile_id) {
|
||||
#[max_length = 64]
|
||||
profile_id -> Varchar,
|
||||
#[max_length = 64]
|
||||
merchant_id -> Varchar,
|
||||
#[max_length = 64]
|
||||
profile_name -> Varchar,
|
||||
created_at -> Timestamp,
|
||||
modified_at -> Timestamp,
|
||||
return_url -> Nullable<Text>,
|
||||
enable_payment_response_hash -> Bool,
|
||||
#[max_length = 255]
|
||||
payment_response_hash_key -> Nullable<Varchar>,
|
||||
redirect_to_merchant_with_http_post -> Bool,
|
||||
webhook_details -> Nullable<Json>,
|
||||
metadata -> Nullable<Json>,
|
||||
routing_algorithm -> Nullable<Json>,
|
||||
intent_fulfillment_time -> Nullable<Int8>,
|
||||
frm_routing_algorithm -> Nullable<Jsonb>,
|
||||
payout_routing_algorithm -> Nullable<Jsonb>,
|
||||
is_recon_enabled -> Bool,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use crate::enums::diesel_exports::*;
|
||||
@ -756,6 +784,7 @@ diesel::table! {
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
address,
|
||||
api_keys,
|
||||
business_profile,
|
||||
captures,
|
||||
cards_info,
|
||||
configs,
|
||||
|
||||
@ -535,6 +535,10 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
||||
object: "dispute".to_owned(),
|
||||
id: dispute_id,
|
||||
},
|
||||
errors::ApiErrorResponse::BusinessProfileNotFound { id } => Self::ResourceMissing {
|
||||
object: "business_profile".to_owned(),
|
||||
id,
|
||||
},
|
||||
errors::ApiErrorResponse::DisputeStatusValidationFailed { reason } => {
|
||||
Self::InternalServerError
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ use crate::{
|
||||
types::{self as domain_types, AsyncLift},
|
||||
},
|
||||
storage,
|
||||
transformers::ForeignTryFrom,
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
@ -830,6 +831,218 @@ pub fn get_frm_config_as_secret(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_business_profile(
|
||||
db: &dyn StorageInterface,
|
||||
request: api::BusinessProfileCreate,
|
||||
merchant_id: &str,
|
||||
) -> RouterResponse<api_models::admin::BusinessProfileResponse> {
|
||||
let key_store = db
|
||||
.get_merchant_key_store_by_merchant_id(merchant_id, &db.get_master_key().to_vec().into())
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
// Get the merchant account, if few fields are not passed, then they will be inherited from
|
||||
// merchant account
|
||||
let merchant_account = db
|
||||
.find_merchant_account_by_merchant_id(merchant_id, &key_store)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
// Generate a unique profile id
|
||||
let profile_id = common_utils::generate_id_with_default_len("pro");
|
||||
|
||||
let payment_response_hash_key = request
|
||||
.payment_response_hash_key
|
||||
.or(merchant_account.payment_response_hash_key)
|
||||
.unwrap_or(generate_cryptographically_secure_random_string(64));
|
||||
|
||||
let webhook_details = request
|
||||
.webhook_details
|
||||
.as_ref()
|
||||
.map(|webhook_details| {
|
||||
utils::Encode::<api::WebhookDetails>::encode_to_value(webhook_details).change_context(
|
||||
errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "webhook details",
|
||||
},
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
if let Some(ref routing_algorithm) = request.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 business_profile_new = storage::business_profile::BusinessProfileNew {
|
||||
profile_id,
|
||||
merchant_id: merchant_id.to_string(),
|
||||
profile_name: request.profile_name.unwrap_or("default".to_string()),
|
||||
created_at: date_time::now(),
|
||||
modified_at: date_time::now(),
|
||||
return_url: request
|
||||
.return_url
|
||||
.map(|return_url| return_url.to_string())
|
||||
.or(merchant_account.return_url),
|
||||
enable_payment_response_hash: request
|
||||
.enable_payment_response_hash
|
||||
.unwrap_or(merchant_account.enable_payment_response_hash),
|
||||
payment_response_hash_key: Some(payment_response_hash_key),
|
||||
redirect_to_merchant_with_http_post: request
|
||||
.redirect_to_merchant_with_http_post
|
||||
.unwrap_or(merchant_account.redirect_to_merchant_with_http_post),
|
||||
webhook_details: webhook_details.or(merchant_account.webhook_details),
|
||||
metadata: request.metadata,
|
||||
routing_algorithm: request
|
||||
.routing_algorithm
|
||||
.or(merchant_account.routing_algorithm),
|
||||
intent_fulfillment_time: request
|
||||
.intent_fulfillment_time
|
||||
.map(i64::from)
|
||||
.or(merchant_account.intent_fulfillment_time),
|
||||
frm_routing_algorithm: request
|
||||
.frm_routing_algorithm
|
||||
.or(merchant_account.frm_routing_algorithm),
|
||||
payout_routing_algorithm: request
|
||||
.payout_routing_algorithm
|
||||
.or(merchant_account.payout_routing_algorithm),
|
||||
is_recon_enabled: merchant_account.is_recon_enabled,
|
||||
};
|
||||
|
||||
let business_profile = db
|
||||
.insert_business_profile(business_profile_new)
|
||||
.await
|
||||
.to_duplicate_response(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to insert Business profile because of duplication error")?;
|
||||
Ok(service_api::ApplicationResponse::Json(
|
||||
api_models::admin::BusinessProfileResponse::foreign_try_from(business_profile)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn list_business_profile(
|
||||
db: &dyn StorageInterface,
|
||||
merchant_id: String,
|
||||
) -> RouterResponse<Vec<api_models::admin::BusinessProfileResponse>> {
|
||||
let business_profiles = db
|
||||
.list_business_profile_by_merchant_id(&merchant_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::InternalServerError)?
|
||||
.into_iter()
|
||||
.map(|business_profile| {
|
||||
api_models::admin::BusinessProfileResponse::foreign_try_from(business_profile)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to parse business profile details")?;
|
||||
|
||||
Ok(service_api::ApplicationResponse::Json(business_profiles))
|
||||
}
|
||||
|
||||
pub async fn retrieve_business_profile(
|
||||
db: &dyn StorageInterface,
|
||||
profile_id: String,
|
||||
) -> RouterResponse<api_models::admin::BusinessProfileResponse> {
|
||||
let business_profile = db
|
||||
.find_business_profile_by_profile_id(&profile_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id,
|
||||
})?;
|
||||
|
||||
Ok(service_api::ApplicationResponse::Json(
|
||||
api_models::admin::BusinessProfileResponse::foreign_try_from(business_profile)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn delete_business_profile(
|
||||
db: &dyn StorageInterface,
|
||||
profile_id: String,
|
||||
merchant_id: &str,
|
||||
) -> RouterResponse<bool> {
|
||||
let delete_result = db
|
||||
.delete_business_profile_by_profile_id_merchant_id(&profile_id, merchant_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id,
|
||||
})?;
|
||||
|
||||
Ok(service_api::ApplicationResponse::Json(delete_result))
|
||||
}
|
||||
|
||||
pub async fn update_business_profile(
|
||||
db: &dyn StorageInterface,
|
||||
profile_id: &str,
|
||||
merchant_id: &str,
|
||||
request: api::BusinessProfileUpdate,
|
||||
) -> RouterResponse<api::BusinessProfileResponse> {
|
||||
let business_profile = db
|
||||
.find_business_profile_by_profile_id(profile_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id.to_owned(),
|
||||
})?;
|
||||
|
||||
if business_profile.merchant_id != merchant_id {
|
||||
Err(errors::ApiErrorResponse::AccessForbidden)?
|
||||
}
|
||||
|
||||
let webhook_details = request
|
||||
.webhook_details
|
||||
.as_ref()
|
||||
.map(|webhook_details| {
|
||||
utils::Encode::<api::WebhookDetails>::encode_to_value(webhook_details).change_context(
|
||||
errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "webhook details",
|
||||
},
|
||||
)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
if let Some(ref routing_algorithm) = request.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 business_profile_update = storage::business_profile::BusinessProfileUpdateInternal {
|
||||
profile_name: request.profile_name,
|
||||
modified_at: Some(date_time::now()),
|
||||
return_url: request.return_url.map(|return_url| return_url.to_string()),
|
||||
enable_payment_response_hash: request.enable_payment_response_hash,
|
||||
payment_response_hash_key: request.payment_response_hash_key,
|
||||
redirect_to_merchant_with_http_post: request.redirect_to_merchant_with_http_post,
|
||||
webhook_details,
|
||||
metadata: request.metadata,
|
||||
routing_algorithm: request.routing_algorithm,
|
||||
intent_fulfillment_time: request.intent_fulfillment_time.map(i64::from),
|
||||
frm_routing_algorithm: request.frm_routing_algorithm,
|
||||
payout_routing_algorithm: request.payout_routing_algorithm,
|
||||
is_recon_enabled: None,
|
||||
};
|
||||
|
||||
let updated_business_profile = 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(
|
||||
api_models::admin::BusinessProfileResponse::foreign_try_from(updated_business_profile)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn validate_auth_type(
|
||||
connector_name: api_models::enums::Connector,
|
||||
val: &types::ConnectorAuthType,
|
||||
|
||||
@ -153,6 +153,8 @@ pub enum ApiErrorResponse {
|
||||
MerchantAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Merchant connector account with id '{id}' does not exist in our records")]
|
||||
MerchantConnectorAccountNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Business profile with the given id '{id}' does not exist in our records")]
|
||||
BusinessProfileNotFound { id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Resource ID does not exist in our records")]
|
||||
ResourceIdNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Mandate does not exist in our records")]
|
||||
|
||||
@ -207,6 +207,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
|
||||
}
|
||||
Self::DisputeNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Dispute does not exist in our records", None))
|
||||
},
|
||||
Self::BusinessProfileNotFound { id } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, format!("Business profile with the given id {id} does not exist"), None))
|
||||
}
|
||||
Self::FileNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File does not exist in our records", None))
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod address;
|
||||
pub mod api_keys;
|
||||
pub mod business_profile;
|
||||
pub mod cache;
|
||||
pub mod capture;
|
||||
pub mod cards_info;
|
||||
@ -75,6 +76,7 @@ pub trait StorageInterface:
|
||||
+ merchant_key_store::MerchantKeyStoreInterface
|
||||
+ MasterKeyInterface
|
||||
+ RedisConnInterface
|
||||
+ business_profile::BusinessProfileInterface
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
|
||||
151
crates/router/src/db/business_profile.rs
Normal file
151
crates/router/src/db/business_profile.rs
Normal file
@ -0,0 +1,151 @@
|
||||
use error_stack::IntoReport;
|
||||
|
||||
use super::Store;
|
||||
use crate::{
|
||||
connection,
|
||||
core::errors::{self, CustomResult},
|
||||
db::MockDb,
|
||||
types::storage::{self, business_profile},
|
||||
};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait BusinessProfileInterface {
|
||||
async fn insert_business_profile(
|
||||
&self,
|
||||
business_profile: business_profile::BusinessProfileNew,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError>;
|
||||
|
||||
async fn find_business_profile_by_profile_id(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError>;
|
||||
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError>;
|
||||
|
||||
async fn delete_business_profile_by_profile_id_merchant_id(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<bool, errors::StorageError>;
|
||||
|
||||
async fn list_business_profile_by_merchant_id(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<business_profile::BusinessProfile>, errors::StorageError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BusinessProfileInterface for Store {
|
||||
async fn insert_business_profile(
|
||||
&self,
|
||||
business_profile: business_profile::BusinessProfileNew,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
business_profile
|
||||
.insert(&conn)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn find_business_profile_by_profile_id(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
storage::business_profile::BusinessProfile::find_by_profile_id(&conn, profile_id)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
current_state: business_profile::BusinessProfile,
|
||||
business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
storage::business_profile::BusinessProfile::update_by_profile_id(
|
||||
current_state,
|
||||
&conn,
|
||||
business_profile_update,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn delete_business_profile_by_profile_id_merchant_id(
|
||||
&self,
|
||||
profile_id: &str,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<bool, errors::StorageError> {
|
||||
let conn = connection::pg_connection_write(self).await?;
|
||||
storage::business_profile::BusinessProfile::delete_by_profile_id_merchant_id(
|
||||
&conn,
|
||||
profile_id,
|
||||
merchant_id,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn list_business_profile_by_merchant_id(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
) -> CustomResult<Vec<business_profile::BusinessProfile>, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
storage::business_profile::BusinessProfile::list_business_profile_by_merchant_id(
|
||||
&conn,
|
||||
merchant_id,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl BusinessProfileInterface for MockDb {
|
||||
async fn insert_business_profile(
|
||||
&self,
|
||||
_business_profile: business_profile::BusinessProfileNew,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
|
||||
async fn find_business_profile_by_profile_id(
|
||||
&self,
|
||||
_profile_id: &str,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
|
||||
async fn update_business_profile_by_profile_id(
|
||||
&self,
|
||||
_current_state: business_profile::BusinessProfile,
|
||||
_business_profile_update: business_profile::BusinessProfileUpdateInternal,
|
||||
) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
|
||||
async fn delete_business_profile_by_profile_id_merchant_id(
|
||||
&self,
|
||||
_profile_id: &str,
|
||||
_merchant_id: &str,
|
||||
) -> CustomResult<bool, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
|
||||
async fn list_business_profile_by_merchant_id(
|
||||
&self,
|
||||
_merchant_id: &str,
|
||||
) -> CustomResult<Vec<business_profile::BusinessProfile>, errors::StorageError> {
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
}
|
||||
@ -106,13 +106,19 @@ pub fn mk_app(
|
||||
|
||||
#[cfg(any(feature = "olap", feature = "oltp"))]
|
||||
{
|
||||
#[cfg(feature = "olap")]
|
||||
{
|
||||
// This is a more specific route as compared to `MerchantConnectorAccount`
|
||||
// so it is registered before `MerchantConnectorAccount`.
|
||||
server_app = server_app.service(routes::BusinessProfile::server(state.clone()))
|
||||
}
|
||||
server_app = server_app
|
||||
.service(routes::Payments::server(state.clone()))
|
||||
.service(routes::Customers::server(state.clone()))
|
||||
.service(routes::Configs::server(state.clone()))
|
||||
.service(routes::Refunds::server(state.clone()))
|
||||
.service(routes::MerchantConnectorAccount::server(state.clone()))
|
||||
.service(routes::Mandates::server(state.clone()));
|
||||
.service(routes::Mandates::server(state.clone()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "oltp")]
|
||||
@ -129,7 +135,7 @@ pub fn mk_app(
|
||||
.service(routes::MerchantAccount::server(state.clone()))
|
||||
.service(routes::ApiKeys::server(state.clone()))
|
||||
.service(routes::Files::server(state.clone()))
|
||||
.service(routes::Disputes::server(state.clone()));
|
||||
.service(routes::Disputes::server(state.clone()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "payouts")]
|
||||
|
||||
@ -25,9 +25,9 @@ pub use self::app::DummyConnector;
|
||||
#[cfg(feature = "payouts")]
|
||||
pub use self::app::Payouts;
|
||||
pub use self::app::{
|
||||
ApiKeys, AppState, Cache, Cards, Configs, Customers, Disputes, EphemeralKey, Files, Health,
|
||||
Mandates, MerchantAccount, MerchantConnectorAccount, PaymentMethods, Payments, Refunds,
|
||||
Webhooks,
|
||||
ApiKeys, AppState, BusinessProfile, Cache, Cards, Configs, Customers, Disputes, EphemeralKey,
|
||||
Files, Health, Mandates, MerchantAccount, MerchantConnectorAccount, PaymentMethods, Payments,
|
||||
Refunds, Webhooks,
|
||||
};
|
||||
#[cfg(feature = "stripe")]
|
||||
pub use super::compatibility::stripe::StripeApis;
|
||||
|
||||
@ -386,6 +386,109 @@ pub async fn merchant_account_toggle_kv(
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileCreate))]
|
||||
pub async fn business_profile_create(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
json_payload: web::Json<admin::BusinessProfileCreate>,
|
||||
path: web::Path<String>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::BusinessProfileCreate;
|
||||
let payload = json_payload.into_inner();
|
||||
let merchant_id = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
payload,
|
||||
|state, _, req| create_business_profile(&*state.store, req, &merchant_id),
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileRetrieve))]
|
||||
pub async fn business_profile_retrieve(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(String, String)>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::BusinessProfileRetrieve;
|
||||
let (_, profile_id) = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
profile_id,
|
||||
|state, _, profile_id| retrieve_business_profile(&*state.store, profile_id),
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileUpdate))]
|
||||
pub async fn business_profile_update(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(String, String)>,
|
||||
json_payload: web::Json<api_models::admin::BusinessProfileUpdate>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::BusinessProfileUpdate;
|
||||
let (merchant_id, profile_id) = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
json_payload.into_inner(),
|
||||
|state, _, req| update_business_profile(&*state.store, &profile_id, &merchant_id, req),
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileDelete))]
|
||||
pub async fn business_profile_delete(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<(String, String)>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::BusinessProfileDelete;
|
||||
let (merchant_id, profile_id) = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
profile_id,
|
||||
|state, _, profile_id| delete_business_profile(&*state.store, profile_id, &merchant_id),
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::BusinessProfileList))]
|
||||
pub async fn business_profiles_list(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
path: web::Path<String>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::BusinessProfileList;
|
||||
let merchant_id = path.into_inner();
|
||||
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
merchant_id,
|
||||
|state, _, merchant_id| list_business_profile(&*state.store, merchant_id),
|
||||
&auth::AdminApiAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Merchant Account - KV Status
|
||||
///
|
||||
/// Toggle KV mode for the Merchant Account
|
||||
|
||||
@ -528,3 +528,24 @@ impl Cache {
|
||||
.service(web::resource("/invalidate/{key}").route(web::post().to(invalidate)))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BusinessProfile;
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
impl BusinessProfile {
|
||||
pub fn server(state: AppState) -> Scope {
|
||||
web::scope("/account/{account_id}/business_profile")
|
||||
.app_data(web::Data::new(state))
|
||||
.service(
|
||||
web::resource("")
|
||||
.route(web::post().to(business_profile_create))
|
||||
.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)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub use api_models::admin::{
|
||||
payout_routing_algorithm, MerchantAccountCreate, MerchantAccountDeleteResponse,
|
||||
payout_routing_algorithm, BusinessProfileCreate, BusinessProfileResponse,
|
||||
BusinessProfileUpdate, MerchantAccountCreate, MerchantAccountDeleteResponse,
|
||||
MerchantAccountResponse, MerchantAccountUpdate, MerchantConnectorCreate,
|
||||
MerchantConnectorDeleteResponse, MerchantConnectorDetails, MerchantConnectorDetailsWrap,
|
||||
MerchantConnectorId, MerchantConnectorResponse, MerchantDetails, MerchantId,
|
||||
@ -7,8 +8,12 @@ pub use api_models::admin::{
|
||||
RoutingAlgorithm, StraightThroughAlgorithm, ToggleKVRequest, ToggleKVResponse, WebhookDetails,
|
||||
};
|
||||
use common_utils::ext_traits::ValueExt;
|
||||
use masking::Secret;
|
||||
|
||||
use crate::{core::errors, types::domain};
|
||||
use crate::{
|
||||
core::errors,
|
||||
types::{domain, storage, transformers::ForeignTryFrom},
|
||||
};
|
||||
|
||||
impl TryFrom<domain::MerchantAccount> for MerchantAccountResponse {
|
||||
type Error = error_stack::Report<errors::ParsingError>;
|
||||
@ -41,3 +46,27 @@ impl TryFrom<domain::MerchantAccount> for MerchantAccountResponse {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignTryFrom<storage::business_profile::BusinessProfile> for BusinessProfileResponse {
|
||||
type Error = error_stack::Report<errors::ParsingError>;
|
||||
|
||||
fn foreign_try_from(
|
||||
item: storage::business_profile::BusinessProfile,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
merchant_id: item.merchant_id,
|
||||
profile_id: item.profile_id,
|
||||
profile_name: item.profile_name,
|
||||
return_url: item.return_url,
|
||||
enable_payment_response_hash: item.enable_payment_response_hash,
|
||||
payment_response_hash_key: item.payment_response_hash_key,
|
||||
redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
|
||||
webhook_details: item.webhook_details.map(Secret::new),
|
||||
metadata: item.metadata,
|
||||
routing_algorithm: item.routing_algorithm,
|
||||
intent_fulfillment_time: item.intent_fulfillment_time,
|
||||
frm_routing_algorithm: item.frm_routing_algorithm,
|
||||
payout_routing_algorithm: item.payout_routing_algorithm,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod address;
|
||||
pub mod api_keys;
|
||||
pub mod business_profile;
|
||||
pub mod capture;
|
||||
pub mod cards_info;
|
||||
pub mod configs;
|
||||
|
||||
3
crates/router/src/types/storage/business_profile.rs
Normal file
3
crates/router/src/types/storage/business_profile.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub use diesel_models::business_profile::{
|
||||
BusinessProfile, BusinessProfileNew, BusinessProfileUpdateInternal,
|
||||
};
|
||||
@ -191,6 +191,16 @@ pub enum Flow {
|
||||
RetrieveDisputeEvidence,
|
||||
/// Invalidate cache flow
|
||||
CacheInvalidate,
|
||||
/// Create a business profile
|
||||
BusinessProfileCreate,
|
||||
/// Update a business profile
|
||||
BusinessProfileUpdate,
|
||||
/// Retrieve a business profile
|
||||
BusinessProfileRetrieve,
|
||||
/// Delete a business profile
|
||||
BusinessProfileDelete,
|
||||
/// List all the business profiles for a merchant
|
||||
BusinessProfileList,
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE IF EXISTS business_profile;
|
||||
@ -0,0 +1,19 @@
|
||||
-- Your SQL goes here
|
||||
CREATE TABLE IF NOT EXISTS business_profile (
|
||||
profile_id VARCHAR(64) PRIMARY KEY,
|
||||
merchant_id VARCHAR(64) NOT NULL,
|
||||
profile_name VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL,
|
||||
modified_at TIMESTAMP NOT NULL,
|
||||
return_url TEXT,
|
||||
enable_payment_response_hash BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
payment_response_hash_key VARCHAR(255) DEFAULT NULL,
|
||||
redirect_to_merchant_with_http_post BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
webhook_details JSON,
|
||||
metadata JSON,
|
||||
routing_algorithm JSON,
|
||||
intent_fulfillment_time BIGINT,
|
||||
frm_routing_algorithm JSONB,
|
||||
payout_routing_algorithm JSONB,
|
||||
is_recon_enabled BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
@ -5885,7 +5885,7 @@
|
||||
},
|
||||
"payment_response_hash_key": {
|
||||
"type": "string",
|
||||
"description": "Refers to the hash key used for payment response",
|
||||
"description": "Refers to the hash key used for calculating the signature for webhooks and redirect response\nIf the value is not provided, a default value is used",
|
||||
"nullable": true
|
||||
},
|
||||
"redirect_to_merchant_with_http_post": {
|
||||
|
||||
Reference in New Issue
Block a user