use domain::{ entities::Job, errors::DomainError, events::DomainEvent, ports::{EventPublisher, JobBatchRepository, JobRepository}, value_objects::{DateTimeStamp, StructuredData, SystemId}, }; use std::sync::Arc; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct CompleteJobCommand { pub job_id: SystemId, pub result: StructuredData, } pub struct CompleteJobHandler { job_repo: Arc, batch_repo: Arc, event_pub: Arc, } impl CompleteJobHandler { pub fn new( job_repo: Arc, batch_repo: Arc, event_pub: Arc, ) -> Self { Self { job_repo, batch_repo, event_pub, } } pub async fn execute(&self, cmd: CompleteJobCommand) -> Result { let mut job = self .job_repo .find_by_id(&cmd.job_id) .await? .ok_or_else(|| DomainError::NotFound(format!("Job {} not found", cmd.job_id)))?; job.complete(cmd.result); self.job_repo.save(&job).await?; if let Some(ref batch_id) = job.batch_id { let mut batch = self.batch_repo.find_by_id(batch_id).await?.ok_or_else(|| { DomainError::NotFound(format!("Batch {} not found", batch_id)) })?; batch.record_completion(); self.batch_repo.save(&batch).await?; } self.event_pub .publish(DomainEvent::JobCompleted { job_id: job.job_id, timestamp: DateTimeStamp::now(), }) .await?; Ok(job) } }