initial commit

This commit is contained in:
2026-07-22 01:12:45 +02:00
commit 124f2746ac
357 changed files with 159669 additions and 0 deletions
+891
View File
@@ -0,0 +1,891 @@
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
date_default_timezone_set("Europe/Berlin");
require_once "config/config.php";
include("Data.class.php");
$Data = new Data($pdo);
/* ===============================
KALENDER HASH Hybrid Phase 1
=============================== */
function buildCalendarHash(array $termin): string {
$data = [
'start' => (int)$termin['startzeit'],
'end' => (int)$termin['endzeit'],
'title' => trim((string)$termin['location']),
'desc' => trim((string)$termin['beschreibung']),
];
return hash('sha256', json_encode($data));
}
$statusMap = [
"0" => "Offen",
"1" => "Bereit",
"2" => "Erledigt",
"3" => "Storniert"
];
require_once "config/session.php";
if (!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true) {
header("location: index.php");
exit;
}
if(isset($_GET["id"])){
$id = $_GET["id"];
}
if(isset($_POST["id"])){
$id = $_POST["id"];
}
/* ===============================
TERMIN LADEN (für Kalenderstatus)
=============================== */
$stmt = $pdo->prepare("SELECT * FROM termine WHERE id = :id");
$stmt->execute([':id' => $id]);
$termin = $stmt->fetch(PDO::FETCH_ASSOC);
// ===============================
// RECHNUNG ZU DIESEM TERMIN?
// ===============================
$invoice = null;
try {
$stInv = $pdo->prepare("SELECT id, invoice_no FROM invoices WHERE termine_id = :tid ORDER BY id DESC LIMIT 1");
$stInv->execute([':tid' => $id]);
$invoice = $stInv->fetch(PDO::FETCH_ASSOC) ?: null;
} catch (Throwable $e) {
// Falls Tabellen noch nicht existieren oder so: einfach ignorieren
$invoice = null;
}
/* ===============================
KALENDER STATUS BERECHNEN
=============================== */
$currentHash = buildCalendarHash($termin);
if (empty($termin['calendar_event_id'])) {
$calendarStatus = 'missing'; // 🔴
} elseif ($termin['calendar_hash'] !== $currentHash) {
$calendarStatus = 'outdated'; // 🟡
} else {
$calendarStatus = 'ok'; // 🟢
}
$per_page = 5; // Anzahl der Changelog-Einträge pro Seite
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($page < 1) $page = 1;
$offset = ($page - 1) * $per_page;
// Gesamtanzahl Einträge
$count_sql = $pdo->prepare("SELECT COUNT(*) FROM changes WHERE termin_id = :id");
$count_sql->execute([':id' => $id]);
$total_entries = $count_sql->fetchColumn();
$total_pages = ceil($total_entries / $per_page);
// Daten holen
$sql = $pdo->prepare("
SELECT * FROM changes
WHERE termin_id = :id
ORDER BY timestamp DESC
LIMIT :limit OFFSET :offset
");
$sql->bindValue(':id', $id, PDO::PARAM_INT);
$sql->bindValue(':limit', $per_page, PDO::PARAM_INT);
$sql->bindValue(':offset', $offset, PDO::PARAM_INT);
$sql->execute();
$changes = $sql->fetchAll(PDO::FETCH_ASSOC);
if(isset($_POST['save'])){
if(isset($_POST['inputStartzeit_ts']) && !empty($_POST['inputStartzeit_ts'])){
$startzeit = $_POST['inputStartzeit_ts'];
if($Data->getTerminDataById($id, "startzeit") != $startzeit){
$Data->createChanges($id, $_SESSION["id"], "startzeit", $Data->getTerminDataById($id, "startzeit"), $startzeit);
$Data->changeTermin($id, "startzeit", $startzeit);
}
}
if(isset($_POST['inputEndzeit_ts']) && !empty($_POST['inputEndzeit_ts'])){
$endzeit = $_POST['inputEndzeit_ts'];
if($Data->getTerminDataById($id, "endzeit") != $endzeit){
$Data->createChanges($id, $_SESSION["id"], "endzeit", $Data->getTerminDataById($id, "endzeit"), $endzeit);
$Data->changeTermin($id, "endzeit", $endzeit);
}
}
if(isset($_POST['inputLocation'])){
$location = $_POST['inputLocation'];
if($Data->getTerminDataById($id, "location") != $location){
$Data->createChanges($id, $_SESSION["id"], "location", $Data->getTerminDataById($id, "location"), $location);
$Data->changeTermin($id, "location", $location);
}
}
if(isset($_POST['inputGage'])){
$gage = $_POST['inputGage'];
if($Data->getTerminDataById($id, "gage") != $gage){
$Data->createChanges($id, $_SESSION["id"], "gage", $Data->getTerminDataById($id, "gage"), $gage);
$Data->changeTermin($id, "gage", $gage);
}
}
if (isset($_POST['users'])) {
// Neue Daten
$userIDs_new = array_map('intval', $_POST['users']);
$json_new = json_encode($userIDs_new);
// Alte Daten holen und in Array umwandeln
$old_json = $Data->getTerminDataById($id, "anwesend");
$userIDs_old = json_decode($old_json, true);
// Falls alt NULL oder kein Array
if (!is_array($userIDs_old)) {
$userIDs_old = [];
}
// Arrays vergleichen unabhängig von Reihenfolge
if (array_diff($userIDs_old, $userIDs_new) || array_diff($userIDs_new, $userIDs_old)) {
// Changelog schreiben
$Data->createChanges(
$id,
$_SESSION["id"],
"anwesend",
json_encode($userIDs_old),
$json_new
);
// Speichern
$Data->changeTermin($id, "anwesend", $json_new);
}
}
if (isset($_POST['inputBeschreibung'])) {
$beschreibung = trim($_POST['inputBeschreibung']);
if ($Data->getTerminDataById($id, "beschreibung") != $beschreibung) {
$Data->createChanges($id, $_SESSION["id"], "beschreibung", "", "");
$Data->changeTermin($id, "beschreibung", $beschreibung);
}
}
if(isset($_POST['status'])){
$status = $_POST['status'];
if($Data->getTerminDataById($id, "status") != $status){
$Data->createChanges($id, $_SESSION["id"], "status", $Data->getTerminDataById($id, "status"), $status);
$Data->changeTermin($id, "status", $status);
if($status == "3"){
$Data->deleteCalendarEvent($id);
header("location: termin_show.php?id=" . $id);
exit;
}
}
}
$Data->updateCalendarEvent($id);
header("location: termin_show.php?id=" . $id);
exit;
}
include('navbar.php');
?>
<style>
/* ---------- CHANGES TABLE / TIMELINE OPTIMIERUNG ---------- */
.select2-container--classic .select2-selection--multiple {
border-radius: 8px;
padding: 6px;
border-color: #ced4da;
}
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
background: #0d6efd;
color: white;
border: none;
padding: 3px 8px;
border-radius: 6px;
}
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
color: white;
margin-right: 5px;
}
.changelog-table {
border-collapse: separate !important;
border-spacing: 0 12px !important; /* Abstand zwischen den Reihen */
}
.changelog-row {
background: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}
.changelog-date {
font-weight: 600;
color: #444;
white-space: nowrap;
padding-top: 12px !important;
}
.change-entry {
padding: 14px 18px !important;
border-left: 4px solid #0d6efd;
background: #f8f9fa !important;
border-radius: 8px;
font-size: 15px;
line-height: 1.45;
}
.change-entry strong {
color: #000;
}
.change-old {
color: #dc3545 !important;
font-weight: 600;
}
.change-new {
color: #198754 !important;
font-weight: 700;
}
/* Mobile Version */
@media (max-width: 768px) {
.changelog-table {
border-spacing: 0 10px !important;
}
.change-entry {
font-size: 16px;
padding: 16px 16px !important;
}
.changelog-date {
font-size: 14px;
margin-bottom: 4px;
display: block;
}
}
/* MOBILE: Datum/Uhrzeit schmaler machen */
@media (max-width: 768px) {
/* Datum/Uhrzeit-Spalte schmaler */
.changelog-date {
width: 95px !important; /* vorher ~150180px */
font-size: 13px !important; /* leicht verkleinern */
text-align: left;
}
/* Änderungstext bekommt mehr Platz */
.change-entry {
font-size: 15px !important;
padding: 14px 14px !important;
}
/* Tabelle anpassen */
.changelog-table th:first-child {
width: 95px !important;
}
}
</style>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<title>ANJUMA Dashboard</title>
</head>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<div class="container">
<div class="row justify-content-center">
<div class="col-12 col-md-10">
<form action="termin_show.php" method="post">
<div class="row g-3">
<!-- Startzeit (nicht änderbar) -->
<div class="col-md-6">
<label class="form-label fw-bold">Startzeit</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-clock-fill"></i></span>
<input
type="datetime-local"
class="form-control"
id="inputStartzeit"
value="<?php echo date('Y-m-d\TH:i', $Data->getTerminDataById($id, 'startzeit')); ?>"
>
<input type="hidden" name="inputStartzeit_ts" id="inputStartzeit_ts">
</div>
</div>
<!-- Endzeit -->
<div class="col-md-6">
<label class="form-label fw-bold">Endzeit</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-clock-fill"></i></span>
<input
type="datetime-local"
class="form-control"
id="inputEndzeit"
value="<?php echo date('Y-m-d\TH:i', $Data->getTerminDataById($id, 'endzeit')); ?>"
>
<input type="hidden" name="inputEndzeit_ts" id="inputEndzeit_ts">
</div>
</div>
<!-- Location -->
<div class="col-md-6">
<label class="form-label fw-bold">Location</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-geo-alt"></i></span>
<input type="text" class="form-control" name="inputLocation"
value="<?php echo $Data->getTerminDataById($id, 'location') ?>">
</div>
</div>
<!-- Gage -->
<div class="col-md-6">
<label class="form-label fw-bold">Gage</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-cash-stack"></i></span>
<input type="text" class="form-control" name="inputGage"
value="<?php echo $Data->getTerminDataById($id, 'gage') ?>">
</div>
</div>
<!-- Beschreibung -->
<div class="col-12">
<label class="form-label fw-bold">Beschreibung</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-card-text"></i></span>
<textarea
class="form-control"
name="inputBeschreibung"
id="beschreibungField"
rows="1"
style="overflow:hidden; resize:none;"
><?php
echo htmlspecialchars($Data->getTerminDataById($id, 'beschreibung'));
?></textarea>
</div>
</div>
<!-- Beteiligte Personen -->
<div class="col-md-6">
<label class="form-label fw-bold">Anwesend</label>
<select class="form-select select2-users" name="users[]" multiple>
<?php
$userList = $pdo->query("SELECT id, name FROM users ORDER BY name")->fetchAll(PDO::FETCH_ASSOC);
$selectedUsers = json_decode($Data->getTerminDataById($id, "anwesend"), true) ?: [];
foreach ($userList as $u) {
$sel = in_array($u['id'], $selectedUsers) ? "selected" : "";
echo "<option value='{$u['id']}' $sel>{$u['name']}</option>";
}
?>
</select>
</div>
</div>
<!-- Status -->
<div class="btn-group my-4" role="group">
<label class="btn btn-primary">
<input type="radio" name="status" value="0" <?php if($Data->getTerminDataById($id, "status") == 0){ echo "checked"; } ?>> Offen
</label>
<label class="btn btn-warning">
<input type="radio" name="status" value="1" <?php if($Data->getTerminDataById($id, "status") == 1){ echo "checked"; } ?>> Bereit
</label>
<label class="btn btn-success">
<input type="radio" name="status" value="2" <?php if($Data->getTerminDataById($id, "status") == 2){ echo "checked"; } ?>> Abgeschlossen
</label>
<label class="btn btn-danger">
<input type="radio" name="status" value="3" <?php if($Data->getTerminDataById($id, "status") == 3){ echo "checked"; } ?>> Storniert
</label>
</div>
<input type="hidden" name="id" value="<?php echo $id ?>">
<?php if (isset($_SESSION['role']) && $_SESSION['role'] === 'admin'): ?>
<button type="button" class="btn btn-danger ms-3"
data-bs-toggle="modal" data-bs-target="#deleteModal">
<i class="bi bi-trash"></i> Termin löschen
</button>
<?php endif; ?>
<button type="submit" name="save" class="btn btn-primary">
<i class="bi bi-save"></i> Speichern
</button>
<?php
$terminStatus = (int)$Data->getTerminDataById($id, "status");
?>
<?php if ($terminStatus === 2): ?>
<?php if ($invoice): ?>
<a class="btn btn-outline-success ms-3"
href="/api/invoice_pdf.php?id=<?= (int)$invoice['id'] ?>"
target="_blank">
<i class="bi bi-receipt"></i> PDF öffnen (<?= htmlspecialchars($invoice['invoice_no']) ?>)
</a>
<?php else: ?>
<button type="button" class="btn btn-success ms-3" id="btnInvoiceOpen">
<i class="bi bi-receipt"></i> Rechnung erstellen
</button>
<?php endif; ?>
<?php endif; ?>
<!-- ===============================
KALENDER STATUS (Hybrid Phase 1)
=============================== -->
<div class="mb-3">
<?php if ($calendarStatus === 'ok'): ?>
<span class="badge bg-success">
📅 Kalender aktuell
<?php if (!empty($termin['calendar_synced_at'])): ?>
<small>(<?= date('d.m.Y H:i', $termin['calendar_synced_at']) ?>)</small>
<?php endif; ?>
</span>
<?php elseif ($calendarStatus === 'outdated'): ?>
<span class="badge bg-warning text-dark">
📅 Kalender nicht aktuell
</span>
<?php else: ?>
<span class="badge bg-danger">
📅 Kein Kalender-Eintrag
</span>
<?php endif; ?>
</div>
<?php if ($calendarStatus === 'outdated'): ?>
<div class="alert alert-warning py-2">
⚠️ Der Termin wurde geändert, der Kalendereintrag ist nicht mehr aktuell.
</div>
<?php endif; ?>
</form>
</div>
</div>
</div>
<!-- Changelog -->
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-10">
<table class="table changelog-table">
<thead class="table-dark">
<tr>
<th style="width: 180px;">Datum/Uhrzeit</th>
<th>Änderung</th>
</tr>
</thead>
<tbody>
<?php
foreach ($changes as $row) {
$datum = $Data->timestampToDate($row['timestamp']);
$name = $Data->getDataByID($row['user_id'], "name");
$feld = strtoupper($row['was']);
$alt = $row['alt'];
$neu = $row['neu'];
if ($row['was'] === 'anwesend'){
$alt = json_decode($row["alt"], true) ?: [];
$neu = json_decode($row["neu"], true) ?: [];
$alt = array_map(fn($uid) => $Data->getDataByID($uid, "name"), $alt);
$neu = array_map(fn($uid) => $Data->getDataByID($uid, "name"), $neu);
}
if ($row['was'] === 'status') {
$alt = $statusMap[$alt] ?? $alt;
$neu = $statusMap[$neu] ?? $neu;
}
if (in_array($row['was'], ['startzeit','endzeit','realendzeit'])) {
if ($alt > 0) $alt = date('d.m.Y H:i', $alt);
$neu = date('d.m.Y H:i', $neu);
}
echo "<tr class='changelog-row'>
<td class='changelog-date'>$datum</td>
<td>
<div class='change-entry'>";
if ($row['was'] === 'create') {
echo "<strong>$name</strong> hat diesen <strong>Termin</strong> erstellt!";
}
elseif ($row['was'] === 'anwesend') {
echo "<strong>$name</strong> hat <strong>$feld</strong> geändert von
<span class='change-old'>".implode(', ', $alt)."</span>
zu <span class='change-new'>".implode(', ', $neu)."</span>.";
}
elseif ($row['was'] === 'startzeit' && $row['alt'] == 0) {
echo "<strong>$name</strong> hat <strong>STARTZEIT</strong> geändert zu
<span class='change-new'>$neu</span>.";
}
elseif ($row['was'] === 'beschreibung') {
echo "<strong>$name</strong> hat die <strong>Beschreibung</strong> geändert!";
}else{
echo "<strong>$name</strong> hat <strong>$feld</strong> geändert von
<span class='change-old'>$alt</span>
zu <span class='change-new'>$neu</span>.";
}
echo " </div>
</td>
</tr>";
}
?>
</tbody>
</table>
<!-- Pagination -->
<nav>
<ul class="pagination justify-content-center">
<!-- Prev Button -->
<li class="page-item <?php if ($page <= 1) echo 'disabled'; ?>">
<a class="page-link" href="?id=<?php echo $id; ?>&page=<?php echo $page - 1; ?>">
&laquo; Zurück
</a>
</li>
<!-- Seitenzahlen -->
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<li class="page-item <?php if ($i == $page) echo 'active'; ?>">
<a class="page-link" href="?id=<?php echo $id; ?>&page=<?php echo $i; ?>">
<?php echo $i; ?>
</a>
</li>
<?php endfor; ?>
<!-- Next Button -->
<li class="page-item <?php if ($page >= $total_pages) echo 'disabled'; ?>">
<a class="page-link" href="?id=<?php echo $id; ?>&page=<?php echo $page + 1; ?>">
Weiter &raquo;
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<!-- Invoice Modal -->
<div class="modal fade" id="invoiceModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<form class="modal-content" id="invoiceForm">
<div class="modal-header">
<h5 class="modal-title">Rechnung erstellen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
</div>
<div class="modal-body">
<div class="mb-2">
<label class="form-label mb-1">Kunde / Firma *</label>
<input type="text" class="form-control" id="invCustomerName" required placeholder="z.B. Lug Lounge GmbH">
</div>
<div class="mb-2">
<label class="form-label mb-1">Straße & Nr.</label>
<input type="text" class="form-control" id="invStreet" placeholder="Musterstraße 1">
</div>
<div class="row g-2">
<div class="col-5">
<label class="form-label mb-1">PLZ</label>
<input type="text" class="form-control" id="invZip" placeholder="00000">
</div>
<div class="col-7">
<label class="form-label mb-1">Ort</label>
<input type="text" class="form-control" id="invCity" placeholder="Nienburg">
</div>
</div>
<div class="mt-2">
<label class="form-label mb-1">Land</label>
<input type="text" class="form-control" id="invCountry" value="DE">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="submit" class="btn btn-success" id="btnCreateInvoice">Erstellen & PDF</button>
</div>
</form>
</div>
</div>
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Termin löschen?</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Bist du sicher, dass du diesen Termin löschen möchtest?</p>
<ul>
<li>Der Termin wird vollständig entfernt</li>
<li>Alle Änderungen (Changelog) werden gelöscht</li>
<li>Kalendereintrag wird entfernt</li>
</ul>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<form action="termin_delete.php" method="POST">
<input type="hidden" name="id" value="<?= $id ?>">
<button type="submit" class="btn btn-danger">
<i class="bi bi-trash"></i> Ja, löschen
</button>
</form>
</div>
</div>
</div>
</div>
<!-- MODAL: Termin existiert -->
<div class="modal fade" id="terminConflictModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">Achtung Terminüberschneidung!</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Für dieses Datum existiert bereits mindestens ein Termin:</p>
<div id="terminConflictList" class="border rounded p-2 bg-light"></div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">Okay</button>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", () => {
const startInput = document.getElementById("inputStartzeit");
startInput.addEventListener("change", async () => {
if (!startInput.value) return;
// ISO → Timestamp
const ts = Math.floor(new Date(startInput.value).getTime() / 1000);
const res = await fetch(`check_date.php?ts=${ts}`);
const data = await res.json();
if (Array.isArray(data) && data.length > 0) {
let html = "";
data.forEach(t => {
html += `
<div class="p-2 mb-2 bg-white rounded border">
<strong>Termin #${t.id}</strong><br>
Start: ${new Date(t.startzeit * 1000).toLocaleString()}<br>
Location: ${t.location}
</div>
`;
});
document.getElementById("terminConflictList").innerHTML = html;
// Modal anzeigen
const myModal = new bootstrap.Modal(document.getElementById("terminConflictModal"));
myModal.show();
}
});
});
document.addEventListener("DOMContentLoaded", function() {
// Select2 aktivieren
$('.select2-users').select2({
placeholder: "Anwesende auswählen…",
allowClear: true,
width: '100%',
theme: "classic"
});
});
function convertToTimestamp(idInput, idHidden) {
const input = document.getElementById(idInput);
const hidden = document.getElementById(idHidden);
if (input && hidden && input.value) {
const ts = Math.floor(new Date(input.value).getTime() / 1000);
hidden.value = ts;
}
}
document.addEventListener("DOMContentLoaded", () => {
const startzeit = document.getElementById("inputStartzeit");
const endzeit = document.getElementById("inputEndzeit");
const real = document.getElementById("inputRealEndzeit");
if (endzeit) {
endzeit.addEventListener("change", () => {
convertToTimestamp("inputEndzeit", "inputEndzeit_ts");
});
}
if (real) {
real.addEventListener("change", () => {
convertToTimestamp("inputRealEndzeit", "inputRealEndzeit_ts");
});
}
if (startzeit) {
startzeit.addEventListener("change", () => {
convertToTimestamp("inputStartzeit", "inputStartzeit_ts");
});
}
});
function autoResizeTextarea(el) {
el.style.height = 'auto';
el.style.height = (el.scrollHeight) + 'px';
}
document.addEventListener("DOMContentLoaded", function() {
const textarea = document.getElementById("beschreibungField");
if (textarea) {
// Beim Laden automatisch anpassen
autoResizeTextarea(textarea);
// Beim Eingeben automatisch anpassen
textarea.addEventListener('input', function() {
autoResizeTextarea(textarea);
});
}
});
// === Rechnung erstellen (Termin Show) ===
const API_INVOICE_CREATE = '/api/invoice_create_from_termin.php';
const API_INVOICE_PDF = '/api/invoice_pdf.php?id=';
const terminIdForInvoice = <?= (int)$id ?>;
document.addEventListener("DOMContentLoaded", () => {
const btnOpen = document.getElementById("btnInvoiceOpen");
if (!btnOpen) return;
const invoiceModalEl = document.getElementById('invoiceModal');
const invoiceModal = new bootstrap.Modal(invoiceModalEl);
btnOpen.addEventListener('click', () => {
// reset
document.getElementById('invCustomerName').value = '';
document.getElementById('invStreet').value = '';
document.getElementById('invZip').value = '';
document.getElementById('invCity').value = '';
document.getElementById('invCountry').value = 'DE';
invoiceModal.show();
});
document.getElementById('invoiceForm').addEventListener('submit', async (ev) => {
ev.preventDefault();
const cname = document.getElementById('invCustomerName').value.trim();
if (!cname) { alert('Bitte Kunde/Firma eintragen'); return; }
const btn = document.getElementById('btnCreateInvoice');
btn.disabled = true;
btn.textContent = 'Erstelle…';
try {
const fd = new FormData();
fd.append('termin_id', terminIdForInvoice);
fd.append('customer_name', cname);
fd.append('customer_street', document.getElementById('invStreet').value.trim());
fd.append('customer_zip', document.getElementById('invZip').value.trim());
fd.append('customer_city', document.getElementById('invCity').value.trim());
fd.append('customer_country', document.getElementById('invCountry').value.trim() || 'DE');
const res = await fetch(API_INVOICE_CREATE, { method: 'POST', body: fd });
const json = await res.json();
if (!json.ok) throw new Error(json.error || 'Rechnung konnte nicht erstellt werden');
invoiceModal.hide();
// PDF öffnen
window.open(API_INVOICE_PDF + json.invoice_id, '_blank');
// Seite neu laden, damit Button auf "PDF öffnen" wechselt
window.location.reload();
} catch (e) {
alert('Fehler: ' + e.message);
} finally {
btn.disabled = false;
btn.textContent = 'Erstellen & PDF';
}
});
});
</script>