feat(admin): GET /admin/belege/{belegnummer}/positions-modified

Neuer Admin-Endpunkt, der zu EINER ERP-Belegnummer das positions_modified-Flag
liefert (Stück-Gutschrift auf einer Belegzeile ODER aktive Geld-Gutschrift) —
gleiche Definition wie in completed-deliveries, aber pro Beleg und ohne
Abschluss-Voraussetzung. 404 bei unbekannter Belegnummer; bei mehreren
Lieferungen gleicher Belegnummer true, sobald eine verändert ist (bool_or).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-07-09 21:32:04 +02:00
parent 6378b1101b
commit 865fcfcd23
8 changed files with 146 additions and 2 deletions

View File

@ -530,6 +530,44 @@ impl DeliveryCompletionRepository for PgDeliveryCompletionRepository {
.collect())
}
async fn positions_modified_for_belegnummer(
&self,
belegnummer: &str,
) -> Result<Option<bool>, ApplicationError> {
// `positions_modified`-Logik identisch zu list_completed_deliveries,
// aber pro Belegnummer und ohne Abschluss-Join. `bool_or` aggregiert
// über evtl. mehrere Lieferungen gleicher Belegnummer (true, sobald eine
// verändert ist) und liefert NULL, wenn es die Belegnummer nicht gibt
// ⇒ das mappt sqlx auf `None` (⇒ 404 im Handler).
let modified: Option<bool> = sqlx::query_scalar(
r#"
SELECT bool_or(
EXISTS (
SELECT 1 FROM delivery_items di
WHERE di.delivery_id = d.id
AND di.credited_quantity > 0
)
OR COALESCE(
( SELECT dca.action
FROM delivery_credit_audit dca
WHERE dca.delivery_id = d.id
ORDER BY dca.recorded_at DESC, dca.id DESC
LIMIT 1 ) = 'set',
false
)
)
FROM deliveries d
WHERE d.erp_belegnummer = $1
"#,
)
.bind(belegnummer)
.fetch_one(&self.pool)
.await
.map_err(db)?;
Ok(modified)
}
async fn mark_mail_sent(
&self,
belegnummern: &[String],