feat(signature): Dateinamen-Schema delivery_{Belegnummer}_signature_{role}.png
Unterschrifts-Dateien folgen jetzt dem Schema
delivery_{Belegnummer}_signature_{customer|driver}.png
(z. B. delivery_V-30690287_signature_customer.png) statt zuvor
{delivery_id}_{role}.png.
- SignatureStorage::save nimmt Belegnummer statt delivery_id; Adapter
baut den Dateinamen + saubere Sanitisierung des Belegnummer-Anteils
(Schutz gegen Pfad-Ausbruch, übliche Werte wie V-30690287 bleiben).
- CompleteDeliveryUseCase löst die Belegnummer vor dem Speichern auf.
- Neue Lookup-Methode DeliveryCompletionRepository::belegnummer_for.
- Totes delete_for_delivery (Reconstruktion via delivery_id, keine
Aufrufer mehr seit Cron-Cleanup) entfernt.
Abwärtskompatibel: bestehende Signaturen werden über die in
delivery_completions gespeicherte Referenz geladen, alte Dateinamen
bleiben lesbar. Nur neue Abschlüsse verwenden das neue Schema.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -83,6 +83,16 @@ pub trait DeliveryCompletionRepository: Send + Sync {
|
||||
input: CompleteDeliveryInput,
|
||||
) -> Result<Delivery, ApplicationError>;
|
||||
|
||||
/// Liefert die ERP-Belegnummer einer Lieferung. Der Abschluss-Use-Case
|
||||
/// braucht sie, um die Unterschrifts-Dateien nach dem Schema
|
||||
/// `delivery_{Belegnummer}_signature_{role}.png` zu benennen — also
|
||||
/// *vor* dem eigentlichen `complete`-Aufruf. `NotFound`, wenn die
|
||||
/// Lieferung nicht existiert.
|
||||
async fn belegnummer_for(
|
||||
&self,
|
||||
delivery_id: Uuid,
|
||||
) -> Result<String, ApplicationError>;
|
||||
|
||||
/// Lädt die für das ERP-Rückschreiben nötigen Daten einer **bereits
|
||||
/// abgeschlossenen** Lieferung (Beleg-Key, ausgelieferte Mengen,
|
||||
/// Geld-Gutschrift, Abschluss-Zeitpunkt).
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::error::ApplicationError;
|
||||
|
||||
@ -35,11 +34,13 @@ impl SignatureRole {
|
||||
pub trait SignatureStorage: Send + Sync {
|
||||
/// Speichert eine Unterschrift (PNG-Bytes) für eine Lieferung+Rolle und
|
||||
/// liefert die persistente, relative Referenz (Dateiname) zurück.
|
||||
/// Deterministisch über `delivery_id`+`role` — ein Retry überschreibt
|
||||
/// Deterministisch über `belegnummer`+`role` — der Dateiname folgt dem
|
||||
/// Schema `delivery_{belegnummer}_signature_{role}.png` (z. B.
|
||||
/// `delivery_V-30690287_signature_customer.png`); ein Retry überschreibt
|
||||
/// dieselbe Datei statt Müll anzuhäufen.
|
||||
async fn save(
|
||||
&self,
|
||||
delivery_id: Uuid,
|
||||
belegnummer: &str,
|
||||
role: SignatureRole,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<String, ApplicationError>;
|
||||
@ -49,12 +50,6 @@ pub trait SignatureStorage: Send + Sync {
|
||||
/// Einbetten in den PDF-Report. `None`, wenn die Datei fehlt.
|
||||
async fn load(&self, reference: &str) -> Result<Option<Vec<u8>>, ApplicationError>;
|
||||
|
||||
/// Löscht beide Unterschriften (Kunde + Fahrer) einer Lieferung. Idempotent
|
||||
/// (fehlende Datei = ok). Hinweis: Wird NICHT mehr beim Report-Upload
|
||||
/// aufgerufen — Unterschriften bleiben erhalten und werden per Cron über
|
||||
/// [`delete_older_than`](Self::delete_older_than) nach Frist entfernt.
|
||||
async fn delete_for_delivery(&self, delivery_id: Uuid) -> Result<(), ApplicationError>;
|
||||
|
||||
/// Löscht alle Unterschrifts-Dateien, deren letzte Änderung länger als
|
||||
/// `max_age` zurückliegt (Aufbewahrungsfrist). Für den periodischen
|
||||
/// Cron-Cleanup. Liefert die Anzahl gelöschter Dateien.
|
||||
|
||||
@ -76,13 +76,16 @@ impl CompleteDeliveryUseCase {
|
||||
}
|
||||
|
||||
// --- Signaturen lokal speichern -----------------------------------
|
||||
// Dateiname folgt dem Schema delivery_{Belegnummer}_signature_{role}.png
|
||||
// → Belegnummer der Lieferung auflösen, bevor geschrieben wird.
|
||||
let belegnummer = self.repository.belegnummer_for(delivery_id).await?;
|
||||
let customer_signature_path = self
|
||||
.signatures
|
||||
.save(delivery_id, SignatureRole::Customer, customer_signature_png)
|
||||
.save(&belegnummer, SignatureRole::Customer, customer_signature_png)
|
||||
.await?;
|
||||
let driver_signature_path = self
|
||||
.signatures
|
||||
.save(delivery_id, SignatureRole::Driver, driver_signature_png)
|
||||
.save(&belegnummer, SignatureRole::Driver, driver_signature_png)
|
||||
.await?;
|
||||
|
||||
// --- Atomarer Abschluss im Repository -----------------------------
|
||||
|
||||
Reference in New Issue
Block a user