Skip to content

Commit

Permalink
feat(db): implement MerchantAccountInteraface for Mockdb (#6283)
Browse files Browse the repository at this point in the history
  • Loading branch information
akhildevelops authored Nov 5, 2024
1 parent e457ccd commit 5f493a5
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 46 deletions.
98 changes: 98 additions & 0 deletions crates/diesel_models/src/merchant_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,36 @@ pub struct MerchantAccountUpdateInternal {
pub recon_status: Option<storage_enums::ReconStatus>,
}

#[cfg(feature = "v2")]
impl MerchantAccountUpdateInternal {
pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount {
let Self {
merchant_name,
merchant_details,
publishable_key,
storage_scheme,
metadata,
modified_at,
organization_id,
recon_status,
} = self;

MerchantAccount {
merchant_name: merchant_name.or(source.merchant_name),
merchant_details: merchant_details.or(source.merchant_details),
publishable_key: publishable_key.or(source.publishable_key),
storage_scheme: storage_scheme.unwrap_or(source.storage_scheme),
metadata: metadata.or(source.metadata),
created_at: source.created_at,
modified_at,
organization_id: organization_id.unwrap_or(source.organization_id),
recon_status: recon_status.unwrap_or(source.recon_status),
version: source.version,
id: source.id,
}
}
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
Expand Down Expand Up @@ -290,3 +320,71 @@ pub struct MerchantAccountUpdateInternal {
pub payment_link_config: Option<serde_json::Value>,
pub pm_collect_link_config: Option<serde_json::Value>,
}

#[cfg(feature = "v1")]
impl MerchantAccountUpdateInternal {
pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount {
let Self {
merchant_name,
merchant_details,
return_url,
webhook_details,
sub_merchants_enabled,
parent_merchant_id,
enable_payment_response_hash,
payment_response_hash_key,
redirect_to_merchant_with_http_post,
publishable_key,
storage_scheme,
locker_id,
metadata,
routing_algorithm,
primary_business_details,
modified_at,
intent_fulfillment_time,
frm_routing_algorithm,
payout_routing_algorithm,
organization_id,
is_recon_enabled,
default_profile,
recon_status,
payment_link_config,
pm_collect_link_config,
} = self;

MerchantAccount {
merchant_id: source.merchant_id,
return_url: return_url.or(source.return_url),
enable_payment_response_hash: enable_payment_response_hash
.unwrap_or(source.enable_payment_response_hash),
payment_response_hash_key: payment_response_hash_key
.or(source.payment_response_hash_key),
redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post
.unwrap_or(source.redirect_to_merchant_with_http_post),
merchant_name: merchant_name.or(source.merchant_name),
merchant_details: merchant_details.or(source.merchant_details),
webhook_details: webhook_details.or(source.webhook_details),
sub_merchants_enabled: sub_merchants_enabled.or(source.sub_merchants_enabled),
parent_merchant_id: parent_merchant_id.or(source.parent_merchant_id),
publishable_key: publishable_key.or(source.publishable_key),
storage_scheme: storage_scheme.unwrap_or(source.storage_scheme),
locker_id: locker_id.or(source.locker_id),
metadata: metadata.or(source.metadata),
routing_algorithm: routing_algorithm.or(source.routing_algorithm),
primary_business_details: primary_business_details
.unwrap_or(source.primary_business_details),
intent_fulfillment_time: intent_fulfillment_time.or(source.intent_fulfillment_time),
created_at: source.created_at,
modified_at,
frm_routing_algorithm: frm_routing_algorithm.or(source.frm_routing_algorithm),
payout_routing_algorithm: payout_routing_algorithm.or(source.payout_routing_algorithm),
organization_id: organization_id.unwrap_or(source.organization_id),
is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled),
default_profile: default_profile.unwrap_or(source.default_profile),
recon_status: recon_status.unwrap_or(source.recon_status),
payment_link_config: payment_link_config.or(source.payment_link_config),
pm_collect_link_config: pm_collect_link_config.or(source.pm_collect_link_config),
version: source.version,
}
}
}
4 changes: 2 additions & 2 deletions crates/hyperswitch_domain_models/src/merchant_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl MerchantAccount {

#[cfg(feature = "v1")]
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum MerchantAccountUpdate {
Update {
merchant_name: OptionalEncryptableName,
Expand Down Expand Up @@ -237,7 +237,7 @@ pub enum MerchantAccountUpdate {

#[cfg(feature = "v2")]
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum MerchantAccountUpdate {
Update {
merchant_name: OptionalEncryptableName,
Expand Down
222 changes: 178 additions & 44 deletions crates/router/src/db/merchant_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,91 +482,225 @@ impl MerchantAccountInterface for MockDb {
merchant_key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
let accounts = self.merchant_accounts.lock().await;
let account: Option<domain::MerchantAccount> = accounts
accounts
.iter()
.find(|account| account.get_id() == merchant_id)
.cloned()
.async_map(|a| async {
a.convert(
state,
merchant_key_store.key.get_inner(),
merchant_key_store.merchant_id.clone().into(),
)
.await
.change_context(errors::StorageError::DecryptionError)
})
.ok_or(errors::StorageError::ValueNotFound(format!(
"Merchant ID: {:?} not found",
merchant_id
)))?
.convert(
state,
merchant_key_store.key.get_inner(),
merchant_key_store.merchant_id.clone().into(),
)
.await
.transpose()?;

match account {
Some(account) => Ok(account),
// [#172]: Implement function for `MockDb`
None => Err(errors::StorageError::MockDbError)?,
}
.change_context(errors::StorageError::DecryptionError)
}

async fn update_merchant(
&self,
_state: &KeyManagerState,
_this: domain::MerchantAccount,
_merchant_account: storage::MerchantAccountUpdate,
_merchant_key_store: &domain::MerchantKeyStore,
state: &KeyManagerState,
merchant_account: domain::MerchantAccount,
merchant_account_update: storage::MerchantAccountUpdate,
merchant_key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
// [#172]: Implement function for `MockDb`
Err(errors::StorageError::MockDbError)?
let merchant_id = merchant_account.get_id().to_owned();
let mut accounts = self.merchant_accounts.lock().await;
accounts
.iter_mut()
.find(|account| account.get_id() == merchant_account.get_id())
.async_map(|account| async {
let update = MerchantAccountUpdateInternal::from(merchant_account_update)
.apply_changeset(
Conversion::convert(merchant_account)
.await
.change_context(errors::StorageError::EncryptionError)?,
);
*account = update.clone();
update
.convert(
state,
merchant_key_store.key.get_inner(),
merchant_key_store.merchant_id.clone().into(),
)
.await
.change_context(errors::StorageError::DecryptionError)
})
.await
.transpose()?
.ok_or(
errors::StorageError::ValueNotFound(format!(
"Merchant ID: {:?} not found",
merchant_id
))
.into(),
)
}

async fn update_specific_fields_in_merchant(
&self,
_state: &KeyManagerState,
_merchant_id: &common_utils::id_type::MerchantId,
_merchant_account: storage::MerchantAccountUpdate,
_merchant_key_store: &domain::MerchantKeyStore,
state: &KeyManagerState,
merchant_id: &common_utils::id_type::MerchantId,
merchant_account_update: storage::MerchantAccountUpdate,
merchant_key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
// [#TODO]: Implement function for `MockDb`
Err(errors::StorageError::MockDbError)?
let mut accounts = self.merchant_accounts.lock().await;
accounts
.iter_mut()
.find(|account| account.get_id() == merchant_id)
.async_map(|account| async {
let update = MerchantAccountUpdateInternal::from(merchant_account_update)
.apply_changeset(account.clone());
*account = update.clone();
update
.convert(
state,
merchant_key_store.key.get_inner(),
merchant_key_store.merchant_id.clone().into(),
)
.await
.change_context(errors::StorageError::DecryptionError)
})
.await
.transpose()?
.ok_or(
errors::StorageError::ValueNotFound(format!(
"Merchant ID: {:?} not found",
merchant_id
))
.into(),
)
}

async fn find_merchant_account_by_publishable_key(
&self,
_state: &KeyManagerState,
_publishable_key: &str,
state: &KeyManagerState,
publishable_key: &str,
) -> CustomResult<authentication::AuthenticationData, errors::StorageError> {
// [#172]: Implement function for `MockDb`
Err(errors::StorageError::MockDbError)?
let accounts = self.merchant_accounts.lock().await;
let account = accounts
.iter()
.find(|account| {
account
.publishable_key
.as_ref()
.is_some_and(|key| key == publishable_key)
})
.ok_or(errors::StorageError::ValueNotFound(format!(
"Publishable Key: {} not found",
publishable_key
)))?;
let key_store = self
.get_merchant_key_store_by_merchant_id(
state,
account.get_id(),
&self.get_master_key().to_vec().into(),
)
.await?;
Ok(authentication::AuthenticationData {
merchant_account: account
.clone()
.convert(
state,
key_store.key.get_inner(),
key_store.merchant_id.clone().into(),
)
.await
.change_context(errors::StorageError::DecryptionError)?,

key_store,
profile_id: None,
})
}

async fn update_all_merchant_account(
&self,
_merchant_account_update: storage::MerchantAccountUpdate,
merchant_account_update: storage::MerchantAccountUpdate,
) -> CustomResult<usize, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
let mut accounts = self.merchant_accounts.lock().await;
Ok(accounts.iter_mut().fold(0, |acc, account| {
let update = MerchantAccountUpdateInternal::from(merchant_account_update.clone())
.apply_changeset(account.clone());
*account = update;
acc + 1
}))
}

async fn delete_merchant_account_by_merchant_id(
&self,
_merchant_id: &common_utils::id_type::MerchantId,
merchant_id: &common_utils::id_type::MerchantId,
) -> CustomResult<bool, errors::StorageError> {
// [#172]: Implement function for `MockDb`
Err(errors::StorageError::MockDbError)?
let mut accounts = self.merchant_accounts.lock().await;
accounts.retain(|x| x.get_id() != merchant_id);
Ok(true)
}

#[cfg(feature = "olap")]
async fn list_merchant_accounts_by_organization_id(
&self,
_state: &KeyManagerState,
_organization_id: &common_utils::id_type::OrganizationId,
state: &KeyManagerState,
organization_id: &common_utils::id_type::OrganizationId,
) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
let accounts = self.merchant_accounts.lock().await;
let futures = accounts
.iter()
.filter(|account| account.organization_id == *organization_id)
.map(|account| async {
let key_store = self
.get_merchant_key_store_by_merchant_id(
state,
account.get_id(),
&self.get_master_key().to_vec().into(),
)
.await;
match key_store {
Ok(key) => account
.clone()
.convert(state, key.key.get_inner(), key.merchant_id.clone().into())
.await
.change_context(errors::StorageError::DecryptionError),
Err(err) => Err(err),
}
});
futures::future::join_all(futures)
.await
.into_iter()
.collect()
}

#[cfg(feature = "olap")]
async fn list_multiple_merchant_accounts(
&self,
_state: &KeyManagerState,
_merchant_ids: Vec<common_utils::id_type::MerchantId>,
state: &KeyManagerState,
merchant_ids: Vec<common_utils::id_type::MerchantId>,
) -> CustomResult<Vec<domain::MerchantAccount>, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
let accounts = self.merchant_accounts.lock().await;
let futures = accounts
.iter()
.filter(|account| merchant_ids.contains(account.get_id()))
.map(|account| async {
let key_store = self
.get_merchant_key_store_by_merchant_id(
state,
account.get_id(),
&self.get_master_key().to_vec().into(),
)
.await;
match key_store {
Ok(key) => account
.clone()
.convert(state, key.key.get_inner(), key.merchant_id.clone().into())
.await
.change_context(errors::StorageError::DecryptionError),
Err(err) => Err(err),
}
});
futures::future::join_all(futures)
.await
.into_iter()
.collect()
}
}

Expand Down
Loading

0 comments on commit 5f493a5

Please sign in to comment.