Add endpoints for working hours

It has an endpoint to show and to delete working hours
This commit is contained in:
Simon Goller 2024-06-27 14:55:05 +02:00
parent d1f6db2104
commit c9e526492c
6 changed files with 201 additions and 14 deletions

View file

@ -0,0 +1,68 @@
{
"db_name": "SQLite",
"query": "SELECT id, sales_person_id, amount, category, description, date_time, created, deleted, update_version FROM extra_hours WHERE id = ?",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Blob"
},
{
"name": "sales_person_id",
"ordinal": 1,
"type_info": "Blob"
},
{
"name": "amount",
"ordinal": 2,
"type_info": "Float"
},
{
"name": "category",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "description",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "date_time",
"ordinal": 5,
"type_info": "Text"
},
{
"name": "created",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "deleted",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "update_version",
"ordinal": 8,
"type_info": "Blob"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
true,
false,
false,
true,
false
]
},
"hash": "1adc3ff219a135b40566e2a0a94ff507b51f6a71163a404e12b2cab65376e187"
}

View file

@ -28,6 +28,7 @@ pub struct ExtraHoursEntity {
#[automock]
#[async_trait]
pub trait ExtraHoursDao {
async fn find_by_id(&self, id: Uuid) -> Result<Option<ExtraHoursEntity>, crate::DaoError>;
async fn find_by_sales_person_id_and_year(
&self,
sales_person_id: Uuid,

View file

@ -69,6 +69,20 @@ impl ExtraHoursDaoImpl {
#[async_trait]
impl ExtraHoursDao for ExtraHoursDaoImpl {
async fn find_by_id(&self, id: Uuid) -> Result<Option<ExtraHoursEntity>, crate::DaoError> {
let id_vec = id.as_bytes().to_vec();
Ok(query_as!(
ExtraHoursDb,
"SELECT id, sales_person_id, amount, category, description, date_time, created, deleted, update_version FROM extra_hours WHERE id = ?",
id_vec,
).fetch_optional(self.pool.as_ref())
.await
.map_db_error()?
.as_ref()
.map(ExtraHoursEntity::try_from)
.transpose()?)
}
async fn find_by_sales_person_id_and_year(
&self,
sales_person_id: Uuid,

View file

@ -1,14 +1,63 @@
use std::rc::Rc;
use axum::{
body::Body, extract::State, response::Response, routing::post, Extension, Json, Router,
body::Body,
extract::{Path, Query, State},
response::Response,
routing::{get, post},
Extension, Json, Router,
};
use rest_types::ExtraHoursTO;
use serde::Deserialize;
use service::extra_hours::ExtraHoursService;
use uuid::Uuid;
use crate::{error_handler, Context, RestStateDef};
pub fn generate_route<RestState: RestStateDef>() -> Router<RestState> {
Router::new().route("/", post(create_extra_hours::<RestState>))
Router::new()
.route("/", post(create_extra_hours::<RestState>))
.route("/:id", post(delete_extra_hours::<RestState>))
.route(
"/by-sales-person/:id",
get(get_extra_hours_for_sales_person::<RestState>),
)
}
#[derive(Clone, Debug, Deserialize)]
pub struct ExtraHoursForSalesPersonAttributes {
year: u32,
until_week: u8,
}
pub async fn get_extra_hours_for_sales_person<RestState: RestStateDef>(
rest_state: State<RestState>,
Extension(context): Extension<Context>,
query: Query<ExtraHoursForSalesPersonAttributes>,
Path(sales_person_id): Path<Uuid>,
) -> Response {
error_handler(
(async {
let extra_hours: Rc<[ExtraHoursTO]> = rest_state
.extra_hours_service()
.find_by_sales_person_id_and_year(
sales_person_id,
query.year,
query.until_week,
context.into(),
)
.await?
.iter()
.map(ExtraHoursTO::from)
.collect();
Ok(Response::builder()
.status(201)
.body(Body::new(serde_json::to_string(&extra_hours).unwrap()))
.unwrap())
})
.await,
)
}
pub async fn create_extra_hours<RestState: RestStateDef>(
@ -25,10 +74,27 @@ pub async fn create_extra_hours<RestState: RestStateDef>(
.await?,
);
Ok(Response::builder()
.status(200)
.status(201)
.body(Body::new(serde_json::to_string(&extra_hours).unwrap()))
.unwrap())
})
.await,
)
}
pub async fn delete_extra_hours<RestState: RestStateDef>(
rest_state: State<RestState>,
Extension(context): Extension<Context>,
Path(extra_hours_id): Path<Uuid>,
) -> Response {
error_handler(
(async {
rest_state
.extra_hours_service()
.delete(extra_hours_id, context.into())
.await?;
Ok(Response::builder().status(204).body(Body::empty()).unwrap())
})
.await,
)
}

View file

@ -107,5 +107,5 @@ pub trait ExtraHoursService {
&self,
id: Uuid,
context: Authentication<Self::Context>,
) -> Result<ExtraHours, ServiceError>;
) -> Result<(), ServiceError>;
}

View file

@ -4,7 +4,7 @@ use async_trait::async_trait;
use dao::extra_hours;
use service::{
extra_hours::ExtraHours,
permission::{Authentication, HR_PRIVILEGE},
permission::{Authentication, HR_PRIVILEGE, SALES_PRIVILEGE},
ServiceError,
};
use tokio::join;
@ -78,12 +78,29 @@ impl<
async fn find_by_sales_person_id_and_year(
&self,
_sales_person_id: Uuid,
_year: u32,
_until_week: u8,
_context: Authentication<Self::Context>,
sales_person_id: Uuid,
year: u32,
until_week: u8,
context: Authentication<Self::Context>,
) -> Result<Arc<[ExtraHours]>, ServiceError> {
unimplemented!()
let (hr_permission, sales_person_permission) = join!(
self.permission_service
.check_permission(HR_PRIVILEGE, context.clone()),
self.sales_person_service
.verify_user_is_sales_person(sales_person_id, context),
);
hr_permission.or(sales_person_permission)?;
let extra_hours_entities = self
.extra_hours_dao
.find_by_sales_person_id_and_year(sales_person_id, year)
.await?;
let extra_hours = extra_hours_entities
.iter()
.filter(|extra_hours| extra_hours.date_time.iso_week() <= until_week)
.map(ExtraHours::from)
.collect::<Vec<ExtraHours>>();
Ok(extra_hours.into())
}
async fn create(
@ -127,11 +144,32 @@ impl<
) -> Result<ExtraHours, ServiceError> {
unimplemented!()
}
async fn delete(
&self,
_id: Uuid,
_context: Authentication<Self::Context>,
) -> Result<ExtraHours, ServiceError> {
unimplemented!()
extra_hours_id: Uuid,
context: Authentication<Self::Context>,
) -> Result<(), ServiceError> {
let (hr_permission, sales_person_permission) = join!(
self.permission_service
.check_permission(HR_PRIVILEGE, context.clone()),
self.permission_service
.check_permission(SALES_PRIVILEGE, context.clone()),
);
hr_permission.or(sales_person_permission)?;
let mut extra_hours_entity = self
.extra_hours_dao
.find_by_id(extra_hours_id)
.await?
.ok_or(ServiceError::EntityNotFound(extra_hours_id))?;
self.sales_person_service
.verify_user_is_sales_person(extra_hours_entity.sales_person_id, context)
.await?;
extra_hours_entity.deleted = Some(self.clock_service.date_time_now());
Ok(())
}
}