use std::sync::Arc; use uuid::Uuid; use crate::dto::SyncTourRequest; use crate::error::ApplicationError; use crate::ports::TourRepository; /// Übernimmt eine Tagestour aus dem ERP. Idempotent: wiederholte Aufrufe /// mit gleichem `(driver_personalnummer, tour_date)` aktualisieren die /// bestehende Tour, statt eine neue anzulegen. /// /// Validierung läuft hier in der Application-Schicht — die Repository- /// Schicht darf einen sauberen Datensatz erwarten. pub struct SyncTourUseCase { repository: Arc, } impl SyncTourUseCase { pub fn new(repository: Arc) -> Self { Self { repository } } pub async fn execute(&self, request: SyncTourRequest) -> Result { if request.deliveries.is_empty() { return Err(ApplicationError::Validation( "tour ohne lieferungen abgelehnt".into(), )); } for delivery in &request.deliveries { if delivery.belegnummer.trim().is_empty() { return Err(ApplicationError::Validation( "leere belegnummer".into(), )); } if delivery.items.is_empty() { return Err(ApplicationError::Validation(format!( "lieferung {} ohne positionen", delivery.belegnummer ))); } for item in &delivery.items { if item.required_quantity <= 0 { return Err(ApplicationError::Validation(format!( "lieferung {}, position {}: required_quantity muss > 0 sein", delivery.belegnummer, item.belegzeilen_nr ))); } } } self.repository.upsert_from_sync(&request).await } }