Skip to content

Commit

Permalink
feat(api/accounting/cost): implement calculate_server_cost_for_all_no…
Browse files Browse the repository at this point in the history
…rmal

Signed-off-by: Sandro-Alessio Gierens <[email protected]>
  • Loading branch information
gierens committed Jan 29, 2025
1 parent acdd78f commit 3bb6b87
Showing 1 changed file with 100 additions and 24 deletions.
124 changes: 100 additions & 24 deletions api/src/routes/accounting/server_cost/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use crate::authorization::require_admin_user;
use crate::database::accounting::server_state::select_user_class_by_server_from_db;
use crate::database::pricing::flavor_price::select_flavor_prices_for_period_from_db;
use crate::database::resources::flavor::select_all_flavors_from_db;
use crate::database::user::project::select_user_class_by_project_from_db;
use crate::database::user::project::{
select_all_projects_from_db, select_user_class_by_project_from_db,
};
use crate::database::user::user::select_user_class_by_user_from_db;
use crate::error::{OptionApiError, UnexpectedOnlyError};
use crate::routes::accounting::server_consumption::get::{
calculate_server_consumption_for_all,
calculate_server_consumption_for_project,
calculate_server_consumption_for_server,
calculate_server_consumption_for_user, ServerConsumptionForProject,
ServerConsumptionForUser,
calculate_server_consumption_for_user, ServerConsumptionForAll,
ServerConsumptionForProject, ServerConsumptionForUser,
};
use actix_web::web::{Data, Query, ReqData};
use actix_web::HttpResponse;
Expand Down Expand Up @@ -195,16 +198,15 @@ pub async fn calculate_server_cost_for_server_normal(
end: DateTime<Utc>,
) -> Result<ServerCostSimple, UnexpectedOnlyError> {
let mut cost = ServerCostSimple { total: 0.0 };
let user_class = match select_user_class_by_server_from_db(
let Some(user_class) = select_user_class_by_server_from_db(
transaction,
server_uuid.to_string(),
)
.await?
.map(|u| UserClass::from_u32(u as u32))
.map_or(Ok(None), |r| r.map(Some))?
{
Some(user_class) => user_class,
None => return Ok(cost),
else {
return Ok(cost);
};
let price_periods =
get_flavor_price_periods(transaction, begin, end).await?;
Expand Down Expand Up @@ -249,16 +251,15 @@ pub async fn calculate_server_cost_for_server_detail(
total: 0.0,
flavors: HashMap::new(),
};
let user_class = match select_user_class_by_server_from_db(
let Some(user_class) = select_user_class_by_server_from_db(
transaction,
server_uuid.to_string(),
)
.await?
.map(|u| UserClass::from_u32(u as u32))
.map_or(Ok(None), |r| r.map(Some))?
{
Some(user_class) => user_class,
None => return Ok(cost),
else {
return Ok(cost);
};
let price_periods =
get_flavor_price_periods(transaction, begin, end).await?;
Expand Down Expand Up @@ -337,15 +338,14 @@ pub async fn calculate_server_cost_for_user_normal(
end: DateTime<Utc>,
) -> Result<ServerCostSimple, UnexpectedOnlyError> {
let mut cost = ServerCostSimple { total: 0.0 };
let user_class =
match select_user_class_by_user_from_db(transaction, user_id)
let Some(user_class) =
select_user_class_by_user_from_db(transaction, user_id)
.await?
.map(UserClass::from_u32)
.map_or(Ok(None), |r| r.map(Some))?
{
Some(user_class) => user_class,
None => return Ok(cost),
};
else {
return Ok(cost);
};
let price_periods =
get_flavor_price_periods(transaction, begin, end).await?;

Expand Down Expand Up @@ -437,15 +437,14 @@ pub async fn calculate_server_cost_for_project_normal(
end: DateTime<Utc>,
) -> Result<ServerCostSimple, UnexpectedOnlyError> {
let mut cost = ServerCostSimple { total: 0.0 };
let user_class =
match select_user_class_by_project_from_db(transaction, project_id)
let Some(user_class) =
select_user_class_by_project_from_db(transaction, project_id)
.await?
.map(UserClass::from_u32)
.map_or(Ok(None), |r| r.map(Some))?
{
Some(user_class) => user_class,
None => return Ok(cost),
};
else {
return Ok(cost);
};
let price_periods =
get_flavor_price_periods(transaction, begin, end).await?;

Expand Down Expand Up @@ -531,13 +530,90 @@ pub enum ServerCostForAll {
Detail(ServerCostAll),
}

// TODO: optimize/parallelize this and other functions
pub async fn calculate_server_cost_for_all_normal(
transaction: &mut Transaction<'_, MySql>,
begin: DateTime<Utc>,
end: DateTime<Utc>,
) -> Result<ServerCostSimple, UnexpectedOnlyError> {
let mut cost = ServerCostSimple { total: 0.0 };
let price_periods =
get_flavor_price_periods(transaction, begin, end).await?;

let mut end_times =
price_periods.keys().skip(1).cloned().collect::<Vec<_>>();
end_times.push(end);

let projects = select_all_projects_from_db(transaction)
.await?
.into_iter()
.map(|p| (p.name.clone(), p))
.collect::<HashMap<_, _>>();

for ((start_time, prices), end_time) in price_periods.iter().zip(end_times)
{
let ServerConsumptionForAll::Detail(consumption) =
calculate_server_consumption_for_all(
transaction,
Some(*start_time),
Some(end_time),
Some(true),
)
.await?
else {
return Err(
anyhow!("Unexpected ServerConsumptionForAll variant").into()
);
};
for (project_name, project_consumption) in consumption.projects {
let Some(project) = projects.get(&project_name) else {
continue;
};
let Ok(user_class) = UserClass::from_u32(project.user_class) else {
continue;
};

for (flavor_name, flavor_consumption) in project_consumption.total {
if flavor_consumption > 0. {
cost.total += calculate_flavor_consumption_cost(
flavor_consumption,
prices.clone(),
user_class.clone(),
flavor_name,
);
}
}
}
}

Ok(cost)
}

// TODO: can we use macros to get rid of the code duplication here
pub async fn calculate_server_cost_for_all_detail(
transaction: &mut Transaction<'_, MySql>,
begin: DateTime<Utc>,
end: DateTime<Utc>,
) -> Result<ServerCostAll, UnexpectedOnlyError> {
todo!()
}

pub async fn calculate_server_cost_for_all(
transaction: &mut Transaction<'_, MySql>,
begin: DateTime<Utc>,
end: DateTime<Utc>,
detail: Option<bool>,
) -> Result<ServerCostForAll, UnexpectedOnlyError> {
todo!()
Ok(match detail {
Some(true) => ServerCostForAll::Detail(
calculate_server_cost_for_all_detail(transaction, begin, end)
.await?,
),
_ => ServerCostForAll::Normal(
calculate_server_cost_for_all_normal(transaction, begin, end)
.await?,
),
})
}

#[derive(Serialize)]
Expand Down

0 comments on commit 3bb6b87

Please sign in to comment.