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(db): implement MerchantAccountInteraface for Mockdb #6283

Merged
merged 13 commits into from
Nov 5, 2024
5 changes: 4 additions & 1 deletion .gitignore
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,7 @@ result*
node_modules/

# cypress credentials
creds.json
creds.json

.vscode

51 changes: 51 additions & 0 deletions crates/diesel_models/src/merchant_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,57 @@ impl MerchantAccount {
}
}

impl MerchantAccount {
#[cfg(feature = "v1")]
pub fn from_update(
&mut self,
update: MerchantAccountUpdateInternal,
) -> Result<(), &'static str> {
macro_rules! update {
([$(($attr:ident,)),*]) => {

$(self.$attr = update.$attr;)*
};
([$(($attr:ident,$error:literal)),*])=>{
$(self.$attr = update.$attr.ok_or(concat!($error,stringify!($attr)))?;)*
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
};

}

update!([
(merchant_name,),
(merchant_details,),
(return_url,),
(webhook_details,),
(sub_merchants_enabled,),
(parent_merchant_id,),
(publishable_key,),
(payment_response_hash_key,),
(locker_id,),
(metadata,),
(routing_algorithm,),
(modified_at,),
(intent_fulfillment_time,),
(frm_routing_algorithm,),
(payout_routing_algorithm,),
(payment_link_config,),
(pm_collect_link_config,)
]);

update!([
(redirect_to_merchant_with_http_post, "Cannot decide to "),
(enable_payment_response_hash, "Cannot decide to "),
(storage_scheme, "Cannot decide on"),
(primary_business_details, "Didn't receive "),
(organization_id, "Cannot update "),
(is_recon_enabled, "Don't know "),
(recon_status, "Don't know about "),
(default_profile, "Didn't receive ")
]);
Ok(())
}
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
#[diesel(table_name = merchant_account)]
Expand Down
2 changes: 1 addition & 1 deletion 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
152 changes: 125 additions & 27 deletions crates/router/src/db/merchant_account.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(feature = "olap")]
use std::collections::HashMap;

use common_utils::{ext_traits::AsyncExt, types::keymanager::KeyManagerState};
use common_utils::types::keymanager::KeyManagerState;
use diesel_models::MerchantAccountUpdateInternal;
use error_stack::{report, ResultExt};
use router_env::{instrument, tracing};
Expand All @@ -22,7 +22,6 @@ use crate::{
storage,
},
};

#[async_trait::async_trait]
pub trait MerchantAccountInterface
where
Expand Down Expand Up @@ -482,27 +481,21 @@ 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(
Expand All @@ -512,8 +505,13 @@ impl MerchantAccountInterface for MockDb {
_merchant_account: storage::MerchantAccountUpdate,
_merchant_key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
// [#172]: Implement function for `MockDb`
Err(errors::StorageError::MockDbError)?
self.update_specific_fields_in_merchant(
_state,
_this.get_id(),
_merchant_account,
_merchant_key_store,
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
)
.await
}

async fn update_specific_fields_in_merchant(
Expand All @@ -524,7 +522,19 @@ impl MerchantAccountInterface for MockDb {
_merchant_key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
// [#TODO]: Implement function for `MockDb`
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
Err(errors::StorageError::MockDbError)?
let mut accounts = self.merchant_accounts.lock().await;
let account = accounts
.iter_mut()
.find(|account| account.get_id() == _merchant_id)
.ok_or(errors::StorageError::ValueNotFound(format!(
"Merchant ID: {:?} not found",
_merchant_id
)))?;
account
.from_update(_merchant_account.into())
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
.map_err(|_| errors::StorageError::MockDbError)?;
self.find_merchant_account_by_merchant_id(_state, _merchant_id, _merchant_key_store)
.await
}

async fn find_merchant_account_by_publishable_key(
Expand All @@ -533,22 +543,62 @@ impl MerchantAccountInterface for MockDb {
_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)
akhildevelops marked this conversation as resolved.
Show resolved Hide resolved
})
.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,
) -> CustomResult<usize, errors::StorageError> {
Err(errors::StorageError::MockDbError)?
let mut accounts = self.merchant_accounts.lock().await;
Ok(accounts.iter_mut().fold(0, |acc, account| {
account
.from_update(_merchant_account_update.clone().into())
.map_or(acc, |_| acc + 1)
}))
}

async fn delete_merchant_account_by_merchant_id(
&self,
_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")]
Expand All @@ -557,7 +607,31 @@ impl MerchantAccountInterface for MockDb {
_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")]
Expand All @@ -566,7 +640,31 @@ impl MerchantAccountInterface for MockDb {
_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
1 change: 1 addition & 0 deletions docker-compose-development.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ services:
FROM rust:latest
RUN apt-get update && \
apt-get install -y protobuf-compiler
RUN rustup component add rustfmt clippy
command: cargo run --bin router -- -f ./config/docker_compose.toml
working_dir: /app
ports:
Expand Down
Loading