Fix+Polish: Phosphor-Icons Danke-Overlay, Quartalsbericht paid_amount
Giftköder Danke-Overlay (poison.js): - Emoji 🚨/🐾/📡 durch Phosphor-Icons ersetzt: siren, paw-print, wifi-slash Quartalsbericht (invoices.py + admin.js): - Backend: _effective_gross() — für bezahlte Rechnungen wird paid_amount statt amount_gross für die Quartalssumme verwendet (Kulanz/Teilzahlung korrekt) - Admin-Preview: effectiveAmt in der Vorschau-Tabelle, bei Abweichung Hinweis "(RG: xx,xx €)" für Nachvollziehbarkeit - CSV: Spalte "Betrag (eingegangen)" + separate Spalte "Rechnungsbetrag" - SW by-v995, APP_VER 995
This commit is contained in:
parent
57192ea010
commit
c59326af17
6 changed files with 32 additions and 17 deletions
|
|
@ -4415,17 +4415,19 @@ window.Page_admin = (() => {
|
|||
const escape = v => `"${String(v || '').replace(/"/g, '""')}"`;
|
||||
|
||||
const statusLabel = { paid: 'Bezahlt', sent: 'Versendet', cancelled: 'Storniert (Original)', storno: 'Stornorechnung' };
|
||||
const header = 'Nummer;Empfaenger;E-Mail;Datum;Leistungszeitraum;Betrag;Eingegangener Betrag;Status;Versendet am;Zahlungseingang\n';
|
||||
const csvRows = data.invoices.map(inv => [
|
||||
const header = 'Nummer;Empfaenger;E-Mail;Datum;Leistungszeitraum;Betrag (eingegangen);Rechnungsbetrag;Status;Versendet am;Zahlungseingang\n';
|
||||
const csvRows = data.invoices.map(inv => {
|
||||
const effectiveAmt = (inv.status === 'paid' && inv.paid_amount != null) ? inv.paid_amount : inv.amount_gross;
|
||||
return [
|
||||
inv.invoice_number,
|
||||
inv.recipient_name, inv.recipient_email || '',
|
||||
fmtDate(inv.created_at), inv.service_period || '',
|
||||
fmtEur(effectiveAmt),
|
||||
fmtEur(inv.amount_gross),
|
||||
inv.paid_amount != null ? fmtEur(inv.paid_amount) : '',
|
||||
statusLabel[inv.status] || inv.status,
|
||||
fmtDate(inv.sent_at), fmtDate(inv.paid_at)
|
||||
].map(escape).join(';')
|
||||
).join('\n');
|
||||
].map(escape).join(';');
|
||||
}).join('\n');
|
||||
|
||||
const blob = new Blob(['' + header + csvRows], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
|
@ -4457,12 +4459,15 @@ window.Page_admin = (() => {
|
|||
const sL = { draft:'Entwurf', sent:'Versendet', paid:'Bezahlt', cancelled:'Storniert (Orig.)', storno:'Stornorechnung' };
|
||||
const rows2 = data.invoices.map((inv, i) => {
|
||||
const isStorno = inv.status === 'storno';
|
||||
const amtColor = isStorno ? 'color:var(--c-danger)' : (inv.amount_gross < 0 ? 'color:var(--c-danger)' : '');
|
||||
const effectiveAmt = (inv.status === 'paid' && inv.paid_amount != null) ? inv.paid_amount : inv.amount_gross;
|
||||
const amtColor = isStorno ? 'color:var(--c-danger)' : (effectiveAmt < 0 ? 'color:var(--c-danger)' : '');
|
||||
const amtNote = (inv.status === 'paid' && inv.paid_amount != null && Math.abs(inv.paid_amount - inv.amount_gross) >= 0.01)
|
||||
? ` <span style="font-size:var(--text-xs);color:var(--c-text-muted)">(RG: ${_fmtE(inv.amount_gross)})</span>` : '';
|
||||
return `
|
||||
<tr style="${i%2===1?'background:var(--c-surface-2)':''}">
|
||||
<td class="adm-td" style="font-family:monospace;font-size:var(--text-xs);${isStorno?'color:var(--c-danger)':''}">${_esc(inv.invoice_number)}</td>
|
||||
<td class="adm-td">${_esc(inv.recipient_name)}</td>
|
||||
<td class="adm-td" style="text-align:right;font-weight:600;${amtColor}">${_fmtE(inv.amount_gross)}</td>
|
||||
<td class="adm-td" style="text-align:right;font-weight:600;${amtColor}">${_fmtE(effectiveAmt)}${amtNote}</td>
|
||||
<td class="adm-td" style="${isStorno?'color:var(--c-danger)':''}">${sL[inv.status]||inv.status}</td>
|
||||
<td class="adm-td" style="font-size:var(--text-xs);color:var(--c-text-muted)">${_fmtD(inv.created_at)}</td>
|
||||
</tr>`;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue