Neues Vorlagen-Badge zwischen Bank-Badge und Buchungsformular in
/belege/{id}. Vorlage auswählen öffnet modalen Dialog mit Feldgruppen
(Metadaten, USt-Zeilen mit Live-Berechnung, Zahlungskonto). Buchungen
werden per VorlageBuchungsService aus JSON-Regeln in der DB erstellt.
Pflege-UI unter /einstellungen/buchungsvorlagen (CRUD inkl. Felder und
Regeln). Initiale Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" via
Migration 080 eingespielt. Test 42 prüft CRUD und Buchungsausführung.
198 lines
15 KiB
PHP
198 lines
15 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
define('BASE_DIR', dirname(__DIR__));
|
|
|
|
require BASE_DIR . '/vendor/autoload.php';
|
|
|
|
// Cache-Buster für statische Assets: Git-Commit-Hash aus Datei lesen
|
|
$_assetVersionFile = BASE_DIR . '/public/static/.asset-version';
|
|
define('ASSET_VERSION', file_exists($_assetVersionFile) ? trim(file_get_contents($_assetVersionFile)) : 'dev');
|
|
unset($_assetVersionFile);
|
|
|
|
use Steuerkram\Auth;
|
|
use Steuerkram\Config;
|
|
use Steuerkram\Router;
|
|
use Steuerkram\Controllers\AccountController;
|
|
use Steuerkram\Controllers\BelegController;
|
|
use Steuerkram\Controllers\BookingController;
|
|
use Steuerkram\Controllers\CustomerController;
|
|
use Steuerkram\Controllers\InvoiceController;
|
|
use Steuerkram\Controllers\SupplierController;
|
|
use Steuerkram\Controllers\UstvaController;
|
|
use Steuerkram\Controllers\EuerController;
|
|
use Steuerkram\Controllers\SettingsController;
|
|
use Steuerkram\Controllers\LoginController;
|
|
use Steuerkram\Controllers\AssetController;
|
|
use Steuerkram\Controllers\UserAdminController;
|
|
use Steuerkram\Controllers\BankController;
|
|
use Steuerkram\Controllers\BuchungsvorlageController;
|
|
|
|
Config::load();
|
|
|
|
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
|
|
if ($requestPath !== '/login') {
|
|
Auth::require();
|
|
}
|
|
|
|
$router = new Router();
|
|
|
|
// ── Dashboard ────────────────────────────────────────────────
|
|
$router->get('/', fn($p) => (new AccountController())->dashboard($p));
|
|
$router->get('/dashboard', fn($p) => (new AccountController())->dashboard($p));
|
|
|
|
// ── Kontenrahmen ─────────────────────────────────────────────
|
|
$router->get('/accounts', fn($p) => (new AccountController())->index($p));
|
|
$router->get('/accounts/new', fn($p) => (new AccountController())->create($p));
|
|
$router->post('/accounts', fn($p) => (new AccountController())->store($p));
|
|
$router->get('/accounts/{id}/journal', fn($p) => (new AccountController())->journal($p));
|
|
$router->get('/accounts/{id}/edit', fn($p) => (new AccountController())->edit($p));
|
|
$router->post('/accounts/{id}', fn($p) => (new AccountController())->update($p));
|
|
$router->post('/accounts/{id}/delete', fn($p) => (new AccountController())->destroy($p));
|
|
$router->get('/accounts/search', fn($p) => (new AccountController())->search($p));
|
|
|
|
// ── Belege ───────────────────────────────────────────────────
|
|
$router->get('/belege', fn($p) => (new BelegController())->index($p));
|
|
$router->get('/belege/export', fn($p) => (new BelegController())->export($p));
|
|
$router->get('/belege/upload', fn($p) => (new BelegController())->uploadForm($p));
|
|
$router->post('/belege/upload', fn($p) => (new BelegController())->upload($p));
|
|
$router->get('/belege/{id}', fn($p) => (new BelegController())->show($p));
|
|
$router->get('/belege/{id}/file', fn($p) => (new BelegController())->serveFile($p));
|
|
$router->post('/belege/{id}/delete', fn($p) => (new BelegController())->destroy($p));
|
|
$router->post('/belege/{id}/meta', fn($p) => (new BelegController())->updateMeta($p));
|
|
$router->post('/belege/{id}/crop', fn($p) => (new BelegController())->cropImage($p));
|
|
$router->post('/belege/{id}/vorschlag/generate', fn($p) => (new BelegController())->generateVorschlag($p));
|
|
$router->post('/belege/{id}/vorschlag/reset', fn($p) => (new BelegController())->resetVorschlag($p));
|
|
|
|
// ── Bank buchen ──────────────────────────────────────────────
|
|
$router->get('/bank', fn($p) => (new BankController())->index($p));
|
|
$router->get('/bank/direkt', fn($p) => (new BankController())->direkt($p));
|
|
$router->post('/bank/direkt', fn($p) => (new BankController())->direktStore($p));
|
|
$router->post('/bank/direkt/_order', fn($p) => (new BankController())->direktOrder($p));
|
|
$router->get('/bank/direkt/{id}/run', fn($p) => (new BankController())->direktRun($p));
|
|
$router->post('/bank/direkt/{id}', fn($p) => (new BankController())->direktUpdate($p));
|
|
$router->post('/bank/direkt/{id}/delete', fn($p) => (new BankController())->direktDelete($p));
|
|
$router->post('/bank/direkt/{id}/tan', fn($p) => (new BankController())->direktTan($p));
|
|
$router->post('/bank/direkt/{id}/accounts', fn($p) => (new BankController())->direktAccounts($p));
|
|
$router->get('/bank/upload', fn($p) => (new BankController())->uploadForm($p));
|
|
$router->post('/bank/upload', fn($p) => (new BankController())->upload($p));
|
|
$router->post('/bank/detect-format', fn($p) => (new BankController())->detectFormat($p));
|
|
$router->post('/bank/upload/confirm', fn($p) => (new BankController())->uploadConfirm($p));
|
|
$router->get('/bank/{id}', fn($p) => (new BankController())->show($p));
|
|
$router->post('/bank/{id}/status', fn($p) => (new BankController())->updateStatus($p));
|
|
$router->post('/bank/{id}/link', fn($p) => (new BankController())->linkBeleg($p));
|
|
$router->post('/bank/{id}/link-invoice', fn($p) => (new BankController())->linkInvoice($p));
|
|
$router->post('/bank/{id}/unlink', fn($p) => (new BankController())->unlinkBeleg($p));
|
|
$router->post('/bank/{id}/beleg', fn($p) => (new BankController())->uploadBeleg($p));
|
|
|
|
// ── Buchungen ────────────────────────────────────────────────
|
|
$router->get('/journal', fn($p) => (new BookingController())->journal($p));
|
|
$router->get('/journal/export', fn($p) => (new BookingController())->export($p));
|
|
$router->post('/belege/{beleg_id}/bookings', fn($p) => (new BookingController())->store($p));
|
|
$router->post('/bookings/{id}/reverse', fn($p) => (new BookingController())->reverse($p));
|
|
$router->post('/bookings/{id}/delete', fn($p) => (new BookingController())->destroy($p));
|
|
|
|
// ── Lieferanten ──────────────────────────────────────────────
|
|
$router->get('/suppliers', fn($p) => (new SupplierController())->index($p));
|
|
$router->get('/suppliers/new', fn($p) => (new SupplierController())->create($p));
|
|
$router->post('/suppliers', fn($p) => (new SupplierController())->store($p));
|
|
$router->get('/suppliers/search', fn($p) => (new SupplierController())->search($p));
|
|
$router->get('/suppliers/{id}/edit', fn($p) => (new SupplierController())->edit($p));
|
|
$router->post('/suppliers/{id}', fn($p) => (new SupplierController())->update($p));
|
|
$router->post('/suppliers/{id}/delete', fn($p) => (new SupplierController())->destroy($p));
|
|
|
|
// ── Kunden ───────────────────────────────────────────────────
|
|
$router->get('/customers', fn($p) => (new CustomerController())->index($p));
|
|
$router->get('/customers/new', fn($p) => (new CustomerController())->create($p));
|
|
$router->post('/customers', fn($p) => (new CustomerController())->store($p));
|
|
$router->get('/customers/{id}', fn($p) => (new CustomerController())->show($p));
|
|
$router->get('/customers/{id}/edit', fn($p) => (new CustomerController())->edit($p));
|
|
$router->post('/customers/{id}', fn($p) => (new CustomerController())->update($p));
|
|
$router->post('/customers/{id}/archive', fn($p) => (new CustomerController())->archive($p));
|
|
|
|
// ── Rechnungen ───────────────────────────────────────────────
|
|
$router->get('/invoices', fn($p) => (new InvoiceController())->index($p));
|
|
$router->get('/invoices/new', fn($p) => (new InvoiceController())->create($p));
|
|
$router->post('/invoices', fn($p) => (new InvoiceController())->store($p));
|
|
$router->get('/invoices/{id}', fn($p) => (new InvoiceController())->show($p));
|
|
$router->get('/invoices/{id}/edit', fn($p) => (new InvoiceController())->edit($p));
|
|
$router->post('/invoices/{id}', fn($p) => (new InvoiceController())->update($p));
|
|
$router->post('/invoices/{id}/finalize', fn($p) => (new InvoiceController())->finalize($p));
|
|
$router->get('/invoices/{id}/pdf', fn($p) => (new InvoiceController())->pdf($p));
|
|
$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));
|
|
$router->post('/invoices/{id}/send', fn($p) => (new InvoiceController())->send($p));
|
|
$router->post('/invoices/{id}/quick-book', fn($p) => (new InvoiceController())->quickBook($p));
|
|
|
|
// ── Anlagevermögen ───────────────────────────────────────────
|
|
$router->get('/assets', fn($p) => (new AssetController())->index($p));
|
|
$router->get('/assets/new', fn($p) => (new AssetController())->create($p));
|
|
$router->post('/assets', fn($p) => (new AssetController())->store($p));
|
|
$router->get('/assets/depreciation-preview', fn($p) => (new AssetController())->depreciationPreview($p));
|
|
$router->get('/assets/{id}/edit', fn($p) => (new AssetController())->edit($p));
|
|
$router->post('/assets/{id}', fn($p) => (new AssetController())->update($p));
|
|
$router->post('/assets/{id}/delete', fn($p) => (new AssetController())->destroy($p));
|
|
$router->post('/assets/{id}/depreciation', fn($p) => (new AssetController())->saveDepreciation($p));
|
|
$router->post('/assets/{id}/depreciation/{rowId}/book', fn($p) => (new AssetController())->bookAfa($p));
|
|
$router->post('/assets/{id}/depreciation/{rowId}/reverse', fn($p) => (new AssetController())->reverseAfaBooking($p));
|
|
$router->post('/assets/{id}/depreciation/{rowId}/delete', fn($p) => (new AssetController())->deleteAfaBooking($p));
|
|
|
|
// ── UStVA ────────────────────────────────────────────────────
|
|
$router->get('/tax/ustva', fn($p) => (new UstvaController())->index($p));
|
|
$router->get('/tax/ustva/{year}/{month}', fn($p) => (new UstvaController())->show($p));
|
|
$router->post('/tax/ustva/{year}/{month}/save', fn($p) => (new UstvaController())->save($p));
|
|
$router->get('/tax/ustva/{year}/{month}/xml', fn($p) => (new UstvaController())->downloadXml($p));
|
|
$router->get('/tax/ustva/{year}/{month}/kz/{kz}', fn($p) => (new UstvaController())->showKzBookings($p));
|
|
|
|
// ── EÜR ─────────────────────────────────────────────────────
|
|
$router->get('/tax/euer', fn($p) => (new EuerController())->index($p));
|
|
$router->get('/tax/euer/{year}', fn($p) => (new EuerController())->show($p));
|
|
$router->get('/tax/euer/{year}/pdf', fn($p) => (new EuerController())->pdf($p));
|
|
$router->get('/tax/euer/{year}/konto/{konto_id}', fn($p) => (new EuerController())->kontoBookings($p));
|
|
$router->get('/tax/euer/{year}/anlageliste/csv', fn($p) => (new EuerController())->anlageCsv($p));
|
|
$router->get('/tax/euer/{year}/anlageliste/pdf', fn($p) => (new EuerController())->anlagePdf($p));
|
|
|
|
// ── Einstellungen ────────────────────────────────────────────
|
|
$router->get('/settings', fn($p) => (new SettingsController())->show($p));
|
|
$router->post('/settings', fn($p) => (new SettingsController())->update($p));
|
|
$router->post('/settings/mail-template', fn($p) => (new SettingsController())->mailTemplate($p));
|
|
$router->post('/settings/mail-test', fn($p) => (new SettingsController())->mailTest($p));
|
|
$router->post('/settings/logo', fn($p) => (new SettingsController())->uploadLogo($p));
|
|
$router->post('/settings/logo/delete', fn($p) => (new SettingsController())->deleteLogo($p));
|
|
$router->post('/settings/generate-app-key', fn($p) => (new SettingsController())->generateAppKey($p));
|
|
$router->get('/settings/bankimport', fn($p) => (new SettingsController())->bankImport($p));
|
|
$router->post('/settings/bankimport/suggest', fn($p) => (new SettingsController())->storeSuggestion($p));
|
|
$router->post('/settings/bankimport/create', fn($p) => (new SettingsController())->createBankImportFormat($p));
|
|
$router->post('/settings/bankimport/dismiss-suggestion', fn($p) => (new SettingsController())->dismissSuggestion($p));
|
|
$router->post('/settings/bankimport/{id}/field', fn($p) => (new SettingsController())->updateBankImportField($p));
|
|
$router->post('/settings/bankimport/{id}/delete', fn($p) => (new SettingsController())->deleteBankImportFormat($p));
|
|
|
|
// ── Buchungsvorlagen ──────────────────────────────────────────
|
|
$router->get('/einstellungen/buchungsvorlagen', fn($p) => (new BuchungsvorlageController())->index($p));
|
|
$router->get('/einstellungen/buchungsvorlagen/neu', fn($p) => (new BuchungsvorlageController())->create($p));
|
|
$router->post('/einstellungen/buchungsvorlagen', fn($p) => (new BuchungsvorlageController())->store($p));
|
|
$router->get('/einstellungen/buchungsvorlagen/{id}/bearbeiten', fn($p) => (new BuchungsvorlageController())->edit($p));
|
|
$router->post('/einstellungen/buchungsvorlagen/{id}', fn($p) => (new BuchungsvorlageController())->update($p));
|
|
$router->post('/einstellungen/buchungsvorlagen/{id}/loeschen', fn($p) => (new BuchungsvorlageController())->destroy($p));
|
|
$router->get('/api/buchungsvorlagen/{id}/modal', fn($p) => (new BuchungsvorlageController())->modal($p));
|
|
$router->post('/belege/{belegId}/vorlage/{vorlageId}/buchen', fn($p) => (new BuchungsvorlageController())->buchen($p));
|
|
|
|
// ── Login / Logout ────────────────────────────────────────────
|
|
$router->get('/login', fn($p) => (new LoginController())->showLogin($p));
|
|
$router->post('/login', fn($p) => (new LoginController())->handleLogin($p));
|
|
$router->post('/logout', fn($p) => (new LoginController())->handleLogout($p));
|
|
|
|
// ── Benutzerverwaltung ────────────────────────────────────────
|
|
$router->get('/useradmin', fn($p) => (new UserAdminController())->index($p));
|
|
$router->post('/useradmin', fn($p) => (new UserAdminController())->store($p));
|
|
$router->post('/useradmin/{id}', fn($p) => (new UserAdminController())->update($p));
|
|
$router->post('/useradmin/{id}/delete', fn($p) => (new UserAdminController())->delete($p));
|
|
$router->post('/useradmin/{id}/toggle', fn($p) => (new UserAdminController())->toggleActive($p));
|
|
|
|
$router->dispatch();
|