feat(report): bei offenem Betrag 0 den Grund nennen ("bei Bestellung bezahlt")

Ohne offenen Betrag gab es im Abschnitt "Zahlung" keine Aussage zur
Abwicklung, nur die Zahlungsmethode vom Beleg (z. B. "Bar"). Jetzt steht
dort "Zahlungsabwicklung: Nicht erforderlich, ..." mit Begruendung:
bereits bei Bestellung bezahlt, durch Anzahlung und Gutschrift oder nur
durch Gutschrift ausgeglichen, bzw. kein Warenwert. Unit-Tests dazu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-25 15:25:13 +02:00
parent 695ac39c19
commit 7cb054cf6c

View File

@ -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", &cents(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"
);
}
}