Bug: [BUG] Add Create Merchant and Create Merchant Key Store in a DB transaction



Currently MerchantAccount and MerchantKeyStore are getting inserted seperately. Since both of them are interdependent we need to make sure both are consistent with each other. If one of them fails  other shouldn't get inserted. 

We need to add this in a db_transaction
https://github.com/juspay/hyperswitch/blob/4805a94ab905da520edacdddab41e9e74bd3a956/crates/router/src/core/admin.rs#L133-L186

For reference of how to do it in a db transaction
```rust
  pool.transaction_async(|conn| async move {
        diesel::update(dsl::users)
            .filter(dsl::id.eq(0))
            .set(dsl::name.eq("Let's change the name again"))
            .execute_async(&conn)
            .await
            .map_err(|e| PoolError::Connection(e))
})
```
diff --git a/crates/diesel_models/src/errors.rs b/crates/diesel_models/src/errors.rs
index 0a8422131ae..30e4273fdb5 100644
--- a/crates/diesel_models/src/errors.rs
+++ b/crates/diesel_models/src/errors.rs
@@ -10,7 +10,15 @@ pub enum DatabaseError {
     NoFieldsToUpdate,
     #[error("An error occurred when generating typed SQL query")]
     QueryGenerationFailed,
+    #[error("DB transaction failure")]
+    TransactionFailed(String),
     // InsertFailed,
     #[error("An unknown error occurred")]
     Others,
 }
+
+impl From<diesel::result::Error> for DatabaseError {
+    fn from(err: diesel::result::Error) -> Self {
+        Self::TransactionFailed(err.to_string())
+    }
+}
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index c0d6c576dd5..0472ffb4198 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -111,10 +111,6 @@ pub async fn create_merchant_account(
         .payment_response_hash_key
         .or(Some(generate_cryptographically_secure_random_string(64)));
 
-    db.insert_merchant_key_store(key_store.clone(), &master_key.to_vec().into())
-        .await
-        .to_duplicate_response(errors::ApiErrorResponse::DuplicateMerchantAccount)?;
-
     let parent_merchant_id = get_parent_merchant(
         db,
         req.sub_merchants_enabled,
diff --git a/crates/router/src/db/merchant_account.rs b/crates/router/src/db/merchant_account.rs
index e0bff7d9069..5f533eabc9f 100644
--- a/crates/router/src/db/merchant_account.rs
+++ b/crates/router/src/db/merchant_account.rs
@@ -1,3 +1,4 @@
+use async_bb8_diesel::AsyncConnection;
 use common_utils::ext_traits::AsyncExt;
 use error_stack::{IntoReport, ResultExt};
 #[cfg(feature = "accounts_cache")]
@@ -72,20 +73,36 @@ impl MerchantAccountInterface for Store {
     async fn insert_merchant(
         &self,
         merchant_account: domain::MerchantAccount,
-        merchant_key_store: &domain::MerchantKeyStore,
+        merchant_key_store: domain::MerchantKeyStore,
     ) -> CustomResult<domain::MerchantAccount, errors::StorageError> {
         let conn = connection::pg_connection_write(self).await?;
-        merchant_account
-            .construct_new()
-            .await
-            .change_context(errors::StorageError::EncryptionError)?
-            .insert(&conn)
-            .await
-            .map_err(Into::into)
-            .into_report()?
-            .convert(merchant_key_store.key.get_inner())
-            .await
-            .change_context(errors::StorageError::DecryptionError)
+
+        conn.transaction_async(|e| async move {
+            let key_store = merchant_key_store
+                .construct_new()
+                .await
+                .change_context(errors::StorageError::EncryptionError)?
+                .insert(&e)
+                .await
+                .map_err(Into::into)
+                .into_report()?
+                .convert(&self.get_master_key().to_vec().into())
+                .await
+                .change_context(errors::StorageError::DecryptionError);
+
+            merchant_account
+                .construct_new()
+                .await
+                .change_context(errors::StorageError::EncryptionError)?
+                .insert(&e)
+                .await
+                .map_err(Into::into)
+                .into_report()?
+                .convert(merchant_key_store.key.get_inner())
+                .await
+                .change_context(errors::StorageError::DecryptionError)
+        })
+        .await
     }
 
     async fn find_merchant_account_by_merchant_id(
diff --git a/crates/storage_impl/src/errors.rs b/crates/storage_impl/src/errors.rs
index bc68986cb8e..c8abccdf4b6 100644
--- a/crates/storage_impl/src/errors.rs
+++ b/crates/storage_impl/src/errors.rs
@@ -98,6 +98,9 @@ impl Into<DataStorageError> for &StorageError {
                 storage_errors::DatabaseError::QueryGenerationFailed => {
                     DataStorageError::DatabaseError("Query generation failed".to_string())
                 }
+                storage_errors::DatabaseError::TransactionFailed(e) => {
+                    DataStorageError::DatabaseError(e.to_string())
+                }
                 storage_errors::DatabaseError::Others => {
                     DataStorageError::DatabaseError("Unknown database error".to_string())
                 }
diff --git a/crates/storage_impl/src/lib.rs b/crates/storage_impl/src/lib.rs
index dd8d71fc701..406c6ee9ab8 100644
--- a/crates/storage_impl/src/lib.rs
+++ b/crates/storage_impl/src/lib.rs
@@ -245,6 +245,9 @@ pub(crate) fn diesel_error_to_data_error(
         diesel_models::errors::DatabaseError::QueryGenerationFailed => {
             StorageError::DatabaseError("Query generation failed".to_string())
         }
+        store::errors::DatabaseError::TransactionFailed(e) => {
+            StorageError::DatabaseError(e.to_string())
+        }
         diesel_models::errors::DatabaseError::Others => {
             StorageError::DatabaseError("Others".to_string())
         }

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [X] Enhancement
- [X] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
Merchant account creation and respective key store creation now happen in a DB transaction

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
- Create a merchant account.
- Check if both merchant account and merchant key store exists
```
SELECT * from merchant_account;
SELECT * from merchant_key_store;
```

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
