Fix #54: Löschen-Button in Rechnungsübersicht, nur im Testmodus sichtbar

This commit is contained in:
fds2610-bot 2026-04-26 11:07:14 +02:00
parent 672c657bbe
commit eb41c910fc
5 changed files with 97 additions and 8 deletions

View file

@ -95,6 +95,7 @@ $router->get('/invoices/{id}/book', fn($p) => (new InvoiceController())->book($p
$router->post('/invoices/{id}/bookings', fn($p) => (new InvoiceController())->storeBooking($p));
$router->post('/invoices/{id}/mark-paid', fn($p) => (new InvoiceController())->markPaid($p));
$router->post('/invoices/{id}/cancel', fn($p) => (new InvoiceController())->cancel($p));
$router->post('/invoices/{id}/delete', fn($p) => (new InvoiceController())->destroy($p));
$router->post('/invoices/{id}/lines', fn($p) => (new InvoiceController())->addLine($p));
$router->post('/invoices/{id}/lines/{line_id}/delete', fn($p) => (new InvoiceController())->deleteLine($p));

View file

@ -17,19 +17,21 @@ class InvoiceController
{
public function index(array $params): void
{
$filter = $_GET;
$page = max(1, (int)($_GET['page'] ?? 1));
$result = Invoice::all($filter, $page);
$filter = $_GET;
$page = max(1, (int)($_GET['page'] ?? 1));
$result = Invoice::all($filter, $page);
$settings = Setting::get();
$view = new View();
$view->render('layout/base.php', [
'pageTitle' => 'Ausgangsrechnungen',
'content' => $this->renderView('invoices/list', [
'rows' => $result['rows'],
'total' => $result['total'],
'pages' => $result['pages'],
'page' => $page,
'filter' => $filter,
'rows' => $result['rows'],
'total' => $result['total'],
'pages' => $result['pages'],
'page' => $page,
'filter' => $filter,
'settings' => $settings,
]),
'topbarActions' => '<a href="/invoices/new" class="btn btn-primary">+ Rechnung erstellen</a>',
]);
@ -347,6 +349,17 @@ class InvoiceController
return $belegNr;
}
public function destroy(array $params): void
{
if (!Setting::isTestMode()) {
View::redirect('/invoices', 'Löschen ist nur im Testmodus erlaubt.', 'error');
return;
}
$id = (int)$params['id'];
Invoice::delete($id);
View::redirect('/invoices', 'Rechnung gelöscht.');
}
public function markPaid(array $params): void
{
Invoice::markPaid((int)$params['id']);

View file

@ -232,6 +232,19 @@ class Invoice
);
}
public static function delete(int $id): void
{
$invoice = self::find($id);
if (!$invoice) return;
if (!empty($invoice['beleg_id'])) {
Database::execute('DELETE FROM bookings WHERE beleg_id = ?', [$invoice['beleg_id']]);
Database::execute('DELETE FROM belege WHERE id = ?', [$invoice['beleg_id']]);
}
Database::execute('DELETE FROM invoice_lines WHERE invoice_id = ?', [$id]);
Database::execute('DELETE FROM invoices WHERE id = ?', [$id]);
}
public static function generateRechnungsNr(): string
{
$settings = Database::fetchOne(

View file

@ -64,6 +64,12 @@
<?php if ($inv['status'] !== 'Entwurf'): ?>
<a href="/invoices/<?= $h($inv['id']) ?>/pdf" class="btn btn-secondary btn-sm">PDF</a>
<?php endif; ?>
<?php if (!empty($settings['test_mode'])): ?>
<form method="post" action="/invoices/<?= $h($inv['id']) ?>/delete" style="display:inline"
onsubmit="return confirm('Rechnung wirklich löschen?')">
<button type="submit" class="btn btn-danger btn-sm">Löschen</button>
</form>
<?php endif; ?>
</div>
</td>
</tr>

View file

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
use Steuerkram\Models\Customer;
use Steuerkram\Models\Invoice;
use Steuerkram\Models\Setting;
class RechnungLoeschenTestmodusTest extends TestCase
{
protected string $testName = 'Test 24: Rechnung löschen (nur im Testmodus)';
public function run(): void
{
$customerId = Customer::create([
'nachname' => 'LoeschTestKunde',
'strasse' => 'Teststr. 1',
'plz' => '12345',
'ort' => 'Teststadt',
'land' => 'DE',
]);
$invoiceId = Invoice::create([
'customer_id' => $customerId,
'betreff' => 'Lösch-Test-Rechnung',
'rechnungs_datum' => date('Y-m-d'),
'lines' => [
[
'bezeichnung' => 'Testposition',
'menge' => 1,
'einheit' => 'Stk.',
'einzelpreis' => 100,
'ust_satz' => 19,
],
],
]);
$this->assertGreaterThan(0, $invoiceId, 'Rechnung wurde angelegt');
$invoice = Invoice::find($invoiceId);
$this->assert($invoice !== false, 'Rechnung per find() auffindbar');
// Rechnung löschen
Invoice::delete($invoiceId);
$afterDelete = Invoice::find($invoiceId);
$this->assert($afterDelete === false, 'Rechnung nach delete() nicht mehr auffindbar');
// Positionen ebenfalls gelöscht
$lines = Invoice::lines($invoiceId);
$this->assertEquals(0, count($lines), 'Invoice-Lines nach delete() gelöscht');
// test_mode-Flag ist bei Neuinstallation gesetzt
$settings = Setting::get();
$this->assert(isset($settings['test_mode']), 'test_mode-Feld in company_settings vorhanden');
}
}