Feat: Entwurf bearbeiten (PATCH), erneut senden; SW by-v968

This commit is contained in:
rene 2026-05-15 11:33:48 +02:00
parent a2d089bce4
commit b14a251bdc
5 changed files with 96 additions and 11 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '967'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '968'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';
// Cache-Bust-Parameter nach Update-Reload sofort entfernen

View file

@ -3726,10 +3726,19 @@ window.Page_admin = (() => {
const rows = invoices.map((inv, i) => {
const actions = [];
if (inv.status === 'draft') {
actions.push(`<button class="btn btn-sm btn-ghost adm-inv-edit" data-id="${inv.id}" title="Bearbeiten">
${UI.icon('pencil')} Bearbeiten
</button>`);
actions.push(`<button class="btn btn-sm btn-primary adm-inv-send" data-id="${inv.id}" data-num="${_esc(inv.invoice_number)}" title="Senden">
${UI.icon('paper-plane-tilt')} Senden
</button>`);
}
if (inv.status === 'sent') {
actions.push(`<button class="btn btn-sm btn-ghost adm-inv-send" data-id="${inv.id}" data-num="${_esc(inv.invoice_number)}" title="Erneut senden"
style="color:var(--c-text-muted)">
${UI.icon('paper-plane-tilt')} Erneut senden
</button>`);
}
if (inv.status === 'sent') {
actions.push(`<button class="btn btn-sm btn-secondary adm-inv-pay" data-id="${inv.id}" data-amount="${inv.amount_gross}" title="Als bezahlt markieren">
${UI.icon('check-circle')} Bezahlt
@ -3808,6 +3817,22 @@ window.Page_admin = (() => {
});
});
// Entwurf bearbeiten
el.querySelectorAll('.adm-inv-edit').forEach(btn => {
btn.addEventListener('click', async () => {
const inv = await API.get(`/admin/invoices/${btn.dataset.id}`);
_openNeueRechnungModal(reload, {
recipient_name: inv.recipient_name,
recipient_email: inv.recipient_email,
recipient_address: inv.recipient_address || '',
service_period: inv.service_period || '',
discount_pct: inv.discount_pct || 0,
notes: inv.notes || '',
items: inv.items.map(it => ({ description: it.description, quantity: it.quantity, unit_price: it.unit_price })),
}, inv.id);
});
});
// Als bezahlt markieren
el.querySelectorAll('.adm-inv-pay').forEach(btn => {
btn.addEventListener('click', () => _openBezahltModal(btn.dataset.id, Number(btn.dataset.amount), reload));
@ -3824,12 +3849,13 @@ window.Page_admin = (() => {
});
}
function _openNeueRechnungModal(reload, prefill = null) {
const id = `inv-new-${Date.now()}`;
const p = prefill || {};
function _openNeueRechnungModal(reload, prefill = null, invoiceId = null) {
const id = `inv-new-${Date.now()}`;
const p = prefill || {};
const isEdit = !!invoiceId;
UI.modal.open({
title: `${UI.icon('receipt')} Neue Rechnung erstellen`,
title: `${UI.icon('receipt')} ${isEdit ? 'Rechnung bearbeiten' : 'Neue Rechnung erstellen'}`,
body: `
<form id="${id}" style="display:flex;flex-direction:column;gap:var(--space-3)">
@ -3904,7 +3930,7 @@ window.Page_admin = (() => {
`,
footer: `
<button class="btn btn-secondary" data-modal-close>Abbrechen</button>
<button class="btn btn-primary" form="${id}" type="submit">${UI.icon('receipt')} Rechnung erstellen</button>
<button class="btn btn-primary" form="${id}" type="submit">${UI.icon('receipt')} ${isEdit ? 'Änderungen speichern' : 'Rechnung erstellen'}</button>
`,
});
@ -3988,7 +4014,7 @@ window.Page_admin = (() => {
if (submitBtn) submitBtn.disabled = true;
try {
await API.post('/admin/invoices', {
const payload = {
recipient_name: fd.get('recipient_name'),
recipient_email: fd.get('recipient_email') || null,
recipient_address: fd.get('recipient_address') || null,
@ -3996,9 +4022,14 @@ window.Page_admin = (() => {
discount_pct: parseFloat(fd.get('discount_pct')) || 0,
notes: fd.get('notes') || null,
items,
});
};
if (isEdit) {
await API.patch(`/admin/invoices/${invoiceId}`, payload);
} else {
await API.post('/admin/invoices', payload);
}
UI.modal.close();
UI.toast.success('Rechnung erstellt.');
UI.toast.success(isEdit ? 'Rechnung gespeichert.' : 'Rechnung erstellt.');
reload();
} catch (err) {
UI.toast.error(err.message || 'Fehler beim Erstellen.');