diff --git a/public/index.php b/public/index.php index a97660f..fef6b00 100644 --- a/public/index.php +++ b/public/index.php @@ -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)); diff --git a/src/Controllers/InvoiceController.php b/src/Controllers/InvoiceController.php index 556779f..686209e 100644 --- a/src/Controllers/InvoiceController.php +++ b/src/Controllers/InvoiceController.php @@ -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' => '+ Rechnung erstellen', ]); @@ -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']); diff --git a/src/Models/Invoice.php b/src/Models/Invoice.php index 9dbe016..6396e0b 100644 --- a/src/Models/Invoice.php +++ b/src/Models/Invoice.php @@ -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( diff --git a/src/Views/invoices/list.php b/src/Views/invoices/list.php index 571fd0d..3d79c5e 100644 --- a/src/Views/invoices/list.php +++ b/src/Views/invoices/list.php @@ -64,6 +64,12 @@ PDF + +
+ +
+ diff --git a/tests/24_RechnungLoeschenTestmodusTest.php b/tests/24_RechnungLoeschenTestmodusTest.php new file mode 100644 index 0000000..7eb4b9e --- /dev/null +++ b/tests/24_RechnungLoeschenTestmodusTest.php @@ -0,0 +1,56 @@ + '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'); + } +}