Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(business_profile): add business profile table and CRUD endpoints #1928

Merged
merged 12 commits into from
Aug 18, 2023
172 changes: 171 additions & 1 deletion crates/api_models/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 changes: 72 additions & 0 deletions crates/diesel_models/src/business_profile.rs
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions crates/diesel_models/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
1 change: 1 addition & 0 deletions crates/diesel_models/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod address;
pub mod api_keys;
pub mod business_profile;
mod capture;
pub mod cards_info;
pub mod configs;
Expand Down
82 changes: 82 additions & 0 deletions crates/diesel_models/src/query/business_profile.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
29 changes: 29 additions & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down Expand Up @@ -754,6 +782,7 @@ diesel::table! {
diesel::allow_tables_to_appear_in_same_query!(
address,
api_keys,
business_profile,
captures,
cards_info,
configs,
Expand Down
Loading
Loading