diff --git a/crates/infrastructure/src/report/renderer.rs b/crates/infrastructure/src/report/renderer.rs index 6a7b44a..f05b149 100644 --- a/crates/infrastructure/src/report/renderer.rs +++ b/crates/infrastructure/src/report/renderer.rs @@ -399,6 +399,22 @@ fn scan_action_de(s: &str) -> &str { } /// Deutsche Beschriftung der Gutschriftaktion. +/// Begründung, warum ohne offenen Betrag nichts abzuwickeln war. +/// Anzahlung deckt den Warenwert ⇒ bei Bestellung bezahlt; sonst hat eine +/// Gutschrift (ggf. zusammen mit der Anzahlung) den Rest ausgeglichen. +fn settled_without_payment(warenwert: f64, prepaid: f64, credit: f64) -> &'static str { + const EPS: f64 = 0.005; + if warenwert < EPS { + "Nicht erforderlich, kein Warenwert" + } else if prepaid + EPS >= warenwert { + "Nicht erforderlich, bereits bei Bestellung bezahlt" + } else if prepaid >= EPS && credit >= EPS { + "Nicht erforderlich, durch Anzahlung und Gutschrift ausgeglichen" + } else { + "Nicht erforderlich, durch Gutschrift ausgeglichen" + } +} + /// Bar/EC = vor Ort kassiert; alles andere (Rechnung) bleibt offen. fn is_collected_on_site(code: &str) -> bool { code == "cash" || code == "ec_card" @@ -563,6 +579,13 @@ impl DeliveryReportRenderer for PdfDeliveryReportRenderer { p.kv("Zahlbetrag", ¢s(pay.amount_cents)); p.kv("Abgewickelt am", &dt(self.tz, &pay.recorded_at)); p.kv("Erfasst von", &payment_actor(pay)); + } else if open < 0.005 { + // Nichts offen ⇒ nichts abzuwickeln. Grund nennen, damit die + // Zahlungsmethode vom Beleg (z. B. „Bar") nicht als kassiert gilt. + p.kv( + "Zahlungsabwicklung", + settled_without_payment(warenwert, d.prepaid_amount, credit), + ); } else if let Some(c) = &d.completion { // Abschluss ohne Zahlungs-Step (ältere App): nur das Inkasso-Flag. if let Some(collected) = c.collected_amount_cents { @@ -820,3 +843,41 @@ impl DeliveryReportRenderer for PdfDeliveryReportRenderer { p.finish() } } + +#[cfg(test)] +mod settled_without_payment_tests { + use super::settled_without_payment; + + #[test] + fn anzahlung_deckt_warenwert() { + assert_eq!( + settled_without_payment(688.0, 688.0, 0.0), + "Nicht erforderlich, bereits bei Bestellung bezahlt" + ); + // Überzahlt zählt ebenfalls als bei Bestellung bezahlt. + assert_eq!( + settled_without_payment(838.0, 938.0, 0.0), + "Nicht erforderlich, bereits bei Bestellung bezahlt" + ); + } + + #[test] + fn gutschrift_gleicht_rest_aus() { + assert_eq!( + settled_without_payment(100.0, 80.0, 20.0), + "Nicht erforderlich, durch Anzahlung und Gutschrift ausgeglichen" + ); + assert_eq!( + settled_without_payment(100.0, 0.0, 100.0), + "Nicht erforderlich, durch Gutschrift ausgeglichen" + ); + } + + #[test] + fn ohne_warenwert() { + assert_eq!( + settled_without_payment(0.0, 0.0, 0.0), + "Nicht erforderlich, kein Warenwert" + ); + } +}