Add basic employee hour balance report

This commit is contained in:
Simon Goller 2024-06-23 18:12:54 +02:00
parent 0eb885216a
commit d4adcb182f
31 changed files with 2155 additions and 5 deletions

View file

@ -2,8 +2,10 @@ use std::{convert::Infallible, sync::Arc};
mod booking;
mod permission;
mod report;
mod sales_person;
mod slot;
mod working_hours;
#[cfg(feature = "oidc")]
use axum::error_handling::HandleErrorLayer;
@ -199,6 +201,12 @@ fn error_handler(result: Result<Response, RestError>) -> Response {
.body(Body::new(err.to_string()))
.unwrap()
}
Err(RestError::ServiceError(err @ service::ServiceError::TimeComponentRangeError(_))) => {
Response::builder()
.status(500)
.body(Body::new(err.to_string()))
.unwrap()
}
Err(RestError::ServiceError(ServiceError::InternalError)) => Response::builder()
.status(500)
.body(Body::new("Internal server error".to_string()))
@ -215,12 +223,22 @@ pub trait RestStateDef: Clone + Send + Sync + 'static {
+ Sync
+ 'static;
type BookingService: service::booking::BookingService<Context = Context> + Send + Sync + 'static;
type ReportingService: service::reporting::ReportingService<Context = Context>
+ Send
+ Sync
+ 'static;
type WorkingHoursService: service::working_hours::WorkingHoursService<Context = Context>
+ Send
+ Sync
+ 'static;
fn user_service(&self) -> Arc<Self::UserService>;
fn permission_service(&self) -> Arc<Self::PermissionService>;
fn slot_service(&self) -> Arc<Self::SlotService>;
fn sales_person_service(&self) -> Arc<Self::SalesPersonService>;
fn booking_service(&self) -> Arc<Self::BookingService>;
fn reporting_service(&self) -> Arc<Self::ReportingService>;
fn working_hours_service(&self) -> Arc<Self::WorkingHoursService>;
}
pub struct OidcConfig {
@ -324,6 +342,8 @@ pub async fn start_server<RestState: RestStateDef>(rest_state: RestState) {
.nest("/slot", slot::generate_route())
.nest("/sales-person", sales_person::generate_route())
.nest("/booking", booking::generate_route())
.nest("/report", report::generate_route())
.nest("/working-hours", working_hours::generate_route())
.with_state(rest_state)
.layer(middleware::from_fn(context_extractor));

77
rest/src/report.rs Normal file
View file

@ -0,0 +1,77 @@
use std::sync::Arc;
use axum::{
body::Body,
extract::{Path, Query, State},
response::Response,
routing::get,
Extension, Router,
};
use rest_types::{EmployeeReportTO, ShortEmployeeReportTO};
use serde::Deserialize;
use service::reporting::ReportingService;
use uuid::Uuid;
use crate::{error_handler, Context, RestStateDef};
pub fn generate_route<RestState: RestStateDef>() -> Router<RestState> {
Router::new()
.route("/", get(get_short_report_for_all::<RestState>))
.route("/:id", get(get_report::<RestState>))
}
#[derive(Clone, Debug, Deserialize)]
pub struct ReportRequest {
year: u32,
until_week: u8,
}
pub async fn get_short_report_for_all<RestState: RestStateDef>(
rest_state: State<RestState>,
query: Query<ReportRequest>,
Extension(context): Extension<Context>,
) -> Response {
error_handler(
(async {
let short_report: Arc<[ShortEmployeeReportTO]> = rest_state
.reporting_service()
.get_reports_for_all_employees(query.year, query.until_week, context.into())
.await?
.iter()
.map(ShortEmployeeReportTO::from)
.collect();
Ok(Response::builder()
.status(200)
.body(Body::new(serde_json::to_string(&short_report).unwrap()))
.unwrap())
})
.await,
)
}
pub async fn get_report<RestState: RestStateDef>(
rest_state: State<RestState>,
query: Query<ReportRequest>,
Path(sales_person_id): Path<Uuid>,
Extension(context): Extension<Context>,
) -> Response {
error_handler(
(async {
let report: EmployeeReportTO = (&rest_state
.reporting_service()
.get_report_for_employee(
&sales_person_id,
query.year,
query.until_week,
context.into(),
)
.await?)
.into();
Ok(Response::builder()
.status(200)
.body(Body::new(serde_json::to_string(&report).unwrap()))
.unwrap())
})
.await,
)
}

34
rest/src/working_hours.rs Normal file
View file

@ -0,0 +1,34 @@
use axum::{
body::Body, extract::State, response::Response, routing::post, Extension, Json, Router,
};
use rest_types::WorkingHoursTO;
use service::working_hours::WorkingHoursService;
use crate::{error_handler, Context, RestStateDef};
pub fn generate_route<RestState: RestStateDef>() -> Router<RestState> {
Router::new().route("/", post(create_working_hours::<RestState>))
}
pub async fn create_working_hours<RestState: RestStateDef>(
rest_state: State<RestState>,
Extension(context): Extension<Context>,
Json(working_hours): Json<WorkingHoursTO>,
) -> Response {
error_handler(
(async {
let working_hours = WorkingHoursTO::from(
&rest_state
.working_hours_service()
.create(&(&working_hours).into(), context.into())
.await?,
);
Ok(Response::builder()
.status(200)
.body(Body::new(serde_json::to_string(&working_hours).unwrap()))
.unwrap())
})
.await,
)
}