fix: update DTOs for account and account category with validation and timestamp adjustments

This commit is contained in:
GW_MC
2026-05-27 11:19:27 +00:00
parent 517fb37818
commit 1d5e24bdfb
2 changed files with 35 additions and 9 deletions

View File

@@ -1,13 +1,16 @@
// TODO: validation for all dto
use crate::db::{ use crate::db::{
Db,
entities::account_category::{ entities::account_category::{
ActiveModel as AccountCategoryActiveModel, Entity as AccountCategoryEntity, ActiveModel as AccountCategoryActiveModel, Entity as AccountCategoryEntity,
}, },
Db,
}; };
use migration::OnConflict;
use sea_orm::{ use sea_orm::{
ActiveModelTrait, ActiveValue::Set, ColumnTrait, ConnectionTrait, DatabaseConnection, ActiveModelTrait, ActiveValue::Set, ColumnTrait, DatabaseConnection, EntityTrait,
DatabaseTransaction, EntityTrait, IntoActiveModel, ModelTrait, PaginatorTrait, QueryFilter, IntoActiveModel, ModelTrait, PaginatorTrait, QueryFilter,
}; };
use serde::{Deserialize, Serialize};
pub struct AccountCategory { pub struct AccountCategory {
pub id: i64, pub id: i64,
@@ -18,17 +21,23 @@ pub struct AccountCategory {
pub updated_at: String, pub updated_at: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AccountType { pub enum AccountType {
Asset, // Positive balance, e.g. Checking, Savings #[serde(rename = "Asset")]
Asset, // Positive balance, e.g. Checking, Savings
#[serde(rename = "Liability")]
Liability, // Negative balance, e.g. Credit Card Liability, // Negative balance, e.g. Credit Card
Unknown, // Fallback for unknown types #[serde(other, rename = "Unknown")]
Unknown, // Fallback for unknown types
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateAccountCategoryRequest { pub struct CreateAccountCategoryRequest {
pub name: String, pub name: String,
pub account_type: AccountType, pub account_type: AccountType,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateAccountCategoryRequest { pub struct UpdateAccountCategoryRequest {
pub name: Option<String>, pub name: Option<String>,
pub account_type: Option<AccountType>, pub account_type: Option<AccountType>,
@@ -129,9 +138,20 @@ impl AccountCategoryService for AccountCategoryServiceImpl {
let new_category = AccountCategoryActiveModel { let new_category = AccountCategoryActiveModel {
name: Set(create_request.name), name: Set(create_request.name),
account_type: Set(create_request.account_type.to_string()), account_type: Set(create_request.account_type.to_string()),
created_at: Set(chrono::Utc::now().to_rfc3339()),
updated_at: Set(chrono::Utc::now().to_rfc3339()),
..Default::default() ..Default::default()
}; };
let res = new_category.insert(tx).await.map_err(|e| e.to_string())?; let res = AccountCategoryEntity::insert(new_category)
.on_conflict(
// force update to ensure a record is returned
OnConflict::column(crate::db::entities::account_category::Column::Name)
.update_column(crate::db::entities::account_category::Column::Name)
.to_owned(),
)
.exec_with_returning(tx)
.await
.map_err(|e| e.to_string())?;
Ok(res.id) Ok(res.id)
} }
@@ -187,6 +207,7 @@ impl AccountCategoryService for AccountCategoryServiceImpl {
if let Some(account_type) = update_request.account_type { if let Some(account_type) = update_request.account_type {
category.account_type = Set(account_type.to_string()); category.account_type = Set(account_type.to_string());
} }
category.updated_at = Set(chrono::Utc::now().to_rfc3339());
category.update(tx).await.map_err(|e| e.to_string())?; category.update(tx).await.map_err(|e| e.to_string())?;
Ok(()) Ok(())
} else { } else {

View File

@@ -1,3 +1,4 @@
// TODO: validation for all dto
use std::sync::Arc; use std::sync::Arc;
use crate::{ use crate::{
@@ -17,9 +18,11 @@ use crate::{
use sea_orm::{ use sea_orm::{
ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait, TransactionTrait, ActiveModelTrait, ActiveValue::Set, DatabaseConnection, EntityTrait, TransactionTrait,
}; };
use serde::{Deserialize, Serialize};
pub mod category; pub mod category;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Account { pub struct Account {
pub id: i64, pub id: i64,
pub name: String, pub name: String,
@@ -43,11 +46,13 @@ impl From<(AccountModel, AccountCategoryModel)> for Account {
} }
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateAccountRequest { pub struct CreateAccountRequest {
pub name: String, pub name: String,
pub category: CreateAccountCategoryRequest, pub category: CreateAccountCategoryRequest,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateAccountRequest { pub struct UpdateAccountRequest {
pub name: Option<String>, pub name: Option<String>,
pub category: Option<UpdateAccountCategoryRequest>, pub category: Option<UpdateAccountCategoryRequest>,
@@ -125,8 +130,8 @@ impl AccountsService for AccountsServiceImpl {
let new_account = AccountEntity::insert(AccountActiveModel { let new_account = AccountEntity::insert(AccountActiveModel {
name: Set(create_request.name), name: Set(create_request.name),
created_at: Set(chrono::Utc::now().to_string()), created_at: Set(chrono::Utc::now().to_rfc3339()),
updated_at: Set(chrono::Utc::now().to_string()), updated_at: Set(chrono::Utc::now().to_rfc3339()),
account_category_id: Set(category_id), account_category_id: Set(category_id),
..Default::default() ..Default::default()
}) })
@@ -162,7 +167,7 @@ impl AccountsService for AccountsServiceImpl {
.update_category_with_tx(id, category_request, &(&tx).into()) .update_category_with_tx(id, category_request, &(&tx).into())
.await?; .await?;
} }
active_model.updated_at = Set(chrono::Utc::now().to_string()); active_model.updated_at = Set(chrono::Utc::now().to_rfc3339());
// //
active_model.update(&tx).await.map_err(|e| e.to_string())?; active_model.update(&tx).await.map_err(|e| e.to_string())?;
let res = tx.commit().await.map_err(|e| e.to_string()); let res = tx.commit().await.map_err(|e| e.to_string());