раскидал структуру для монорепозитория
This commit is contained in:
77
backend/src/services/category_service.rs
Normal file
77
backend/src/services/category_service.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use sea_orm::*;
|
||||
use sea_orm::prelude::Decimal;
|
||||
use chrono::Utc;
|
||||
use crate::models::category::{self, Entity as Category, Model as CategoryModel};
|
||||
|
||||
pub struct CategoryService;
|
||||
|
||||
impl CategoryService {
|
||||
pub async fn create(
|
||||
db: &DatabaseConnection,
|
||||
family_id: i32,
|
||||
name: String,
|
||||
limit_amount: Decimal,
|
||||
) -> Result<CategoryModel, DbErr> {
|
||||
let category = category::ActiveModel {
|
||||
family_id: Set(family_id),
|
||||
name: Set(name),
|
||||
limit_amount: Set(limit_amount),
|
||||
created_at: Set(Utc::now().naive_utc()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
category.insert(db).await
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &DatabaseConnection, id: i32) -> Result<Option<CategoryModel>, DbErr> {
|
||||
Category::find_by_id(id).one(db).await
|
||||
}
|
||||
|
||||
pub async fn find_all(db: &DatabaseConnection) -> Result<Vec<CategoryModel>, DbErr> {
|
||||
Category::find().all(db).await
|
||||
}
|
||||
|
||||
pub async fn find_by_family_id(
|
||||
db: &DatabaseConnection,
|
||||
family_id: i32,
|
||||
) -> Result<Vec<CategoryModel>, DbErr> {
|
||||
Category::find()
|
||||
.filter(category::Column::FamilyId.eq(family_id))
|
||||
.all(db)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
db: &DatabaseConnection,
|
||||
id: i32,
|
||||
name: Option<String>,
|
||||
limit_amount: Option<Decimal>,
|
||||
) -> Result<CategoryModel, DbErr> {
|
||||
let category = Category::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Category not found".to_string()))?;
|
||||
|
||||
let mut category: category::ActiveModel = category.into();
|
||||
|
||||
if let Some(name) = name {
|
||||
category.name = Set(name);
|
||||
}
|
||||
|
||||
if let Some(limit_amount) = limit_amount {
|
||||
category.limit_amount = Set(limit_amount);
|
||||
}
|
||||
|
||||
category.update(db).await
|
||||
}
|
||||
|
||||
pub async fn delete(db: &DatabaseConnection, id: i32) -> Result<DeleteResult, DbErr> {
|
||||
let category = Category::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Category not found".to_string()))?;
|
||||
|
||||
let category: category::ActiveModel = category.into();
|
||||
category.delete(db).await
|
||||
}
|
||||
}
|
||||
95
backend/src/services/expense_service.rs
Normal file
95
backend/src/services/expense_service.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use sea_orm::*;
|
||||
use sea_orm::prelude::Decimal;
|
||||
use chrono::Utc;
|
||||
use crate::models::expense::{self, Entity as Expense, Model as ExpenseModel};
|
||||
use crate::models::category::{Entity as Category};
|
||||
|
||||
pub struct ExpenseService;
|
||||
|
||||
impl ExpenseService {
|
||||
pub async fn create(
|
||||
db: &DatabaseConnection,
|
||||
category_id: i32,
|
||||
amount: Decimal,
|
||||
description: Option<String>,
|
||||
) -> Result<ExpenseModel, DbErr> {
|
||||
let expense = expense::ActiveModel {
|
||||
category_id: Set(category_id),
|
||||
amount: Set(amount),
|
||||
description: Set(description),
|
||||
created_at: Set(Utc::now().naive_utc()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
expense.insert(db).await
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &DatabaseConnection, id: i32) -> Result<Option<ExpenseModel>, DbErr> {
|
||||
Expense::find_by_id(id).one(db).await
|
||||
}
|
||||
|
||||
pub async fn find_all(db: &DatabaseConnection) -> Result<Vec<ExpenseModel>, DbErr> {
|
||||
Expense::find().all(db).await
|
||||
}
|
||||
|
||||
pub async fn find_by_category_id(
|
||||
db: &DatabaseConnection,
|
||||
category_id: i32,
|
||||
) -> Result<Vec<ExpenseModel>, DbErr> {
|
||||
Expense::find()
|
||||
.filter(expense::Column::CategoryId.eq(category_id))
|
||||
.all(db)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
db: &DatabaseConnection,
|
||||
id: i32,
|
||||
amount: Option<Decimal>,
|
||||
description: Option<String>,
|
||||
) -> Result<ExpenseModel, DbErr> {
|
||||
let expense = Expense::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Expense not found".to_string()))?;
|
||||
|
||||
let mut expense: expense::ActiveModel = expense.into();
|
||||
|
||||
if let Some(amount) = amount {
|
||||
expense.amount = Set(amount);
|
||||
}
|
||||
|
||||
if let Some(desc) = description {
|
||||
expense.description = Set(Some(desc));
|
||||
}
|
||||
|
||||
expense.update(db).await
|
||||
}
|
||||
|
||||
pub async fn delete(db: &DatabaseConnection, id: i32) -> Result<DeleteResult, DbErr> {
|
||||
let expense = Expense::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Expense not found".to_string()))?;
|
||||
|
||||
let expense: expense::ActiveModel = expense.into();
|
||||
expense.delete(db).await
|
||||
}
|
||||
|
||||
pub async fn calculate_remaining_limit(
|
||||
db: &DatabaseConnection,
|
||||
category_id: i32,
|
||||
) -> Result<Decimal, DbErr> {
|
||||
let category = Category::find_by_id(category_id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Category not found".to_string()))?;
|
||||
|
||||
let expenses = Self::find_by_category_id(db, category_id).await?;
|
||||
|
||||
let total_spent: Decimal = expenses.iter().map(|e| e.amount).sum();
|
||||
let remaining = category.limit_amount - total_spent;
|
||||
|
||||
Ok(remaining)
|
||||
}
|
||||
}
|
||||
49
backend/src/services/family_service.rs
Normal file
49
backend/src/services/family_service.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use sea_orm::*;
|
||||
use crate::models::family::{self, Entity as Family, Model as FamilyModel};
|
||||
|
||||
pub struct FamilyService;
|
||||
|
||||
impl FamilyService {
|
||||
pub async fn create(db: &DatabaseConnection, name: String) -> Result<FamilyModel, DbErr> {
|
||||
let family = family::ActiveModel {
|
||||
name: Set(name),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
family.insert(db).await
|
||||
}
|
||||
|
||||
pub async fn find_by_id(db: &DatabaseConnection, id: i32) -> Result<Option<FamilyModel>, DbErr> {
|
||||
Family::find_by_id(id).one(db).await
|
||||
}
|
||||
|
||||
pub async fn find_all(db: &DatabaseConnection) -> Result<Vec<FamilyModel>, DbErr> {
|
||||
Family::find().all(db).await
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
db: &DatabaseConnection,
|
||||
id: i32,
|
||||
name: String,
|
||||
) -> Result<FamilyModel, DbErr> {
|
||||
let family = Family::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Family not found".to_string()))?;
|
||||
|
||||
let mut family: family::ActiveModel = family.into();
|
||||
family.name = Set(name);
|
||||
|
||||
family.update(db).await
|
||||
}
|
||||
|
||||
pub async fn delete(db: &DatabaseConnection, id: i32) -> Result<DeleteResult, DbErr> {
|
||||
let family = Family::find_by_id(id)
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or(DbErr::RecordNotFound("Family not found".to_string()))?;
|
||||
|
||||
let family: family::ActiveModel = family.into();
|
||||
family.delete(db).await
|
||||
}
|
||||
}
|
||||
7
backend/src/services/mod.rs
Normal file
7
backend/src/services/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod family_service;
|
||||
pub mod category_service;
|
||||
pub mod expense_service;
|
||||
|
||||
pub use family_service::FamilyService;
|
||||
pub use category_service::CategoryService;
|
||||
pub use expense_service::ExpenseService;
|
||||
Reference in New Issue
Block a user