use async_trait::async_trait; use service::{ booking::{Booking, BookingService}, ServiceError, ValidationFailureItem, }; use std::sync::Arc; use uuid::Uuid; const BOOKING_SERVICE_PROCESS: &str = "booking-service"; pub struct BookingServiceImpl< BookingDao, PermissionService, ClockService, UuidService, SalesPersonService, SlotService, > where BookingDao: dao::booking::BookingDao + Send + Sync, PermissionService: service::permission::PermissionService + Send + Sync, UuidService: service::uuid_service::UuidService + Send + Sync, ClockService: service::clock::ClockService + Send + Sync, SalesPersonService: service::sales_person::SalesPersonService + Send + Sync, SlotService: service::slot::SlotService + Send + Sync, { pub booking_dao: Arc, pub permission_service: Arc, pub clock_service: Arc, pub uuid_service: Arc, pub sales_person_service: Arc, pub slot_service: Arc, } impl BookingServiceImpl< BookingDao, PermissionService, ClockService, UuidService, SalesPersonService, SlotService, > where BookingDao: dao::booking::BookingDao + Send + Sync, PermissionService: service::permission::PermissionService + Send + Sync, UuidService: service::uuid_service::UuidService + Send + Sync, ClockService: service::clock::ClockService + Send + Sync, SalesPersonService: service::sales_person::SalesPersonService + Send + Sync, SlotService: service::slot::SlotService + Send + Sync, { pub fn new( booking_dao: Arc, permission_service: Arc, clock_service: Arc, uuid_service: Arc, sales_person_service: Arc, slot_service: Arc, ) -> Self { Self { booking_dao, permission_service, clock_service, uuid_service, sales_person_service, slot_service, } } } #[async_trait] impl BookingService for BookingServiceImpl< BookingDao, PermissionService, ClockService, UuidService, SalesPersonService, SlotService, > where BookingDao: dao::booking::BookingDao + Send + Sync, PermissionService: service::permission::PermissionService + Send + Sync, UuidService: service::uuid_service::UuidService + Send + Sync, ClockService: service::clock::ClockService + Send + Sync, SalesPersonService: service::sales_person::SalesPersonService + Send + Sync, SlotService: service::slot::SlotService + Send + Sync, { type Context = PermissionService::Context; async fn get_all(&self, context: Self::Context) -> Result, ServiceError> { self.permission_service .check_permission("hr", context) .await?; Ok(self .booking_dao .all() .await? .iter() .map(Booking::from) .collect()) } async fn get(&self, id: Uuid, context: Self::Context) -> Result { self.permission_service .check_permission("hr", context) .await?; let booking_entity = self.booking_dao.find_by_id(id).await?; let booking = booking_entity .as_ref() .map(Booking::from) .ok_or_else(move || ServiceError::EntityNotFound(id))?; Ok(booking) } async fn create( &self, booking: &Booking, context: Self::Context, ) -> Result { self.permission_service .check_permission("hr", context.clone()) .await?; if booking.id != Uuid::nil() { return Err(ServiceError::IdSetOnCreate); } if booking.version != Uuid::nil() { return Err(ServiceError::VersionSetOnCreate); } let mut validation = Vec::with_capacity(8); if booking.created.is_some() { validation.push(ValidationFailureItem::InvalidValue("created".into())); } if booking.sales_person_id == Uuid::nil() { validation.push(ValidationFailureItem::InvalidValue( "sales_person_id".into(), )); } if booking.slot_id == Uuid::nil() { validation.push(ValidationFailureItem::InvalidValue("slot_id".into())); } if booking.calendar_week <= 0 { validation.push(ValidationFailureItem::InvalidValue("calendar_week".into())); } if booking.calendar_week > 53 { validation.push(ValidationFailureItem::InvalidValue("calendar_week".into())); } if self .sales_person_service .exists(booking.sales_person_id, context.clone()) .await? == false { validation.push(ValidationFailureItem::IdDoesNotExist( "sales_person_id".into(), booking.sales_person_id, )); } if self .slot_service .exists(booking.slot_id, context.clone()) .await? == false { validation.push(ValidationFailureItem::IdDoesNotExist( "slot_id".into(), booking.slot_id, )); } if !validation.is_empty() { return Err(ServiceError::ValidationError(validation.into())); } let new_id = self.uuid_service.new_uuid("booking-id"); let new_version = self.uuid_service.new_uuid("booking-version"); let new_booking = Booking { id: new_id, version: new_version, created: Some(self.clock_service.date_time_now()), ..booking.clone() }; self.booking_dao .create(&(&new_booking).try_into()?, BOOKING_SERVICE_PROCESS) .await?; Ok(new_booking) } async fn delete(&self, id: Uuid, context: Self::Context) -> Result<(), ServiceError> { self.permission_service .check_permission("hr", context) .await?; let mut booking_entity = self .booking_dao .find_by_id(id) .await? .ok_or_else(move || ServiceError::EntityNotFound(id))?; booking_entity.deleted = Some(self.clock_service.date_time_now()); booking_entity.version = self.uuid_service.new_uuid("booking-version"); self.booking_dao .update(&booking_entity, BOOKING_SERVICE_PROCESS) .await?; Ok(()) } }