use std::sync::Arc; use crate::{ db::entities::{ account::{ ActiveModel as AccountActiveModel, Entity as AccountEntity, Model as AccountModel, }, account_category::{ ActiveModel as AccountCategoryActiveModel, Entity as AccountCategoryEntity, Model as AccountCategoryModel, }, }, services::accounts::category::{ AccountType, CreateAccountCategoryRequest, UpdateAccountCategoryRequest, }, }; use sea_orm::{ ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait, TransactionTrait, }; pub mod category; pub struct Account { pub id: i64, pub name: String, pub account_type: AccountType, pub account_category: String, // pub created_at: String, pub updated_at: String, } impl From<(AccountModel, AccountCategoryModel)> for Account { fn from((account_model, category_model): (AccountModel, AccountCategoryModel)) -> Self { Account { id: account_model.id, name: account_model.name, account_type: AccountType::from(category_model.account_type), account_category: category_model.name, created_at: account_model.created_at, updated_at: account_model.updated_at, } } } pub struct CreateAccountRequest { pub name: String, pub category: CreateAccountCategoryRequest, } pub struct UpdateAccountRequest { pub name: Option, pub category: Option, } #[async_trait::async_trait] pub trait AccountsService: Send + Sync + 'static { async fn get_accounts(&self) -> Result, String>; async fn get_account(&self, id: &i64) -> Result, String>; async fn create_account(&self, create_request: CreateAccountRequest) -> Result; async fn update_account( &self, id: &i64, update_request: UpdateAccountRequest, ) -> Result<(), String>; async fn delete_account(&self, id: &i64) -> Result<(), String>; } pub struct AccountsServiceImpl { db: DatabaseConnection, account_category_service: Arc, } impl AccountsServiceImpl { pub fn new( db: DatabaseConnection, account_category_service: Arc, ) -> Self { Self { db, account_category_service, } } } #[async_trait::async_trait] impl AccountsService for AccountsServiceImpl { async fn get_accounts(&self) -> Result, String> { let accounts = AccountEntity::find() .find_both_related(AccountCategoryEntity) .all(&self.db) .await; match accounts { Ok(accounts) => Ok(accounts.into_iter().map(|a| a.into()).collect()), Err(e) => Err(format!("Failed to fetch accounts: {}", e)), } } async fn get_account(&self, id: &i64) -> Result, String> { let result = AccountEntity::find_by_id(*id) .find_both_related(AccountCategoryEntity) .one(&self.db) .await; match result { Ok(Some(account)) => Ok(Some(account.into())), Ok(None) => Ok(None), Err(e) => Err(format!("Failed to fetch account: {}", e)), } } async fn create_account(&self, create_request: CreateAccountRequest) -> Result { let tx = self.db.begin().await.map_err(|e| e.to_string())?; let category_id = self .account_category_service .create_category_with_tx( CreateAccountCategoryRequest { name: create_request.category.name, account_type: create_request.category.account_type, }, &(&tx).into(), ) .await?; let new_account = AccountEntity::insert(AccountActiveModel { name: Set(create_request.name), created_at: Set(chrono::Utc::now().to_string()), updated_at: Set(chrono::Utc::now().to_string()), account_category_id: Set(category_id), ..Default::default() }) .exec(&tx) .await; tx.commit().await.map_err(|e| e.to_string())?; match new_account { Ok(res) => Ok(res.last_insert_id), Err(e) => Err(format!("Failed to create account: {}", e)), } } async fn update_account( &self, id: &i64, update_request: UpdateAccountRequest, ) -> Result<(), String> { let tx = self.db.begin().await.map_err(|e| e.to_string())?; let account = AccountEntity::find_by_id(*id).one(&tx).await; match account { Ok(Some(account)) => { let mut active_model: AccountActiveModel = account.into(); // Only update fields that are provided in the request if let Some(name) = update_request.name { active_model.name = Set(name); } // if let Some(category_request) = update_request.category { // update the category if it is provided in the request self.account_category_service .update_category_with_tx(id, category_request, &(&tx).into()) .await?; } active_model.updated_at = Set(chrono::Utc::now().to_string()); // active_model.update(&tx).await.map_err(|e| e.to_string())?; let res = tx.commit().await.map_err(|e| e.to_string()); match res { Ok(_) => Ok(()), Err(e) => Err(format!("Failed to update account: {}", e)), } } Ok(None) => Err("Account not found".to_string()), Err(e) => Err(format!("Failed to fetch account: {}", e)), } } async fn delete_account(&self, id: &i64) -> Result<(), String> { let res = AccountEntity::delete_by_id(*id).exec(&self.db).await; match res { Ok(_) => Ok(()), Err(e) => Err(format!("Failed to delete account: {}", e)), } } }