diff --git a/migrations/024_bewirtung_zu_beleg.sql b/migrations/024_bewirtung_zu_beleg.sql new file mode 100644 index 0000000..b60ad6b --- /dev/null +++ b/migrations/024_bewirtung_zu_beleg.sql @@ -0,0 +1,10 @@ +-- Migration 024: Bewirtungsfelder von bookings nach belege verschieben +-- Bestehende Daten werden nicht migriert (können gelöscht werden). + +ALTER TABLE belege + ADD COLUMN bewirtungsgrund TEXT NULL AFTER notes, + ADD COLUMN teilnehmerliste TEXT NULL AFTER bewirtungsgrund; + +ALTER TABLE bookings + DROP COLUMN bewirtungsgrund, + DROP COLUMN teilnehmerliste; diff --git a/migrations/025_remove_eingangs_datum.sql b/migrations/025_remove_eingangs_datum.sql new file mode 100644 index 0000000..5f63a11 --- /dev/null +++ b/migrations/025_remove_eingangs_datum.sql @@ -0,0 +1,2 @@ +-- Migration 025: Eingangsdatum aus belege entfernen +ALTER TABLE belege DROP COLUMN eingangs_datum; diff --git a/migrations/026_kontenrahmen_prod.sql b/migrations/026_kontenrahmen_prod.sql new file mode 100644 index 0000000..b8a432d --- /dev/null +++ b/migrations/026_kontenrahmen_prod.sql @@ -0,0 +1,159 @@ +-- Migration 026: Kontenrahmen-Abgleich von Produktion (2026-04-11) + +INSERT INTO accounts (kontonummer, bezeichnung, kontenart, steuercode, ustva_kz, euer_zeile, is_system, aktiv) VALUES + ('0027', 'EDV-Software', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0030', 'Lizenzen an gewerblichen Schutzrechten', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0210', 'Maschinen', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0320', 'Pkw', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0350', 'Lkw', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0400', 'Betriebsausstattung', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0410', 'Geschäftsausstattung', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0420', 'Büroeinrichtung', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0440', 'Werkzeuge', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('0480', 'Geringwertige Wirtschaftsgüter', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1000', 'Kasse', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1010', 'Nebenkasse 1', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1200', 'Bank 1 - Comdirekt', 'Zahlungskonto', '', '', NULL, 1, 1), + ('1210', 'Bank 2 - Sonstige Banken und Kasse', 'Zahlungskonto', '', '', NULL, 1, 1), + ('1220', 'Bank 3', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1230', 'Bank 4', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1240', 'Bank 5', 'Zahlungskonto', NULL, NULL, NULL, 1, 1), + ('1390', 'Verrechnungskonto Ist-Versteuerung', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1770', 'Umsatzsteuer', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1771', 'Umsatzsteuer 7 %', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1776', 'Umsatzsteuer 19 %', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1780', 'Umsatzsteuer-Vorauszahlungen lfd. Jahr', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1781', 'Umsatzsteuer-Vorauszahlungen 1/11', 'Verbindlichkeit', '', '', NULL, 1, 1), + ('1800', 'Privatentnahmen', 'Privat', NULL, NULL, NULL, 1, 1), + ('1810', 'Privatsteuern', 'Privat', NULL, NULL, NULL, 1, 1), + ('1820', 'Sonderausgaben beschränkt abzugsfähig', 'Privat', NULL, NULL, NULL, 1, 1), + ('1830', 'Sonderausgaben unbeschränkt abzugsfähig', 'Privat', NULL, NULL, NULL, 1, 1), + ('1840', 'Zuwendungen, Spenden', 'Privat', NULL, NULL, NULL, 1, 1), + ('1890', 'Privateinlagen', 'Privat', NULL, NULL, NULL, 1, 1), + ('3106', 'Fremdleistungen 19 % Vorsteuer', 'Betriebsausgabe', 'VSt19', '61', '29', 1, 1), + ('3108', 'Fremdleistungen 7 % Vorsteuer', 'Betriebsausgabe', 'VSt7', '62', '29', 1, 1), + ('3109', 'Fremdleistungen ohne Vorsteuer', 'Betriebsausgabe', NULL, NULL, '29', 1, 1), + ('3300', 'Wareneingang 7 % Vorsteuer', 'Betriebsausgabe', 'VSt7', '62', '28', 1, 1), + ('3349', 'Wareneingang ohne Vorsteuerabzug', 'Betriebsausgabe', NULL, NULL, '26', 1, 1), + ('3400', 'Wareneingang 19 % Vorsteuer', 'Betriebsausgabe', 'VSt19', '61', '27', 1, 1), + ('4100', 'Löhne und Gehälter', 'Betriebsausgabe', NULL, NULL, '30', 1, 1), + ('4110', 'Löhne', 'Betriebsausgabe', NULL, NULL, '30', 1, 1), + ('4120', 'Gehälter', 'Betriebsausgabe', NULL, NULL, '30', 1, 1), + ('4130', 'Gesetzliche soziale Aufwendungen', 'Betriebsausgabe', NULL, NULL, '31', 1, 1), + ('4138', 'Beiträge zur Berufsgenossenschaft', 'Betriebsausgabe', NULL, NULL, '31', 1, 1), + ('4140', 'Freiwillige soziale Aufwendungen, lohnsteuerfrei', 'Betriebsausgabe', NULL, NULL, '32', 1, 1), + ('4145', 'Freiwillige soziale Aufwendungen, lohnsteuerpflichtig', 'Betriebsausgabe', NULL, NULL, '32', 1, 1), + ('4180', 'Aushilfslöhne', 'Betriebsausgabe', NULL, NULL, '30', 1, 1), + ('4190', 'Aushilfslöhne Minijobs', 'Betriebsausgabe', NULL, NULL, '30', 1, 1), + ('4210', 'Miete (unbewegliche Wirtschaftsgüter)', 'Betriebsausgabe', NULL, NULL, '33', 1, 1), + ('4211', 'Miete/Pacht unbewegliche WG (gewerbesteuerl. hinzuzur.)', 'Betriebsausgabe', NULL, NULL, '33', 1, 1), + ('4220', 'Pacht (unbewegliche Wirtschaftsgüter)', 'Betriebsausgabe', NULL, NULL, '33', 1, 1), + ('4230', 'Heizung', 'Betriebsausgabe', 'VSt19', '61', '34', 1, 1), + ('4240', 'Gas, Strom, Wasser', 'Betriebsausgabe', 'VSt19', '61', '34', 1, 1), + ('4250', 'Reinigung', 'Betriebsausgabe', 'VSt19', '61', '37', 1, 1), + ('4260', 'Instandhaltung betrieblicher Räume', 'Betriebsausgabe', 'VSt19', '61', '37', 1, 1), + ('4280', 'Sonstige Raumkosten', 'Betriebsausgabe', 'VSt19', '61', '33', 1, 1), + ('4287', 'Tagespauschale für Tätigkeit in der häuslichen Wohnung', 'Betriebsausgabe', NULL, NULL, '66', 1, 1), + ('4288', 'Häusliches Arbeitszimmer (abziehbarer Anteil)', 'Betriebsausgabe', NULL, NULL, '65', 1, 1), + ('4289', 'Häusliches Arbeitszimmer (nicht abziehbarer Anteil)', 'Betriebsausgabe', NULL, NULL, '51', 1, 1), + ('4300', 'Nicht abziehbare Vorsteuer', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4301', 'Nicht abziehbare Vorsteuer 7 %', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4306', 'Nicht abziehbare Vorsteuer 19 %', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4320', 'Gewerbesteuer', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4340', 'Sonstige Betriebssteuern', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4350', 'Verbrauchsteuer (sonstige Steuern)', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4360', 'Versicherungen', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4366', 'Versicherungen für Gebäude', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4380', 'Beiträge', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4390', 'Sonstige Abgaben', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4500', 'Fahrzeugkosten (allgemein)', 'Betriebsausgabe', NULL, NULL, '40', 1, 1), + ('4510', 'Kfz-Steuer', 'Betriebsausgabe', NULL, NULL, '40', 1, 1), + ('4520', 'Fahrzeug-Versicherungen', 'Betriebsausgabe', NULL, NULL, '40', 1, 1), + ('4530', 'Laufende Fahrzeug-Betriebskosten', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4540', 'Fahrzeug-Reparaturen', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4550', 'Garagenmiete', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4560', 'Mautgebühren', 'Betriebsausgabe', NULL, NULL, '40', 1, 1), + ('4570', 'Mietleasing Kfz', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4575', 'Mietleasing Elektrofahrzeuge/Fahrräder (gewerbesteuerl. hinzuzurechnen)', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4580', 'Sonstige Fahrzeugkosten', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4590', 'Fremdfahrzeugkosten', 'Betriebsausgabe', 'VSt19', '61', '40', 1, 1), + ('4600', 'Werbekosten', 'Betriebsausgabe', 'VSt19', '61', '41', 1, 1), + ('4605', 'Streuartikel', 'Betriebsausgabe', 'VSt19', '61', '41', 1, 1), + ('4630', 'Geschenke abzugsfähig ohne § 37b EStG', 'Betriebsausgabe', 'VSt19', '61', '41', 1, 1), + ('4631', 'Geschenke abzugsfähig mit § 37b EStG (§ 37b-Steuer)', 'Betriebsausgabe', 'VSt19', '61', '41', 1, 1), + ('4635', 'Geschenke nicht abzugsfähig ohne § 37b EStG', 'Betriebsausgabe', 'VSt19', '61', '51', 1, 1), + ('4636', 'Geschenke nicht abzugsfähig mit § 37b EStG', 'Betriebsausgabe', 'VSt19', '61', '51', 1, 1), + ('4650', 'Bewirtungskosten (70 % abzugsfähig) VSt. 19%', 'Betriebsausgabe', 'VSt19', '61', '44', 1, 1), + ('4651', 'Bewirtungskosten (70 % abzugsfähig) VSt. 7%', 'Betriebsausgabe', 'VSt7', '62', '44', 1, 1), + ('4652', 'Bewirtungskosten (70 % abzugsfähig) VSt. 0%', 'Betriebsausgabe', '', '', NULL, 0, 1), + ('4654', 'Nicht abzugsfähige Bewirtungskosten VSt. 19%', 'Betriebsausgabe', 'VSt19', '61', '51', 1, 1), + ('4656', 'nicht abzugsfähige Bewirtungskosten VSt. 7%', 'Betriebsausgabe', 'VSt7', '62', '51', 1, 1), + ('4657', 'nicht abzugsfähige Bewirtungskosten VSt. 0%', 'Betriebsausgabe', '', '', NULL, 0, 1), + ('4660', 'Reisekosten Arbeitnehmer', 'Betriebsausgabe', NULL, NULL, '42', 1, 1), + ('4663', 'Reisekosten Arbeitnehmer Fahrtkosten', 'Betriebsausgabe', NULL, NULL, '42', 1, 1), + ('4664', 'Reisekosten Arbeitnehmer Verpflegungsmehraufwand', 'Betriebsausgabe', NULL, NULL, '42', 1, 1), + ('4666', 'Reisekosten Arbeitnehmer Übernachtungsaufwand', 'Betriebsausgabe', 'VSt19', '61', '42', 1, 1), + ('4668', 'Kilometergelderstattung Arbeitnehmer', 'Betriebsausgabe', NULL, NULL, '42', 1, 1), + ('4670', 'Reisekosten Unternehmer', 'Betriebsausgabe', NULL, NULL, '43', 1, 1), + ('4672', 'Reisekosten Unternehmer (nicht abziehbarer Anteil)', 'Betriebsausgabe', NULL, NULL, '51', 1, 1), + ('4673', 'Reisekosten Unternehmer Fahrtkosten', 'Betriebsausgabe', NULL, NULL, '43', 1, 1), + ('4674', 'Reisekosten Unternehmer Verpflegungsmehraufwand', 'Betriebsausgabe', NULL, NULL, '43', 1, 1), + ('4676', 'Reisekosten Unternehmer Übernachtungsaufwand', 'Betriebsausgabe', 'VSt19', '61', '43', 1, 1), + ('4780', 'Fremdarbeiten', 'Betriebsausgabe', 'VSt19', '61', '29', 1, 1), + ('4800', 'Reparaturen und Instandhaltungen (Maschinen, techn. Anlagen)', 'Betriebsausgabe', 'VSt19', '61', '38', 1, 1), + ('4801', 'Reparaturen und Instandhaltung von Bauten', 'Betriebsausgabe', 'VSt19', '61', '37', 1, 1), + ('4805', 'Reparaturen und Instandhaltungen (andere Anlagen, BGA)', 'Betriebsausgabe', 'VSt19', '61', '38', 1, 1), + ('4806', 'Wartungskosten Hard- und Software', 'Betriebsausgabe', 'VSt19', '61', '38', 1, 1), + ('4809', 'Sonstige Reparaturen und Instandhaltungen', 'Betriebsausgabe', 'VSt19', '61', '38', 1, 1), + ('4822', 'Abschreibungen auf immaterielle Vermögensgegenstände', 'Betriebsausgabe', NULL, NULL, '49', 1, 1), + ('4830', 'Abschreibungen auf Sachanlagen (ohne AfA Fzg./Gebäude)', 'Betriebsausgabe', NULL, NULL, '49', 1, 1), + ('4831', 'Abschreibungen auf Gebäude', 'Betriebsausgabe', NULL, NULL, '49', 1, 1), + ('4832', 'Abschreibungen auf Fahrzeuge', 'Betriebsausgabe', NULL, NULL, '49', 1, 1), + ('4855', 'Sofortabschreibung geringwertiger Wirtschaftsgüter', 'Betriebsausgabe', NULL, NULL, '50', 1, 1), + ('4856', 'Sonderabschreibungen nach § 7b EStG (Mietwohnungsneubau)', 'Betriebsausgabe', NULL, NULL, '37', 1, 1), + ('4900', 'Sonstige betriebliche Aufwendungen', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('4909', 'Fremdleistungen / Fremdarbeiten', 'Betriebsausgabe', 'VSt19', '61', '29', 1, 1), + ('4910', 'Porto', 'Betriebsausgabe', NULL, NULL, '47', 1, 1), + ('4920', 'Telefon', 'Betriebsausgabe', 'VSt19', '61', '47', 1, 1), + ('4925', 'Internetkosten', 'Betriebsausgabe', 'VSt19', '61', '47', 1, 1), + ('4930', 'Bürobedarf', 'Betriebsausgabe', 'VSt19', '61', '47', 1, 1), + ('4940', 'Zeitschriften, Bücher, digitale Medien (Fachliteratur)', 'Betriebsausgabe', 'VSt7', '62', '47', 1, 1), + ('4945', 'Fortbildungskosten', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('4950', 'Rechts- und Beratungskosten', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('4955', 'Buchführungskosten', 'Betriebsausgabe', 'VSt19', '61', '46', 1, 1), + ('4957', 'Abschluss- und Prüfungskosten', 'Betriebsausgabe', 'VSt19', '61', '46', 1, 1), + ('4960', 'Mieten für Einrichtungen (bewegliche Wirtschaftsgüter)', 'Betriebsausgabe', 'VSt19', '61', '48', 1, 1), + ('4964', 'Zeitlich befristete Überlassung von Rechten (Lizenzen)', 'Betriebsausgabe', 'VSt19', '61', '48', 1, 1), + ('4965', 'Mietleasing (bewegliche WG / Geschäftsausstattung)', 'Betriebsausgabe', 'VSt19', '61', '48', 1, 1), + ('4969', 'Abraum- und Abfallbeseitigung', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('4970', 'Nebenkosten des Geldverkehrs (Bankgebühren, Zinsen)', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4971', 'Verwahrentgelt', 'Betriebsausgabe', NULL, NULL, '52', 1, 1), + ('4980', 'Sonstiger Betriebsbedarf', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('4985', 'Werkzeuge und Kleingeräte', 'Betriebsausgabe', 'VSt19', '61', '52', 1, 1), + ('8100', 'Steuerfreie Umsätze § 4 Nr. 8 ff. UStG', 'Betriebseinnahme', NULL, '48', '17', 1, 1), + ('8105', 'Steuerfreie Umsätze § 4 Nr. 12 UStG (Vermietung/Verpachtung)', 'Betriebseinnahme', NULL, '48', '17', 1, 1), + ('8110', 'Sonstige steuerfreie Umsätze Inland', 'Betriebseinnahme', NULL, '48', '17', 1, 1), + ('8120', 'Steuerfreie Umsätze § 4 Nr. 1a UStG', 'Betriebseinnahme', NULL, '43', '18', 1, 1), + ('8125', 'Steuerfreie innergemeinschaftliche Lieferungen § 4 Nr. 1b UStG', 'Betriebseinnahme', NULL, '41', '18', 1, 1), + ('8300', 'Erlöse 7 % USt', 'Betriebseinnahme', 'USt7', '86', '15', 1, 1), + ('8400', 'Erlöse 19 % USt', 'Betriebseinnahme', 'USt19', '81', '16', 1, 1), + ('8570', 'Sonstige Erträge aus Provisionen, Lizenzen und Patenten', 'Betriebseinnahme', 'USt19', '81', '16', 1, 1), + ('8710', 'Erlösschmälerungen 7 % USt', 'Betriebseinnahme', 'USt7', '86', '15', 1, 1), + ('8720', 'Erlösschmälerungen 19 % USt', 'Betriebseinnahme', 'USt19', '81', '16', 1, 1), + ('8800', 'Erlöse aus Verkäufen Sachanlagevermögen (bei Buchverlust)', 'Betriebseinnahme', NULL, NULL, '22', 1, 1), + ('8801', 'Erlöse aus Verkäufen Sachanlagevermögen 19 % USt (bei Buchverlust)', 'Betriebseinnahme', 'USt19', '81', '22', 1, 1), + ('8820', 'Erlöse aus Verkäufen Sachanlagevermögen 19 % USt (bei Buchgewinn)', 'Betriebseinnahme', 'USt19', '81', '22', 1, 1), + ('8900', 'Sonstige betriebliche Erträge', 'Betriebseinnahme', NULL, NULL, '23', 1, 1), + ('8910', 'Sonstige betriebliche Erträge (steuerfrei)', 'Betriebseinnahme', NULL, NULL, '23', 1, 1), + ('8920', 'Verwendung von Gegenständen für Zwecke außerhalb des Unternehmens', 'Betriebseinnahme', NULL, NULL, '22', 1, 1), + ('8921', 'Verwendung von Gegenständen für Zwecke außerhalb des Unternehmens 7 % USt', 'Betriebseinnahme', 'USt7', '86', '22', 1, 1), + ('8922', 'Verwendung von Gegenständen für Zwecke außerhalb des Unternehmens 19 % USt', 'Betriebseinnahme', 'USt19', '81', '22', 1, 1), + ('8950', 'Nicht steuerbare Umsätze (Innenenumsätze)', 'Betriebseinnahme', NULL, NULL, '21', 1, 1) +ON DUPLICATE KEY UPDATE + bezeichnung=VALUES(bezeichnung), + kontenart=VALUES(kontenart), + steuercode=VALUES(steuercode), + ustva_kz=VALUES(ustva_kz), + euer_zeile=VALUES(euer_zeile), + is_system=VALUES(is_system), + aktiv=VALUES(aktiv); diff --git a/public/static/js/app.js b/public/static/js/app.js index ad8e560..f744567 100644 --- a/public/static/js/app.js +++ b/public/static/js/app.js @@ -33,11 +33,14 @@ document.addEventListener('input', (e) => { if (opt.value === '') { opt.hidden = false; continue; } opt.hidden = !opt.dataset.search.toLowerCase().includes(q); } - // Auto-select first visible match + // Auto-select nur bei exaktem Kontonummer-Treffer; sonst Select leeren + // (verhindert, dass direkte Kontonummer-Eingabe durch einen Partial-Match überschrieben wird) if (q.length > 0) { - for (const opt of select.options) { - if (!opt.hidden && opt.value !== '') { select.value = opt.value; break; } - } + const exact = [...select.options].find( + opt => opt.value !== '' && opt.dataset.search && opt.dataset.search.split(' ')[0] === q + ); + select.value = exact ? exact.value : ''; + select.dispatchEvent(new Event('change')); } }); @@ -363,11 +366,12 @@ document.addEventListener('keydown', (e) => { // ── Flash Message Auto-dismiss ──────────────────────────────── document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.flash').forEach(el => { - if (el.closest('#ki-badge')) return; // KI-Badge nie auto-dismissen + if (el.closest('#ki-badge')) return; // KI-Badge nie auto-dismissen + if (el.classList.contains('flash-persistent')) return; // z.B. Bewirtungshinweis setTimeout(() => { el.style.transition = 'opacity .4s'; el.style.opacity = '0'; setTimeout(() => el.remove(), 400); - }, 4000); + }, 20000); }); }); diff --git a/src/Controllers/BelegController.php b/src/Controllers/BelegController.php index 8f8bec0..86b4dd4 100644 --- a/src/Controllers/BelegController.php +++ b/src/Controllers/BelegController.php @@ -126,9 +126,8 @@ class BelegController 'mime_type' => $mime, 'file_hash' => $hash, 'beleg_datum' => $_POST['beleg_datum'] ?? null, - 'eingangs_datum'=> $_POST['eingangs_datum'] ?? date('Y-m-d'), 'rechnungs_nr' => $filenameWithoutExt, - 'betrag_brutto' => ($_POST['betrag_brutto'] ?? '') !== '' ? $_POST['betrag_brutto'] : null, + 'betrag_brutto' => null, 'belegtyp' => $_POST['belegtyp'] ?? 'Eingangsrechnung', 'notes' => $_POST['notes'] ?? null, ]); @@ -214,7 +213,6 @@ class BelegController 'rechnungs_nr' => trim($_POST['rechnungs_nr'] ?? ''), 'belegtyp' => $_POST['belegtyp'] ?? $beleg['belegtyp'], 'beleg_datum' => $_POST['beleg_datum'] ?: null, - 'betrag_brutto' => ($_POST['betrag_brutto'] ?? '') !== '' ? $_POST['betrag_brutto'] : null, 'supplier_id' => $supplierId, ]); diff --git a/src/Controllers/BookingController.php b/src/Controllers/BookingController.php index dcef41f..5a158b6 100644 --- a/src/Controllers/BookingController.php +++ b/src/Controllers/BookingController.php @@ -89,10 +89,27 @@ class BookingController $data = $_POST; $errors = []; + // Direkte Kontonummer-Eingabe: nur auflösen wenn nichts per Select gewählt + foreach ([ + 'kategorie_kontonummer' => 'kategorie_konto_id', + 'zahlungs_kontonummer' => 'zahlungskonto_id', + ] as $field => $idField) { + if (!empty($data[$idField])) continue; // Select-Auswahl hat Vorrang + $nr = trim($data[$field] ?? ''); + if ($nr !== '') { + $acc = \Steuerkram\Database::fetchOne('SELECT id FROM accounts WHERE kontonummer = ?', [$nr]); + if (!$acc) { + $errors[$idField] = "Kontonummer '$nr' nicht gefunden."; + } else { + $data[$idField] = $acc['id']; + } + } + } + // Validate - if (empty($data['buchungstyp'])) $errors['buchungstyp'] = 'Pflichtfeld'; - if (empty($data['kategorie_konto_id'])) $errors['kategorie_konto_id'] = 'Pflichtfeld'; - if (empty($data['zahlungskonto_id'])) $errors['zahlungskonto_id'] = 'Pflichtfeld'; + if (empty($data['buchungstyp'])) $errors['buchungstyp'] = 'Pflichtfeld'; + if (empty($data['kategorie_konto_id']) && !isset($errors['kategorie_konto_id'])) $errors['kategorie_konto_id'] = 'Pflichtfeld'; + if (empty($data['zahlungskonto_id']) && !isset($errors['zahlungskonto_id'])) $errors['zahlungskonto_id'] = 'Pflichtfeld'; if (empty($data['buchungs_datum'])) $errors['buchungs_datum'] = 'Pflichtfeld'; if (!isset($data['betrag_netto']) || $data['betrag_netto'] === '') $errors['betrag_netto'] = 'Pflichtfeld'; @@ -110,14 +127,24 @@ class BookingController try { $data['beleg_id'] = $belegId; - // Bewirtungskonto-Split: 4650→4654, 4651→4656 + // Bewirtungsfelder am Beleg speichern (gehören zum Beleg, nicht zur Buchung) + \Steuerkram\Database::execute( + 'UPDATE belege SET bewirtungsgrund=?, teilnehmerliste=?, updated_at=NOW() WHERE id=?', + [ + !empty($data['bewirtungsgrund']) ? $data['bewirtungsgrund'] : null, + !empty($data['teilnehmerliste']) ? $data['teilnehmerliste'] : null, + $belegId, + ] + ); + + // Bewirtungskonto-Split: 4650→4654, 4651→4656, 4652→4657 $konto = \Steuerkram\Database::fetchOne( 'SELECT kontonummer FROM accounts WHERE id = ?', [(int)$data['kategorie_konto_id']] ); $kontonummer = $konto['kontonummer'] ?? ''; - if ($kontonummer === '4650' || $kontonummer === '4651') { + if (in_array($kontonummer, ['4650', '4651', '4652'], true)) { $this->bucheBewirtungssplit($data, $kontonummer); } else { Booking::create($data); @@ -171,7 +198,7 @@ class BookingController private function bucheBewirtungssplit(array $data, string $kontonummer): void { // Abzugskonto ermitteln - $abzugskontonummer = $kontonummer === '4650' ? '4654' : '4656'; + $abzugskontonummer = match($kontonummer) { '4650' => '4654', '4652' => '4657', default => '4656' }; $abzugskonto = \Steuerkram\Database::fetchOne( 'SELECT id FROM accounts WHERE kontonummer = ?', [$abzugskontonummer] @@ -188,17 +215,13 @@ class BookingController // Buchung 1: 70 % auf Bewirtungskonto (abzugsfähig) Booking::create(array_merge($data, [ - 'betrag_netto' => $netto70, - 'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null, - 'teilnehmerliste' => $data['teilnehmerliste'] ?? null, + 'betrag_netto' => $netto70, ])); // Buchung 2: 30 % auf Abzugskonto (nicht abzugsfähig, § 4 Abs. 5 EStG) Booking::create(array_merge($data, [ 'kategorie_konto_id' => $abzugskonto['id'], 'betrag_netto' => $netto30, - 'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null, - 'teilnehmerliste' => $data['teilnehmerliste'] ?? null, ])); } diff --git a/src/Controllers/InvoiceController.php b/src/Controllers/InvoiceController.php index 311942e..6421c16 100644 --- a/src/Controllers/InvoiceController.php +++ b/src/Controllers/InvoiceController.php @@ -323,7 +323,6 @@ class InvoiceController 'mime_type' => 'application/pdf', 'file_hash' => hash('sha256', $invoice['rechnungs_nr']), 'beleg_datum' => $invoice['rechnungs_datum'], - 'eingangs_datum' => $invoice['rechnungs_datum'], 'rechnungs_nr' => $invoice['rechnungs_nr'], 'betrag_brutto' => $invoice['betrag_brutto'], 'belegtyp' => 'Ausgangsrechnung', diff --git a/src/Models/Beleg.php b/src/Models/Beleg.php index 03345ed..214fe62 100644 --- a/src/Models/Beleg.php +++ b/src/Models/Beleg.php @@ -40,9 +40,8 @@ class Beleg $offset = ($page - 1) * $perPage; $sql = 'SELECT b.*, - COALESCE(b.betrag_brutto, - (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0) + (SELECT SUM(bk.betrag_brutto) FROM bookings bk + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, @@ -51,7 +50,7 @@ class Beleg LEFT JOIN fiscal_years fy ON b.fiscal_year_id = fy.id LEFT JOIN suppliers s ON b.supplier_id = s.id WHERE ' . implode(' AND ', $where) . ' - ORDER BY b.eingangs_datum DESC, b.id DESC + ORDER BY b.created_at DESC, b.id DESC LIMIT ? OFFSET ?'; $params[] = $perPage; @@ -71,9 +70,8 @@ class Beleg { return Database::fetchOne( 'SELECT b.*, - COALESCE(b.betrag_brutto, - (SELECT SUM(bk.betrag_brutto) FROM bookings bk - WHERE bk.beleg_id = b.id AND bk.is_reversal = 0) + (SELECT SUM(bk.betrag_brutto) FROM bookings bk + WHERE bk.beleg_id = b.id AND bk.is_reversal = 0 ) AS betrag_brutto, fy.year as fiscal_year_nr, s.name as supplier_name, @@ -98,8 +96,8 @@ class Beleg Database::execute( 'INSERT INTO belege (beleg_nr, filename, storage_path, mime_type, file_hash, - beleg_datum, eingangs_datum, rechnungs_nr, betrag_brutto, belegtyp, notes, fiscal_year_id) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', + beleg_datum, rechnungs_nr, betrag_brutto, belegtyp, notes, fiscal_year_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [ $data['beleg_nr'], $data['filename'], @@ -107,7 +105,6 @@ class Beleg $data['mime_type'], $data['file_hash'], $data['beleg_datum'] ?: null, - $data['eingangs_datum'], $data['rechnungs_nr'] ?? null, $data['betrag_brutto'] ?? null, $data['belegtyp'] ?? 'Eingangsrechnung', @@ -134,13 +131,12 @@ class Beleg } Database::execute( - 'UPDATE belege SET beleg_datum=?, rechnungs_nr=?, betrag_brutto=?, belegtyp=?, notes=?, + 'UPDATE belege SET beleg_datum=?, rechnungs_nr=?, belegtyp=?, notes=?, fiscal_year_id=?, updated_at=NOW() WHERE id=? AND locked=0', [ $data['beleg_datum'] ?: null, $data['rechnungs_nr'] ?? null, - $data['betrag_brutto'] ?? null, $data['belegtyp'] ?? 'Eingangsrechnung', $data['notes'] ?? null, $fyId, @@ -163,7 +159,6 @@ class Beleg rechnungs_nr = ?, belegtyp = ?, beleg_datum = ?, - betrag_brutto = ?, supplier_id = ?, fiscal_year_id = COALESCE(?, fiscal_year_id), updated_at = NOW() @@ -172,7 +167,6 @@ class Beleg $data['rechnungs_nr'] ?: null, $data['belegtyp'], $data['beleg_datum'] ?: null, - $data['betrag_brutto'] !== null && $data['betrag_brutto'] !== '' ? (float)$data['betrag_brutto'] : null, isset($data['supplier_id']) && $data['supplier_id'] !== '' ? (int)$data['supplier_id'] : null, $fyId, $id, diff --git a/src/Models/Booking.php b/src/Models/Booking.php index b34f265..8537170 100644 --- a/src/Models/Booking.php +++ b/src/Models/Booking.php @@ -105,8 +105,8 @@ class Booking 'INSERT INTO bookings (buchungs_nr, beleg_id, buchungs_datum, buchungstyp, kategorie_konto_id, zahlungskonto_id, betrag_netto, ust_satz, steuerart, betrag_ust, betrag_brutto, - buchungstext, bewirtungsgrund, teilnehmerliste, fiscal_year_id) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', + buchungstext, fiscal_year_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [ $nr, (int)$data['beleg_id'], @@ -120,8 +120,6 @@ class Booking $ust, $brutto, $data['buchungstext'], - $data['bewirtungsgrund'] ?? null, - $data['teilnehmerliste'] ?? null, $fy['id'], ] ); diff --git a/src/Services/NextcloudImportService.php b/src/Services/NextcloudImportService.php index c7c88a6..5d48d9b 100644 --- a/src/Services/NextcloudImportService.php +++ b/src/Services/NextcloudImportService.php @@ -269,7 +269,6 @@ class NextcloudImportService 'mime_type' => $contentType, 'file_hash' => $hash, 'beleg_datum' => null, - 'eingangs_datum' => $today, 'rechnungs_nr' => null, 'betrag_brutto' => null, 'belegtyp' => 'Eingangsrechnung', diff --git a/src/Views/belege/detail.php b/src/Views/belege/detail.php index 58be0ad..a060d1c 100644 --- a/src/Views/belege/detail.php +++ b/src/Views/belege/detail.php @@ -57,10 +57,7 @@ $suppliers = $suppliers ?? []; -
- Eingangsdatum
- -
+
Rechnungsnr.✎' : '' ?>
@@ -75,7 +72,7 @@ $suppliers = $suppliers ?? [];
- Brutto lt. Beleg
+ Brutto (Buchungen)
' . $fmt($beleg['betrag_brutto']) . '' : '–' ?>
@@ -86,6 +83,17 @@ $suppliers = $suppliers ?? []; ⚠ Prüfsumme abweichend
+ +
+ Bewirtung
+ + + + + · + +
+
Datei öffnen @@ -127,11 +135,7 @@ $suppliers = $suppliers ?? [];
-
- - -
+
Storniert - -
Grund: - - -
Teilnehmer: - @@ -378,12 +376,13 @@ $suppliers = $suppliers ?? []; - - - + @@ -405,9 +404,10 @@ $suppliers = $suppliers ?? []; - - @@ -451,7 +451,7 @@ $suppliers = $suppliers ?? []; -
- - -
+
@@ -46,12 +42,7 @@
-
- - -
+
diff --git a/src/Views/dashboard.php b/src/Views/dashboard.php index 44e20c9..4ee1de6 100644 --- a/src/Views/dashboard.php +++ b/src/Views/dashboard.php @@ -115,7 +115,7 @@ $fmt = fn($v) => View::formatMoney($v); const fd = new FormData(); fd.append('beleg_file', file); fd.append('belegtyp', 'Eingangsrechnung'); - fd.append('eingangs_datum', new Date().toISOString().slice(0,10)); + fd.append('beleg_datum', new Date().toISOString().slice(0,10)); fetch('/belege/upload', {