feat(admin): GET /admin/completed-deliveries — abgeschlossene Lieferungen eines Tages

Neuer Admin-Endpunkt, der ALLE an einem Tag (Berliner Kalendertag von
completed_at) abgeschlossenen Lieferungen liefert — unabhängig vom
Mail-Versand-Status. Pro Lieferung: Belegnummer und ein Flag
`positions_modified`, das true ist, wenn eine Belegzeile in der Menge
reduziert/entfernt wurde (delivery_items.credited_quantity > 0) oder eine
aktive Geld-Gutschrift vorliegt (jüngstes delivery_credit_audit-Event 'set').

Pflichtparameter `day` (DD-MM-YYYY). Geschützt per admin_api_key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-07-09 16:06:01 +02:00
parent 819005eaa5
commit 748df577ef
9 changed files with 206 additions and 4 deletions

View File

@ -43,6 +43,17 @@ pub struct ErpWritebackData {
pub payment_method_code: Option<String>,
}
/// Zusammenfassung einer abgeschlossenen Lieferung für den Admin-Tagesabruf.
/// Belegnummer plus ein Flag, ob an der Lieferung Positionen verändert wurden.
pub struct CompletedDeliverySummary {
pub belegnummer: String,
/// `true`, wenn an der Lieferung fachlich etwas von der ursprünglichen
/// Bestellung abweicht: eine Position wurde ganz entfernt oder in der Menge
/// reduziert (`delivery_items.credited_quantity > 0`) **oder** es liegt eine
/// aktive Geld-Gutschrift vor (jüngstes `delivery_credit_audit`-Event `set`).
pub positions_modified: bool,
}
/// Vollständige Eingabe für den Abschluss — alles, was die Abschluss-Zeile
/// braucht plus die fachlichen Bestätigungs-Flags fürs Gate.
pub struct CompleteDeliveryInput {
@ -121,6 +132,18 @@ pub trait DeliveryCompletionRepository: Send + Sync {
day: Option<NaiveDate>,
) -> Result<Vec<String>, ApplicationError>;
/// Liefert alle **abgeschlossenen** (ausgelieferten) Lieferungen, deren
/// Abschluss-Zeitpunkt (`completed_at`) auf den Berliner Kalendertag `day`
/// fällt — unabhängig vom Mail-Versand-Status. Pro Lieferung Belegnummer
/// und das `positions_modified`-Flag (siehe [`CompletedDeliverySummary`]).
///
/// `completed_at` ist ein UTC-Zeitstempel; der Kalendertag wird in
/// **Europe/Berlin** bestimmt. Sortierung: aufsteigend nach Abschluss-Zeit.
async fn list_completed_deliveries_for_day(
&self,
day: NaiveDate,
) -> Result<Vec<CompletedDeliverySummary>, ApplicationError>;
/// Markiert die Liefermail der angegebenen Belegnummern als **versendet**
/// (`mail_sent_at = now()`), aber nur dort, wo sie noch offen ist
/// (`mail_sent_at IS NULL`) — bereits markierte bleiben unverändert

View File

@ -51,7 +51,8 @@ pub use delivery_service_repository::DeliveryServiceRepository;
pub use docuframe_report_gateway::DocuframeReportGateway;
pub use driver_identity_provisioner::{DriverIdentityProvisioner, ProvisionOutcome};
pub use delivery_completion_repository::{
CompleteDeliveryInput, DeliveryCompletionRepository, ErpWritebackData, ErpWritebackLine,
CompleteDeliveryInput, CompletedDeliverySummary, DeliveryCompletionRepository, ErpWritebackData,
ErpWritebackLine,
};
pub use erp_delivery_source::ErpDeliverySource;
pub use erp_delivery_writeback::{

View File

@ -0,0 +1,33 @@
//! Use Case: abgeschlossene (ausgelieferte) Lieferungen eines Tages auflisten.
//!
//! Reine Lese-Operation für den Admin-Endpunkt. Im Gegensatz zu
//! [`crate::usecases::ListDeliveredBelegnummernUseCase`] (Mailclient-Sicht,
//! nur noch nicht versendete Belege) liefert dieser Use Case **alle**
//! Abschlüsse des Tages — unabhängig vom Mail-Status — samt einem Flag, ob an
//! der Lieferung Positionen verändert wurden (Menge reduziert/entfernt oder
//! Geld-Gutschrift). Tages-/TZ-Logik liegt im Repository (Europe/Berlin).
use std::sync::Arc;
use chrono::NaiveDate;
use crate::error::ApplicationError;
use crate::ports::{CompletedDeliverySummary, DeliveryCompletionRepository};
pub struct ListCompletedDeliveriesUseCase {
completions: Arc<dyn DeliveryCompletionRepository>,
}
impl ListCompletedDeliveriesUseCase {
pub fn new(completions: Arc<dyn DeliveryCompletionRepository>) -> Self {
Self { completions }
}
/// Liefert alle am `day` (Berliner Kalendertag) abgeschlossenen Lieferungen.
pub async fn execute(
&self,
day: NaiveDate,
) -> Result<Vec<CompletedDeliverySummary>, ApplicationError> {
self.completions.list_completed_deliveries_for_day(day).await
}
}

View File

@ -19,6 +19,7 @@ pub mod get_account;
pub mod get_attachment_preview;
pub mod get_tour;
pub mod import_erp_tours;
pub mod list_completed_deliveries;
pub mod list_delivered_belegnummern;
pub mod list_my_tours_today;
pub mod mark_mail_sent;
@ -48,6 +49,7 @@ pub use get_account::GetAccountUseCase;
pub use get_attachment_preview::GetAttachmentPreviewUseCase;
pub use get_tour::GetTourUseCase;
pub use import_erp_tours::{ImportErpToursUseCase, ImportSummary};
pub use list_completed_deliveries::ListCompletedDeliveriesUseCase;
pub use list_delivered_belegnummern::ListDeliveredBelegnummernUseCase;
pub use list_my_tours_today::ListMyToursTodayUseCase;
pub use mark_mail_sent::MarkMailSentUseCase;