feat(dev): /dev/reset-delivery — einzelne Lieferung per Belegnummer zurücksetzen

Setzt EINE Lieferung zurück, ohne die Tour zu löschen (Alternative zum
destruktiven /dev/resync): Abschluss (delivery_completions), Scan-/
Gutschrift-Audit + offener Report-Job weg, Positionen zurück (scanned/
credited = 0, Status in_progress), Lieferung wieder active (state_reason/
assigned_car/review_* geleert). Notizen/Dienstleistungen/Anhänge bleiben.

Vervollständigt den bisher nur als Port-Stub vorhandenen
reset_delivery_by_belegnummer (Build war dadurch kaputt) + Use Case +
DEV-Route (nur bei dev.sync_enabled gemountet, unauthentifiziert).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-06-24 13:35:45 +02:00
parent fb5f43ed7a
commit 819005eaa5
7 changed files with 173 additions and 2 deletions

View File

@ -55,4 +55,19 @@ pub trait TourRepository: Send + Sync {
/// Dev-Resync, der die Postgres-Daten vor einem frischen Import platt
/// macht. Gibt die Anzahl gelöschter Touren zurück.
async fn delete_all_tours(&self) -> Result<u64, ApplicationError>;
/// **DEV-ONLY**: Setzt eine **einzelne** Lieferung (über ihre ERP-
/// Belegnummer) zurück, ohne die Tour anzufassen — damit man den
/// Auslieferungs-Flow neu durchspielen kann:
/// * Abschluss (`delivery_completions`) gelöscht,
/// * Scan-/Gutschrift-Audit (`scan_audit`, `delivery_credit_audit`) gelöscht,
/// * Positionen zurück (scanned/credited = 0, Status `in_progress`),
/// * Lieferung wieder `active` (state_reason/assigned_car/review_* geleert).
///
/// Notizen, Dienstleistungen und Anhänge bleiben unangetastet. Gibt die
/// Anzahl zurückgesetzter Lieferungen zurück (0 = Belegnummer unbekannt).
async fn reset_delivery_by_belegnummer(
&self,
belegnummer: &str,
) -> Result<u64, ApplicationError>;
}

View File

@ -0,0 +1,32 @@
//! DEV-ONLY: Einzelne Lieferung zurücksetzen (per Belegnummer).
//!
//! Erlaubt, den Auslieferungs-Flow einer Lieferung erneut durchzuspielen,
//! ohne die ganze Tour (`/dev/resync`) zu löschen: Abschluss, Scan-/
//! Gutschrift-Audit und Report-Job weg, Positionen + Lieferung zurück auf
//! `active`. Notizen/Dienstleistungen/Anhänge bleiben unangetastet.
use std::sync::Arc;
use crate::error::ApplicationError;
use crate::ports::TourRepository;
pub struct DevResetDeliveryUseCase {
tours: Arc<dyn TourRepository>,
}
impl DevResetDeliveryUseCase {
pub fn new(tours: Arc<dyn TourRepository>) -> Self {
Self { tours }
}
/// Liefert die Anzahl zurückgesetzter Lieferungen (0 = Belegnummer unbekannt).
pub async fn execute(&self, belegnummer: &str) -> Result<u64, ApplicationError> {
let bn = belegnummer.trim();
if bn.is_empty() {
return Err(ApplicationError::Validation(
"belegnummer darf nicht leer sein".into(),
));
}
self.tours.reset_delivery_by_belegnummer(bn).await
}
}

View File

@ -12,6 +12,7 @@ pub mod cars;
pub mod complete_delivery;
pub mod create_delivery_note;
pub mod delete_delivery_note;
pub mod dev_reset_delivery;
pub mod dev_resync_tours;
pub mod generate_delivery_report;
pub mod get_account;
@ -39,6 +40,7 @@ pub use cars::{
};
pub use complete_delivery::CompleteDeliveryUseCase;
pub use create_delivery_note::CreateDeliveryNoteUseCase;
pub use dev_reset_delivery::DevResetDeliveryUseCase;
pub use dev_resync_tours::DevResyncToursUseCase;
pub use generate_delivery_report::GenerateDeliveryReportUseCase;
pub use delete_delivery_note::DeleteDeliveryNoteUseCase;