Merge pull request 'Feature: Belegbuchung verbessert, Metadaten bereinigt (Migrationen 024–026)' (#26) from fds2610-bot/Steuerkram:main into main

Reviewed-on: https://codeberg.org/fds2610/Steuerkram/pulls/26
This commit is contained in:
fds2610 2026-04-11 11:46:09 +02:00
commit b2ec251871
14 changed files with 264 additions and 85 deletions

View file

@ -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;

View file

@ -0,0 +1,2 @@
-- Migration 025: Eingangsdatum aus belege entfernen
ALTER TABLE belege DROP COLUMN eingangs_datum;

View file

@ -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);

View file

@ -33,11 +33,14 @@ document.addEventListener('input', (e) => {
if (opt.value === '') { opt.hidden = false; continue; } if (opt.value === '') { opt.hidden = false; continue; }
opt.hidden = !opt.dataset.search.toLowerCase().includes(q); 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) { if (q.length > 0) {
for (const opt of select.options) { const exact = [...select.options].find(
if (!opt.hidden && opt.value !== '') { select.value = opt.value; break; } 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 ──────────────────────────────── // ── Flash Message Auto-dismiss ────────────────────────────────
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.flash').forEach(el => { 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(() => { setTimeout(() => {
el.style.transition = 'opacity .4s'; el.style.transition = 'opacity .4s';
el.style.opacity = '0'; el.style.opacity = '0';
setTimeout(() => el.remove(), 400); setTimeout(() => el.remove(), 400);
}, 4000); }, 20000);
}); });
}); });

View file

@ -126,9 +126,8 @@ class BelegController
'mime_type' => $mime, 'mime_type' => $mime,
'file_hash' => $hash, 'file_hash' => $hash,
'beleg_datum' => $_POST['beleg_datum'] ?? null, 'beleg_datum' => $_POST['beleg_datum'] ?? null,
'eingangs_datum'=> $_POST['eingangs_datum'] ?? date('Y-m-d'),
'rechnungs_nr' => $filenameWithoutExt, 'rechnungs_nr' => $filenameWithoutExt,
'betrag_brutto' => ($_POST['betrag_brutto'] ?? '') !== '' ? $_POST['betrag_brutto'] : null, 'betrag_brutto' => null,
'belegtyp' => $_POST['belegtyp'] ?? 'Eingangsrechnung', 'belegtyp' => $_POST['belegtyp'] ?? 'Eingangsrechnung',
'notes' => $_POST['notes'] ?? null, 'notes' => $_POST['notes'] ?? null,
]); ]);
@ -214,7 +213,6 @@ class BelegController
'rechnungs_nr' => trim($_POST['rechnungs_nr'] ?? ''), 'rechnungs_nr' => trim($_POST['rechnungs_nr'] ?? ''),
'belegtyp' => $_POST['belegtyp'] ?? $beleg['belegtyp'], 'belegtyp' => $_POST['belegtyp'] ?? $beleg['belegtyp'],
'beleg_datum' => $_POST['beleg_datum'] ?: null, 'beleg_datum' => $_POST['beleg_datum'] ?: null,
'betrag_brutto' => ($_POST['betrag_brutto'] ?? '') !== '' ? $_POST['betrag_brutto'] : null,
'supplier_id' => $supplierId, 'supplier_id' => $supplierId,
]); ]);

View file

@ -89,10 +89,27 @@ class BookingController
$data = $_POST; $data = $_POST;
$errors = []; $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 // Validate
if (empty($data['buchungstyp'])) $errors['buchungstyp'] = 'Pflichtfeld'; if (empty($data['buchungstyp'])) $errors['buchungstyp'] = 'Pflichtfeld';
if (empty($data['kategorie_konto_id'])) $errors['kategorie_konto_id'] = 'Pflichtfeld'; if (empty($data['kategorie_konto_id']) && !isset($errors['kategorie_konto_id'])) $errors['kategorie_konto_id'] = 'Pflichtfeld';
if (empty($data['zahlungskonto_id'])) $errors['zahlungskonto_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 (empty($data['buchungs_datum'])) $errors['buchungs_datum'] = 'Pflichtfeld';
if (!isset($data['betrag_netto']) || $data['betrag_netto'] === '') if (!isset($data['betrag_netto']) || $data['betrag_netto'] === '')
$errors['betrag_netto'] = 'Pflichtfeld'; $errors['betrag_netto'] = 'Pflichtfeld';
@ -110,14 +127,24 @@ class BookingController
try { try {
$data['beleg_id'] = $belegId; $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( $konto = \Steuerkram\Database::fetchOne(
'SELECT kontonummer FROM accounts WHERE id = ?', 'SELECT kontonummer FROM accounts WHERE id = ?',
[(int)$data['kategorie_konto_id']] [(int)$data['kategorie_konto_id']]
); );
$kontonummer = $konto['kontonummer'] ?? ''; $kontonummer = $konto['kontonummer'] ?? '';
if ($kontonummer === '4650' || $kontonummer === '4651') { if (in_array($kontonummer, ['4650', '4651', '4652'], true)) {
$this->bucheBewirtungssplit($data, $kontonummer); $this->bucheBewirtungssplit($data, $kontonummer);
} else { } else {
Booking::create($data); Booking::create($data);
@ -171,7 +198,7 @@ class BookingController
private function bucheBewirtungssplit(array $data, string $kontonummer): void private function bucheBewirtungssplit(array $data, string $kontonummer): void
{ {
// Abzugskonto ermitteln // Abzugskonto ermitteln
$abzugskontonummer = $kontonummer === '4650' ? '4654' : '4656'; $abzugskontonummer = match($kontonummer) { '4650' => '4654', '4652' => '4657', default => '4656' };
$abzugskonto = \Steuerkram\Database::fetchOne( $abzugskonto = \Steuerkram\Database::fetchOne(
'SELECT id FROM accounts WHERE kontonummer = ?', 'SELECT id FROM accounts WHERE kontonummer = ?',
[$abzugskontonummer] [$abzugskontonummer]
@ -188,17 +215,13 @@ class BookingController
// Buchung 1: 70 % auf Bewirtungskonto (abzugsfähig) // Buchung 1: 70 % auf Bewirtungskonto (abzugsfähig)
Booking::create(array_merge($data, [ Booking::create(array_merge($data, [
'betrag_netto' => $netto70, 'betrag_netto' => $netto70,
'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null,
'teilnehmerliste' => $data['teilnehmerliste'] ?? null,
])); ]));
// Buchung 2: 30 % auf Abzugskonto (nicht abzugsfähig, § 4 Abs. 5 EStG) // Buchung 2: 30 % auf Abzugskonto (nicht abzugsfähig, § 4 Abs. 5 EStG)
Booking::create(array_merge($data, [ Booking::create(array_merge($data, [
'kategorie_konto_id' => $abzugskonto['id'], 'kategorie_konto_id' => $abzugskonto['id'],
'betrag_netto' => $netto30, 'betrag_netto' => $netto30,
'bewirtungsgrund' => $data['bewirtungsgrund'] ?? null,
'teilnehmerliste' => $data['teilnehmerliste'] ?? null,
])); ]));
} }

View file

@ -323,7 +323,6 @@ class InvoiceController
'mime_type' => 'application/pdf', 'mime_type' => 'application/pdf',
'file_hash' => hash('sha256', $invoice['rechnungs_nr']), 'file_hash' => hash('sha256', $invoice['rechnungs_nr']),
'beleg_datum' => $invoice['rechnungs_datum'], 'beleg_datum' => $invoice['rechnungs_datum'],
'eingangs_datum' => $invoice['rechnungs_datum'],
'rechnungs_nr' => $invoice['rechnungs_nr'], 'rechnungs_nr' => $invoice['rechnungs_nr'],
'betrag_brutto' => $invoice['betrag_brutto'], 'betrag_brutto' => $invoice['betrag_brutto'],
'belegtyp' => 'Ausgangsrechnung', 'belegtyp' => 'Ausgangsrechnung',

View file

@ -40,9 +40,8 @@ class Beleg
$offset = ($page - 1) * $perPage; $offset = ($page - 1) * $perPage;
$sql = 'SELECT b.*, $sql = 'SELECT b.*,
COALESCE(b.betrag_brutto, (SELECT SUM(bk.betrag_brutto) FROM bookings bk
(SELECT SUM(bk.betrag_brutto) FROM bookings bk WHERE bk.beleg_id = b.id AND bk.is_reversal = 0
WHERE bk.beleg_id = b.id AND bk.is_reversal = 0)
) AS betrag_brutto, ) AS betrag_brutto,
fy.year as fiscal_year_nr, fy.year as fiscal_year_nr,
s.name as supplier_name, 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 fiscal_years fy ON b.fiscal_year_id = fy.id
LEFT JOIN suppliers s ON b.supplier_id = s.id LEFT JOIN suppliers s ON b.supplier_id = s.id
WHERE ' . implode(' AND ', $where) . ' WHERE ' . implode(' AND ', $where) . '
ORDER BY b.eingangs_datum DESC, b.id DESC ORDER BY b.created_at DESC, b.id DESC
LIMIT ? OFFSET ?'; LIMIT ? OFFSET ?';
$params[] = $perPage; $params[] = $perPage;
@ -71,9 +70,8 @@ class Beleg
{ {
return Database::fetchOne( return Database::fetchOne(
'SELECT b.*, 'SELECT b.*,
COALESCE(b.betrag_brutto, (SELECT SUM(bk.betrag_brutto) FROM bookings bk
(SELECT SUM(bk.betrag_brutto) FROM bookings bk WHERE bk.beleg_id = b.id AND bk.is_reversal = 0
WHERE bk.beleg_id = b.id AND bk.is_reversal = 0)
) AS betrag_brutto, ) AS betrag_brutto,
fy.year as fiscal_year_nr, fy.year as fiscal_year_nr,
s.name as supplier_name, s.name as supplier_name,
@ -98,8 +96,8 @@ class Beleg
Database::execute( Database::execute(
'INSERT INTO belege (beleg_nr, filename, storage_path, mime_type, file_hash, '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) beleg_datum, rechnungs_nr, betrag_brutto, belegtyp, notes, fiscal_year_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[ [
$data['beleg_nr'], $data['beleg_nr'],
$data['filename'], $data['filename'],
@ -107,7 +105,6 @@ class Beleg
$data['mime_type'], $data['mime_type'],
$data['file_hash'], $data['file_hash'],
$data['beleg_datum'] ?: null, $data['beleg_datum'] ?: null,
$data['eingangs_datum'],
$data['rechnungs_nr'] ?? null, $data['rechnungs_nr'] ?? null,
$data['betrag_brutto'] ?? null, $data['betrag_brutto'] ?? null,
$data['belegtyp'] ?? 'Eingangsrechnung', $data['belegtyp'] ?? 'Eingangsrechnung',
@ -134,13 +131,12 @@ class Beleg
} }
Database::execute( 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() fiscal_year_id=?, updated_at=NOW()
WHERE id=? AND locked=0', WHERE id=? AND locked=0',
[ [
$data['beleg_datum'] ?: null, $data['beleg_datum'] ?: null,
$data['rechnungs_nr'] ?? null, $data['rechnungs_nr'] ?? null,
$data['betrag_brutto'] ?? null,
$data['belegtyp'] ?? 'Eingangsrechnung', $data['belegtyp'] ?? 'Eingangsrechnung',
$data['notes'] ?? null, $data['notes'] ?? null,
$fyId, $fyId,
@ -163,7 +159,6 @@ class Beleg
rechnungs_nr = ?, rechnungs_nr = ?,
belegtyp = ?, belegtyp = ?,
beleg_datum = ?, beleg_datum = ?,
betrag_brutto = ?,
supplier_id = ?, supplier_id = ?,
fiscal_year_id = COALESCE(?, fiscal_year_id), fiscal_year_id = COALESCE(?, fiscal_year_id),
updated_at = NOW() updated_at = NOW()
@ -172,7 +167,6 @@ class Beleg
$data['rechnungs_nr'] ?: null, $data['rechnungs_nr'] ?: null,
$data['belegtyp'], $data['belegtyp'],
$data['beleg_datum'] ?: null, $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, isset($data['supplier_id']) && $data['supplier_id'] !== '' ? (int)$data['supplier_id'] : null,
$fyId, $fyId,
$id, $id,

View file

@ -105,8 +105,8 @@ class Booking
'INSERT INTO bookings (buchungs_nr, beleg_id, buchungs_datum, buchungstyp, 'INSERT INTO bookings (buchungs_nr, beleg_id, buchungs_datum, buchungstyp,
kategorie_konto_id, zahlungskonto_id, kategorie_konto_id, zahlungskonto_id,
betrag_netto, ust_satz, steuerart, betrag_ust, betrag_brutto, betrag_netto, ust_satz, steuerart, betrag_ust, betrag_brutto,
buchungstext, bewirtungsgrund, teilnehmerliste, fiscal_year_id) buchungstext, fiscal_year_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
[ [
$nr, $nr,
(int)$data['beleg_id'], (int)$data['beleg_id'],
@ -120,8 +120,6 @@ class Booking
$ust, $ust,
$brutto, $brutto,
$data['buchungstext'], $data['buchungstext'],
$data['bewirtungsgrund'] ?? null,
$data['teilnehmerliste'] ?? null,
$fy['id'], $fy['id'],
] ]
); );

View file

@ -269,7 +269,6 @@ class NextcloudImportService
'mime_type' => $contentType, 'mime_type' => $contentType,
'file_hash' => $hash, 'file_hash' => $hash,
'beleg_datum' => null, 'beleg_datum' => null,
'eingangs_datum' => $today,
'rechnungs_nr' => null, 'rechnungs_nr' => null,
'betrag_brutto' => null, 'betrag_brutto' => null,
'belegtyp' => 'Eingangsrechnung', 'belegtyp' => 'Eingangsrechnung',

View file

@ -57,10 +57,7 @@ $suppliers = $suppliers ?? [];
<?= View::formatDate($beleg['beleg_datum']) ?> <?= View::formatDate($beleg['beleg_datum']) ?>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div>
<span class="text-muted text-sm">Eingangsdatum</span><br>
<?= View::formatDate($beleg['eingangs_datum']) ?>
</div>
<div> <div>
<span class="text-muted text-sm">Rechnungsnr.<?= !$beleg['locked'] ? ' <span style="opacity:.4;font-size:.7rem">✎</span>' : '' ?></span><br> <span class="text-muted text-sm">Rechnungsnr.<?= !$beleg['locked'] ? ' <span style="opacity:.4;font-size:.7rem">✎</span>' : '' ?></span><br>
<?php if (!$beleg['locked']): ?> <?php if (!$beleg['locked']): ?>
@ -75,7 +72,7 @@ $suppliers = $suppliers ?? [];
<?php endif; ?> <?php endif; ?>
</div> </div>
<div> <div>
<span class="text-muted text-sm">Brutto lt. Beleg</span><br> <span class="text-muted text-sm">Brutto (Buchungen)</span><br>
<?= $beleg['betrag_brutto'] ? '<strong>' . $fmt($beleg['betrag_brutto']) . '</strong>' : '<span class="text-muted">–</span>' ?> <?= $beleg['betrag_brutto'] ? '<strong>' . $fmt($beleg['betrag_brutto']) . '</strong>' : '<span class="text-muted">–</span>' ?>
</div> </div>
<div> <div>
@ -86,6 +83,17 @@ $suppliers = $suppliers ?? [];
<span class="badge badge-red">⚠ Prüfsumme abweichend</span> <span class="badge badge-red">⚠ Prüfsumme abweichend</span>
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php if (!empty($beleg['bewirtungsgrund']) || !empty($beleg['teilnehmerliste'])): ?>
<div>
<span class="text-muted text-sm">Bewirtung</span><br>
<?php if (!empty($beleg['bewirtungsgrund'])): ?>
<span><?= $h($beleg['bewirtungsgrund']) ?></span>
<?php endif; ?>
<?php if (!empty($beleg['teilnehmerliste'])): ?>
<span class="text-muted" style="font-size:.85em"> · <?= $h($beleg['teilnehmerliste']) ?></span>
<?php endif; ?>
</div>
<?php endif; ?>
<div style="margin-left:auto;display:flex;gap:.5rem"> <div style="margin-left:auto;display:flex;gap:.5rem">
<a href="/belege/<?= $h($beleg['id']) ?>/file" target="_blank" class="btn btn-secondary btn-sm">Datei öffnen</a> <a href="/belege/<?= $h($beleg['id']) ?>/file" target="_blank" class="btn btn-secondary btn-sm">Datei öffnen</a>
<?php if (!$beleg['locked'] && in_array($beleg['mime_type'], ['image/jpeg', 'image/png'])): ?> <?php if (!$beleg['locked'] && in_array($beleg['mime_type'], ['image/jpeg', 'image/png'])): ?>
@ -127,11 +135,7 @@ $suppliers = $suppliers ?? [];
<label style="font-size:.8rem">Belegdatum</label> <label style="font-size:.8rem">Belegdatum</label>
<input type="date" name="beleg_datum" value="<?= $h($beleg['beleg_datum'] ?? '') ?>"> <input type="date" name="beleg_datum" value="<?= $h($beleg['beleg_datum'] ?? '') ?>">
</div> </div>
<div class="form-group" style="margin:0;min-width:120px">
<label style="font-size:.8rem">Brutto lt. Beleg (€)</label>
<input type="number" name="betrag_brutto" step="0.01" min="0"
value="<?= $h($beleg['betrag_brutto'] ?? '') ?>" placeholder="0.00">
</div>
<div class="form-group" style="margin:0;min-width:180px"> <div class="form-group" style="margin:0;min-width:180px">
<label style="font-size:.8rem">Lieferant</label> <label style="font-size:.8rem">Lieferant</label>
<input type="text" name="supplier_name" id="supplier_name_input" <input type="text" name="supplier_name" id="supplier_name_input"
@ -217,12 +221,6 @@ $suppliers = $suppliers ?? [];
<?php elseif ($isReversed): ?> <?php elseif ($isReversed): ?>
<span class="badge badge-red">Storniert</span> <span class="badge badge-red">Storniert</span>
<?php endif; ?> <?php endif; ?>
<?php if (!empty($bk['bewirtungsgrund'])): ?>
<br><span class="td-muted" style="font-size:.8em">Grund: <?= $h($bk['bewirtungsgrund']) ?></span>
<?php endif; ?>
<?php if (!empty($bk['teilnehmerliste'])): ?>
<br><span class="td-muted" style="font-size:.8em">Teilnehmer: <?= $h($bk['teilnehmerliste']) ?></span>
<?php endif; ?>
</td> </td>
<td> <td>
<?php if (!$bk['locked'] && !$isReversal && !$isReversed): ?> <?php if (!$bk['locked'] && !$isReversal && !$isReversed): ?>
@ -378,12 +376,13 @@ $suppliers = $suppliers ?? [];
<label for="kategorie_konto_id">Kategorie * <label for="kategorie_konto_id">Kategorie *
<span id="kategorie_konto_art" class="badge badge-gray" style="margin-left:.5rem;font-size:.7rem"></span> <span id="kategorie_konto_art" class="badge badge-gray" style="margin-left:.5rem;font-size:.7rem"></span>
</label> </label>
<input type="search" placeholder="Kontonr. oder Bezeichnung filtern…" class="konto-filter" <input type="search" name="kategorie_kontonummer" placeholder="Kontonr. oder Bezeichnung filtern – oder direkt eingeben" class="konto-filter"
data-target="kategorie_konto_id" autocomplete="off" style="margin-bottom:.3rem"> data-target="kategorie_konto_id" autocomplete="off" style="margin-bottom:.3rem"
<select id="kategorie_konto_id" name="kategorie_konto_id" required size="6" value="<?= $h($formData['kategorie_kontonummer'] ?? '') ?>">
<select id="kategorie_konto_id" name="kategorie_konto_id" size="6"
onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState();updateBewirtungsState();updateAutoUst()"> onchange="showKontoArt('kategorie_konto_id','kategorie_konto_art',this);updateEigenanteilState();updateBewirtungsState();updateAutoUst()">
<option value="">– Konto wählen –</option> <option value="">– Konto wählen –</option>
<?php foreach (['Betriebsausgabe', 'Betriebseinnahme', 'Privat'] as $art): ?> <?php foreach (['Betriebsausgabe', 'Betriebseinnahme', 'Privat', 'Verbindlichkeit'] as $art): ?>
<?php if (empty($kontenGruppen[$art])) continue; ?> <?php if (empty($kontenGruppen[$art])) continue; ?>
<optgroup label="── <?= $h($art) ?> ──" data-kontenart="<?= $h($art) ?>"> <optgroup label="── <?= $h($art) ?> ──" data-kontenart="<?= $h($art) ?>">
<?php foreach ($kontenGruppen[$art] as $acc): ?> <?php foreach ($kontenGruppen[$art] as $acc): ?>
@ -405,9 +404,10 @@ $suppliers = $suppliers ?? [];
<label for="zahlungskonto_id">Zahlungskonto * <label for="zahlungskonto_id">Zahlungskonto *
<span id="zahlungskonto_art" class="badge badge-gray" style="margin-left:.5rem;font-size:.7rem"></span> <span id="zahlungskonto_art" class="badge badge-gray" style="margin-left:.5rem;font-size:.7rem"></span>
</label> </label>
<input type="search" placeholder="Kontonr. oder Bezeichnung filtern…" class="konto-filter" <input type="search" name="zahlungs_kontonummer" placeholder="Kontonr. oder Bezeichnung filtern – oder direkt eingeben" class="konto-filter"
data-target="zahlungskonto_id" autocomplete="off" style="margin-bottom:.3rem"> data-target="zahlungskonto_id" autocomplete="off" style="margin-bottom:.3rem"
<select id="zahlungskonto_id" name="zahlungskonto_id" required size="4" value="<?= $h($formData['zahlungs_kontonummer'] ?? '') ?>">
<select id="zahlungskonto_id" name="zahlungskonto_id" size="4"
onchange="showKontoArt('zahlungskonto_id','zahlungskonto_art',this)"> onchange="showKontoArt('zahlungskonto_id','zahlungskonto_art',this)">
<option value="">– Konto wählen –</option> <option value="">– Konto wählen –</option>
<?php foreach (['Zahlungskonto', 'Verbindlichkeit'] as $art): ?> <?php foreach (['Zahlungskonto', 'Verbindlichkeit'] as $art): ?>
@ -451,7 +451,7 @@ $suppliers = $suppliers ?? [];
<!-- Bewirtungsfelder (nur bei Konto 4650/4651) --> <!-- Bewirtungsfelder (nur bei Konto 4650/4651) -->
<div id="bewirtungsfelder" style="display:none"> <div id="bewirtungsfelder" style="display:none">
<div class="flash flash-info" style="margin-bottom:.75rem;padding:.5rem .75rem;font-size:.85rem"> <div class="flash flash-info flash-persistent" style="margin-bottom:.75rem;padding:.5rem .75rem;font-size:.85rem">
<strong>Bewirtungsausgabe:</strong> 70 % werden auf das gewählte Konto gebucht, 30 % automatisch auf das Abzugskonto. Die Vorsteuer wird vollständig berücksichtigt. <strong>Bewirtungsausgabe:</strong> 70 % werden auf das gewählte Konto gebucht, 30 % automatisch auf das Abzugskonto. Die Vorsteuer wird vollständig berücksichtigt.
</div> </div>
<div class="form-group"> <div class="form-group">
@ -459,13 +459,13 @@ $suppliers = $suppliers ?? [];
<textarea name="bewirtungsgrund" id="bewirtungsgrund_input" <textarea name="bewirtungsgrund" id="bewirtungsgrund_input"
style="height:2.4em;resize:none;overflow:hidden" style="height:2.4em;resize:none;overflow:hidden"
oninput="this.style.height='auto';this.style.height=this.scrollHeight+'px'" oninput="this.style.height='auto';this.style.height=this.scrollHeight+'px'"
placeholder="Anlass/Grund der Bewirtung"><?= $h($formData['bewirtungsgrund'] ?? '') ?></textarea> placeholder="Anlass/Grund der Bewirtung"><?= $h($formData['bewirtungsgrund'] ?? $beleg['bewirtungsgrund'] ?? '') ?></textarea>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="teilnehmerliste_input">Teilnehmerliste *</label> <label for="teilnehmerliste_input">Teilnehmerliste *</label>
<textarea name="teilnehmerliste" id="teilnehmerliste_input" <textarea name="teilnehmerliste" id="teilnehmerliste_input"
style="height:5.4em;resize:vertical" style="height:5.4em;resize:vertical"
placeholder="Namen der Teilnehmer"><?= $h($formData['teilnehmerliste'] ?? '') ?></textarea> placeholder="Namen der Teilnehmer"><?= $h($formData['teilnehmerliste'] ?? $beleg['teilnehmerliste'] ?? '') ?></textarea>
</div> </div>
</div> </div>
@ -497,8 +497,8 @@ function filterKategorieKonten(buchungstyp) {
groups.forEach(function(g) { groups.forEach(function(g) {
const art = g.getAttribute('data-kontenart'); const art = g.getAttribute('data-kontenart');
if (!art) return; if (!art) return;
// Privat immer anzeigen, Kategorie nach Typ filtern // Privat und Verbindlichkeit immer anzeigen, Kategorie nach Typ filtern
g.style.display = (art === zielArt || art === 'Privat') ? '' : 'none'; g.style.display = (art === zielArt || art === 'Privat' || art === 'Verbindlichkeit') ? '' : 'none';
}); });
// Auswahl zurücksetzen wenn aktuell gewähltes Konto nicht mehr sichtbar // Auswahl zurücksetzen wenn aktuell gewähltes Konto nicht mehr sichtbar
@ -518,8 +518,10 @@ function updateAutoUst() {
const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex]; const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex];
const steuercode = selectedOpt ? (selectedOpt.getAttribute('data-steuercode') || '') : ''; const steuercode = selectedOpt ? (selectedOpt.getAttribute('data-steuercode') || '') : '';
const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : '';
const ustMap = { 'VSt19': '19', 'USt19': '19', 'VSt7': '7', 'USt7': '7' }; const ustMap = { 'VSt19': '19', 'USt19': '19', 'VSt7': '7', 'USt7': '7' };
const autoUst = ustMap[steuercode] || null; // 4652/4657 immer 0 % (keine Vorsteuer bei pauschalen Bewirtungskosten ohne USt-Ausweis)
const autoUst = (['4652','4657'].includes(kontonummer)) ? '0' : (ustMap[steuercode] || null);
const hiddenEl = document.getElementById('ust_satz_hidden'); const hiddenEl = document.getElementById('ust_satz_hidden');
if (autoUst !== null) { if (autoUst !== null) {
@ -543,7 +545,7 @@ function updateBewirtungsState() {
const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex]; const selectedOpt = kategorieEl.options[kategorieEl.selectedIndex];
const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : ''; const kontonummer = selectedOpt ? (selectedOpt.getAttribute('data-kontonummer') || '') : '';
const istBewirtung = kontonummer === '4650' || kontonummer === '4651'; const istBewirtung = ['4650','4651','4652'].includes(kontonummer);
felder.style.display = istBewirtung ? '' : 'none'; felder.style.display = istBewirtung ? '' : 'none';

View file

@ -65,7 +65,7 @@
const fd = new FormData(); const fd = new FormData();
fd.append('beleg_file', file); fd.append('beleg_file', file);
fd.append('belegtyp', 'Eingangsrechnung'); fd.append('belegtyp', 'Eingangsrechnung');
fd.append('eingangs_datum', new Date().toISOString().slice(0,10));
fd.append('beleg_datum', new Date().toISOString().slice(0,10)); fd.append('beleg_datum', new Date().toISOString().slice(0,10));
fetch('/belege/upload', { fetch('/belege/upload', {
@ -132,7 +132,7 @@
<thead> <thead>
<tr> <tr>
<th>Belegnr.</th> <th>Belegnr.</th>
<th>Eingangsdatum</th>
<th>Belegdatum</th> <th>Belegdatum</th>
<th>Lieferant</th> <th>Lieferant</th>
<th>Rechnungsnr.</th> <th>Rechnungsnr.</th>
@ -146,7 +146,7 @@
<?php foreach ($rows as $b): ?> <?php foreach ($rows as $b): ?>
<tr> <tr>
<td><a href="/belege/<?= $h($b['id']) ?>" class="font-mono"><?= $h($b['beleg_nr']) ?></a></td> <td><a href="/belege/<?= $h($b['id']) ?>" class="font-mono"><?= $h($b['beleg_nr']) ?></a></td>
<td class="td-muted"><?= View::formatDate($b['eingangs_datum']) ?></td>
<td class="td-muted"><?= View::formatDate($b['beleg_datum']) ?></td> <td class="td-muted"><?= View::formatDate($b['beleg_datum']) ?></td>
<td class="td-muted"><?= $h($b['supplier_name'] ?? '–') ?></td> <td class="td-muted"><?= $h($b['supplier_name'] ?? '–') ?></td>
<td class="td-muted"><?= $h($b['rechnungs_nr'] ?? '–') ?></td> <td class="td-muted"><?= $h($b['rechnungs_nr'] ?? '–') ?></td>

View file

@ -25,11 +25,7 @@
</select> </select>
</div> </div>
<div class="form-group">
<label for="eingangs_datum">Eingangsdatum *</label>
<input type="date" id="eingangs_datum" name="eingangs_datum"
value="<?= $h($old['eingangs_datum'] ?? date('Y-m-d')) ?>" required>
</div>
</div> </div>
<div class="form-grid form-grid-2"> <div class="form-grid form-grid-2">
@ -46,12 +42,7 @@
</div> </div>
</div> </div>
<div class="form-group">
<label for="betrag_brutto">Bruttobetrag (€)</label>
<input type="number" id="betrag_brutto" name="betrag_brutto"
value="<?= $h($old['betrag_brutto'] ?? '') ?>"
step="0.01" min="0" placeholder="0.00">
</div>
<div class="form-group"> <div class="form-group">
<label for="notes">Notizen</label> <label for="notes">Notizen</label>

View file

@ -115,7 +115,7 @@ $fmt = fn($v) => View::formatMoney($v);
const fd = new FormData(); const fd = new FormData();
fd.append('beleg_file', file); fd.append('beleg_file', file);
fd.append('belegtyp', 'Eingangsrechnung'); fd.append('belegtyp', 'Eingangsrechnung');
fd.append('eingangs_datum', new Date().toISOString().slice(0,10));
fd.append('beleg_datum', new Date().toISOString().slice(0,10)); fd.append('beleg_datum', new Date().toISOString().slice(0,10));
fetch('/belege/upload', { fetch('/belege/upload', {