Added support for Streamdeck Pedal and updated UI to better fit the Packed UI style
This commit is contained in:
277
pirp/public/recurring_edit.php
Normal file
277
pirp/public/recurring_edit.php
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../src/config.php';
|
||||
require_once __DIR__ . '/../src/auth.php';
|
||||
require_once __DIR__ . '/../src/db.php';
|
||||
require_once __DIR__ . '/../src/invoice_functions.php';
|
||||
require_once __DIR__ . '/../src/customer_functions.php';
|
||||
require_once __DIR__ . '/../src/recurring_functions.php';
|
||||
require_once __DIR__ . '/../src/icons.php';
|
||||
require_login();
|
||||
|
||||
$settings = get_settings();
|
||||
$customers = get_customers();
|
||||
$error = '';
|
||||
$msg = '';
|
||||
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : null;
|
||||
$template = null;
|
||||
$items = [];
|
||||
|
||||
if ($id) {
|
||||
$template = get_recurring_template($id);
|
||||
if (!$template) {
|
||||
header('Location: ' . url_for('recurring.php'));
|
||||
exit;
|
||||
}
|
||||
$items = get_recurring_template_items($id);
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$data = [
|
||||
'template_name' => trim($_POST['template_name'] ?? ''),
|
||||
'customer_id' => (int)($_POST['customer_id'] ?? 0),
|
||||
'interval_type' => $_POST['interval_type'] ?? 'monthly',
|
||||
'start_date' => $_POST['start_date'] ?? date('Y-m-d'),
|
||||
'end_date' => $_POST['end_date'] ?: null,
|
||||
'next_due_date' => $_POST['next_due_date'] ?? date('Y-m-d'),
|
||||
'vat_mode' => $settings['vat_mode'] ?? 'klein',
|
||||
'vat_rate' => (float)($settings['default_vat_rate'] ?? 19.0),
|
||||
'is_active' => !empty($_POST['is_active']),
|
||||
'notes_internal' => $_POST['notes_internal'] ?? ''
|
||||
];
|
||||
|
||||
// Validierung
|
||||
if (empty($data['template_name'])) {
|
||||
$error = 'Bitte einen Namen eingeben.';
|
||||
} elseif ($data['customer_id'] <= 0) {
|
||||
$error = 'Bitte einen Kunden auswählen.';
|
||||
} else {
|
||||
// Positionen sammeln
|
||||
$newItems = [];
|
||||
$count = isset($_POST['item_desc']) ? count($_POST['item_desc']) : 0;
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
$desc = trim($_POST['item_desc'][$i] ?? '');
|
||||
$qty = (float)($_POST['item_qty'][$i] ?? 0);
|
||||
$price = (float)($_POST['item_price'][$i] ?? 0);
|
||||
|
||||
if ($desc !== '' && $qty > 0) {
|
||||
$newItems[] = [
|
||||
'position_no' => count($newItems) + 1,
|
||||
'description' => $desc,
|
||||
'quantity' => $qty,
|
||||
'unit_price' => $price
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($newItems)) {
|
||||
$error = 'Bitte mindestens eine Position ausfüllen.';
|
||||
} else {
|
||||
$template_id = save_recurring_template($id, $data);
|
||||
save_recurring_template_items($template_id, $newItems);
|
||||
|
||||
header('Location: ' . url_for('recurring.php'));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= $id ? 'Abo-Vorlage bearbeiten' : 'Neue Abo-Vorlage' ?></title>
|
||||
<link rel="stylesheet" href="assets/style.css">
|
||||
<script>
|
||||
function addRow() {
|
||||
const tbody = document.getElementById('items-body');
|
||||
const index = tbody.children.length;
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${index+1}</td>
|
||||
<td><input type="text" name="item_desc[${index}]" size="40"></td>
|
||||
<td><input type="number" step="0.01" name="item_qty[${index}]" value="1"></td>
|
||||
<td><input type="number" step="0.01" name="item_price[${index}]" value="0.00"></td>
|
||||
<td><button type="button" onclick="this.closest('tr').remove()">X</button></td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>PIRP</h1>
|
||||
<nav>
|
||||
<a href="<?= url_for('index.php') ?>"><?= icon_dashboard() ?>Dashboard</a>
|
||||
<a href="<?= url_for('invoices.php') ?>" class="active"><?= icon_invoices() ?>Rechnungen</a>
|
||||
<a href="<?= url_for('customers.php') ?>"><?= icon_customers() ?>Kunden</a>
|
||||
<a href="<?= url_for('expenses.php') ?>"><?= icon_expenses() ?>Ausgaben</a>
|
||||
<a href="<?= url_for('belegarchiv.php') ?>"><?= icon_archive() ?>Belege</a>
|
||||
<a href="<?= url_for('journal.php') ?>"><?= icon_journal() ?>Journal</a>
|
||||
<a href="<?= url_for('euer.php') ?>"><?= icon_euer() ?>EÜR</a>
|
||||
<a href="<?= url_for('settings.php') ?>"><?= icon_settings() ?>Einstellungen</a>
|
||||
<a href="<?= url_for('logout.php') ?>"><?= icon_logout() ?>Logout (<?= htmlspecialchars($_SESSION['username'] ?? '') ?>)</a>
|
||||
<span class="cmd-k-hint" onclick="document.dispatchEvent(new KeyboardEvent('keydown',{key:'k',ctrlKey:true}))"><kbd>Ctrl+K</kbd></span>
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<div class="module-subnav">
|
||||
<a href="<?= url_for('invoices.php') ?>">Übersicht</a>
|
||||
<a href="<?= url_for('invoice_new.php') ?>">Neue Rechnung</a>
|
||||
<a href="<?= url_for('recurring.php') ?>" class="active">Abo-Rechnungen</a>
|
||||
</div>
|
||||
<?php if ($error): ?><p class="error"><?= htmlspecialchars($error) ?></p><?php endif; ?>
|
||||
|
||||
<form method="post">
|
||||
<section>
|
||||
<h2>Abo-Details</h2>
|
||||
<div>
|
||||
<label>Name der Vorlage:
|
||||
<input type="text" name="template_name"
|
||||
value="<?= htmlspecialchars($template['template_name'] ?? '') ?>" required>
|
||||
</label>
|
||||
|
||||
<label>Kunde:
|
||||
<select name="customer_id" required>
|
||||
<option value="">-- wählen --</option>
|
||||
<?php foreach ($customers as $c): ?>
|
||||
<option value="<?= $c['id'] ?>"
|
||||
<?= ($template['customer_id'] ?? 0) == $c['id'] ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($c['name']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>Intervall:
|
||||
<select name="interval_type" required>
|
||||
<option value="monthly" <?= ($template['interval_type'] ?? '') === 'monthly' ? 'selected' : '' ?>>
|
||||
Monatlich
|
||||
</option>
|
||||
<option value="quarterly" <?= ($template['interval_type'] ?? '') === 'quarterly' ? 'selected' : '' ?>>
|
||||
Quartalsweise (alle 3 Monate)
|
||||
</option>
|
||||
<option value="yearly" <?= ($template['interval_type'] ?? '') === 'yearly' ? 'selected' : '' ?>>
|
||||
Jährlich
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<div class="flex-row">
|
||||
<label>Startdatum:
|
||||
<input type="date" name="start_date"
|
||||
value="<?= htmlspecialchars($template['start_date'] ?? date('Y-m-d')) ?>" required>
|
||||
</label>
|
||||
<label>Enddatum (optional):
|
||||
<input type="date" name="end_date"
|
||||
value="<?= htmlspecialchars($template['end_date'] ?? '') ?>">
|
||||
</label>
|
||||
<label>Nächste Fälligkeit:
|
||||
<input type="date" name="next_due_date"
|
||||
value="<?= htmlspecialchars($template['next_due_date'] ?? date('Y-m-d')) ?>" required>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" name="is_active" value="1"
|
||||
<?= ($template['is_active'] ?? true) ? 'checked' : '' ?>>
|
||||
Aktiv (Rechnungen werden generiert)
|
||||
</label>
|
||||
|
||||
<label>Interne Notizen:
|
||||
<textarea name="notes_internal" rows="2"><?= htmlspecialchars($template['notes_internal'] ?? '') ?></textarea>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Positionen</h2>
|
||||
<div>
|
||||
<table class="list" id="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:5%">Pos.</th>
|
||||
<th>Beschreibung</th>
|
||||
<th style="width:12%">Menge</th>
|
||||
<th style="width:15%">Einzelpreis (netto)</th>
|
||||
<th style="width:5%"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="items-body">
|
||||
<?php
|
||||
// Bestehende Positionen oder leere Zeilen
|
||||
$displayItems = !empty($items) ? $items : [
|
||||
['description' => '', 'quantity' => 1, 'unit_price' => 0],
|
||||
['description' => '', 'quantity' => 1, 'unit_price' => 0],
|
||||
['description' => '', 'quantity' => 1, 'unit_price' => 0]
|
||||
];
|
||||
foreach ($displayItems as $i => $item):
|
||||
?>
|
||||
<tr>
|
||||
<td><?= $i + 1 ?></td>
|
||||
<td><input type="text" name="item_desc[<?= $i ?>]"
|
||||
value="<?= htmlspecialchars($item['description']) ?>" size="40"></td>
|
||||
<td><input type="number" step="0.01" name="item_qty[<?= $i ?>]"
|
||||
value="<?= number_format($item['quantity'], 2, '.', '') ?>"></td>
|
||||
<td><input type="number" step="0.01" name="item_price[<?= $i ?>]"
|
||||
value="<?= number_format($item['unit_price'], 2, '.', '') ?>"></td>
|
||||
<td><button type="button" onclick="this.closest('tr').remove()">X</button></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<button type="button" onclick="addRow()" class="button-secondary">Position hinzufügen</button>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<p>
|
||||
<button type="submit">Speichern</button>
|
||||
<a href="<?= url_for('recurring.php') ?>" class="button-secondary">Abbrechen</a>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<?php if ($id): ?>
|
||||
<section>
|
||||
<h2>Generierte Rechnungen</h2>
|
||||
<div>
|
||||
<?php $log = get_recurring_log($id); ?>
|
||||
<?php if (empty($log)): ?>
|
||||
<p>Noch keine Rechnungen generiert.</p>
|
||||
<?php else: ?>
|
||||
<table class="list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Fälligkeit</th>
|
||||
<th>Rechnungsnr.</th>
|
||||
<th>Betrag</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($log as $entry): ?>
|
||||
<tr>
|
||||
<td><?= date('d.m.Y H:i', strtotime($entry['generated_at'])) ?></td>
|
||||
<td><?= date('d.m.Y', strtotime($entry['due_date'])) ?></td>
|
||||
<td><?= htmlspecialchars($entry['invoice_number'] ?? '-') ?></td>
|
||||
<td><?= $entry['total_gross'] ? number_format($entry['total_gross'], 2, ',', '.') . ' €' : '-' ?></td>
|
||||
<td>
|
||||
<?php if ($entry['invoice_id']): ?>
|
||||
<a href="<?= url_for('invoice_pdf.php?id=' . $entry['invoice_id']) ?>" target="_blank">PDF</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
<script src="assets/command-palette.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user