feat(abschluss): interne Notiz des Fahrers beim Abschluss

- CompleteDeliveryAcknowledgements.internalNote (optional, getrimmt,
  max. 2000 Zeichen) wird atomar mit dem Abschluss gespeichert
  (delivery_completions.internal_note)
- Bewusst keine delivery_notes-Zeile: loest weder die Kunden-Bestaetigung
  der Notizen aus noch erscheint sie im Notizen-Step der App
- Lieferbericht: eigener Abschnitt "Interne Notiz" mit Zeitpunkt und Fahrer
- Bericht: Betrag in "Betrag erhalten" ans Zeilenende (Helvetica setzt nach
  dem Euro-Zeichen zu eng)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-25 14:41:05 +02:00
parent caaf88ac3d
commit 695ac39c19
9 changed files with 81 additions and 5 deletions

View File

@ -295,8 +295,8 @@ impl DeliveryCompletionRepository for PgDeliveryCompletionRepository {
delivery_id, customer_signature_path, driver_signature_path,
receipt_confirmed, notes_acknowledged, acknowledged_note_ids,
completed_by_personalnummer, completed_by_car_id,
payment_collected, collected_amount_cents, payment_id
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
payment_collected, collected_amount_cents, payment_id, internal_note
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
"#,
)
.bind(delivery_id)
@ -310,6 +310,7 @@ impl DeliveryCompletionRepository for PgDeliveryCompletionRepository {
.bind(requires_collection && collected)
.bind(collected_amount_cents)
.bind(logged_payment_id)
.bind(input.internal_note.as_deref())
.execute(&mut *tx)
.await
.map_err(db)?;

View File

@ -568,7 +568,7 @@ impl DeliveryReportRenderer for PdfDeliveryReportRenderer {
if let Some(collected) = c.collected_amount_cents {
p.kv(
"Betrag erhalten",
&format!("Ja — {} (am {})", cents(collected), dt(self.tz, &c.completed_at)),
&format!("Ja, am {} — {}", dt(self.tz, &c.completed_at), cents(collected)),
);
}
}
@ -620,6 +620,30 @@ impl DeliveryReportRenderer for PdfDeliveryReportRenderer {
}
}
// 6b. Interne Notiz des Fahrers (nach den Unterschriften erfasst,
// nicht Teil der Kunden-Bestätigung).
p.heading("Interne Notiz");
match d
.completion
.as_ref()
.and_then(|c| c.internal_note.as_deref().map(|n| (c, n)))
{
Some((c, note)) => {
p.text(
&format!(
"{} · Fahrer {}",
dt(self.tz, &c.completed_at),
c.completed_by_personalnummer
),
8.0,
true,
0.0,
);
p.text(note, 9.0, false, 4.0);
}
None => p.text("— keine —", 9.0, false, 0.0),
}
// 7. Unterschriften
p.heading("Unterschriften");
match &d.completion {

View File

@ -104,6 +104,7 @@ struct CompletionRow {
payment_collected: bool,
collected_amount_cents: Option<i64>,
payment_id: Option<Uuid>,
internal_note: Option<String>,
}
#[derive(sqlx::FromRow)]
@ -289,7 +290,7 @@ impl DeliveryReportRepository for PgDeliveryReportRepository {
r#"
SELECT completed_at, completed_by_personalnummer, receipt_confirmed,
notes_acknowledged, customer_signature_path, driver_signature_path,
payment_collected, collected_amount_cents, payment_id
payment_collected, collected_amount_cents, payment_id, internal_note
FROM delivery_completions
WHERE delivery_id = $1
"#,
@ -466,6 +467,7 @@ impl DeliveryReportRepository for PgDeliveryReportRepository {
payment_collected: c.payment_collected,
collected_amount_cents: c.collected_amount_cents,
payment_id: c.payment_id,
internal_note: c.internal_note,
}),
scan_audit: scan_audit
.into_iter()