Telefon-Anfragen ohne Personenbezug wieder anzeigen

Seit dem 02.09.2026 legt die Telefonanlage Anfragen mit source='telefon'
an. Von 309 solchen Zeilen haben 207 keine requester_person_id, weil der
Anrufer nicht zugeordnet werden konnte - darunter alle 33 offenen. Saemtliche
Anzeigepfade haengen per INNER JOIN an persons, wodurch genau diese Zeilen
kommentarlos aus dem Ergebnis fielen. Die Ansicht "Unbeantwortete Anfragen"
zeigte dadurch 2 statt 35 Eintraege.

Bei mail- und portal-Anfragen konnte das nicht auffallen: die Formulare
legen die Person vorher in persons an und brechen sonst ab (rezepte.php),
entsprechend hat dort keine einzige Zeile eine fehlende Person. personid
und userid stehen zwar auch bei mail auf 0, sind aber tote Legacy-Spalten
und tragen den Personenbezug nicht.

Die Anzeigepfade verwenden jetzt LEFT JOIN und zeigen ohne Treffer
"Kein Patient zugeordnet" statt einer leeren Zeile: Liste, Antworten,
Loesch-Dialog, Loeschen ohne Mail und Antwort einsehen. Die beiden Knoepfe,
die zwingend eine Mailadresse brauchen - Antworten und Loeschen mit Mail -
erscheinen nur noch mit zugeordneter Person; wer das Antwortformular direkt
aufruft, bekommt einen Hinweis samt Transkript statt eines Abbruchs.
"Telefonisch beantwortet" brauchte keine Aenderung, dieser Weg fragt nur
die anfrageid ab.

Der Mailversand in functions.inc.php und die patientenbezogene Historie
behalten ihren INNER JOIN - dort ist eine Person Voraussetzung.

Neu ist GetAnfrageHerkunft(). Die Liste leitete die Herkunft bisher aus
sicherenachricht ab, was Telefonanfragen mangels Wert als "Mailanfrage"
etikettierte. Nur dieser dritte Fall kommt aus source. Die Unterscheidung
intern/Mail bleibt bewusst an sicherenachricht haengen, weil insertAnfrage()
kein source setzt und 304 interne Anfragen deshalb als source='mail' in der
Tabelle stehen; ueber source vergeben haette das Label 9871 Bestandszeilen
umetikettiert, darunter die datenschutzrelevante Unterscheidung.

Nachgeprueft gegen die Datenbank: die Ansicht liefert statt 2 nun 35 Zeilen
mit allen 33 offenen Telefon-Anfragen. Der Renderblock ueber alle 12784
Zeilen simuliert, error_reporting=E_ALL als Exception, ohne Warnung; das
Herkunfts-Label bleibt fuer 12475 Bestandszeilen unveraendert und aendert
sich nur fuer die 309 Telefon-Zeilen. Alle fuenf von der Liste erreichbaren
Aktionen laden fuer eine Zeile ohne Person.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 12:56:45 +02:00
co-authored by Claude Opus 5
parent 6d903ac4fc
commit f19c490f44
2 changed files with 90 additions and 25 deletions
+68 -25
View File
@@ -115,8 +115,8 @@ if(!check_worker()){
p.ort, p.plz, p.strasse, p.ort, p.plz, p.strasse,
aa.artname aa.artname
FROM anfragen a FROM anfragen a
JOIN persons p ON a.requester_person_id = p.person_id LEFT JOIN persons p ON a.requester_person_id = p.person_id
JOIN anfrageart aa ON a.anforderungart = aa.artid LEFT JOIN anfrageart aa ON a.anforderungart = aa.artid
"; ";
$params = []; $params = [];
@@ -201,16 +201,18 @@ if(!check_worker()){
$dateiname = e((string)$row["dateiname"]); $dateiname = e((string)$row["dateiname"]);
$anfrageart = e((string)$row["artname"]); // artname kann seit dem LEFT JOIN leer sein.
$anfrageart = e((string)($row["artname"] ?? ""));
if($anfrageart === ""){
$anfrageart = "unbekannte Art";
}
$ordnungsid = $row["ordnungsid"]; $ordnungsid = $row["ordnungsid"];
$ordnungsstring = GetOrdnungsid($ordnungsid); $ordnungsstring = GetOrdnungsid($ordnungsid);
$WeitereInfos= ""; $WeitereInfos= "";
$sicherenachricht = $row["sicherenachricht"]; $sicherenachricht = $row["sicherenachricht"];
if($sicherenachricht == "1"){ // Telefonanfragen liessen sicherenachricht NULL und wurden
$WeitereInfos .= "Interne Anfrage<br>"; // dadurch faelschlich als Mailanfrage etikettiert.
}else{ $WeitereInfos .= GetAnfrageHerkunft($row["source"] ?? "mail", $sicherenachricht) . "<br>";
$WeitereInfos .= "Mailanfrage<br>";
}
if($medikamenteins){ if($medikamenteins){
$WeitereInfos .= "Medikament1: $medikamenteins<br>"; $WeitereInfos .= "Medikament1: $medikamenteins<br>";
} }
@@ -244,17 +246,34 @@ if(!check_worker()){
$farbe = GetStatusFarbe($checked); $farbe = GetStatusFarbe($checked);
$checkausgabe = GetStatus($checked); $checkausgabe = GetStatus($checked);
$userausgabe = $vorname . " " . $nachname . "<br>" . $ausgabegeburstag; // Ohne Treffer im LEFT JOIN gibt es keine Personendaten -
$adresse = $plz . " " . $ort . "<br>" . $strasse ; // typisch fuer Telefonanfragen, deren Anrufer nicht zugeordnet
$adresse = $adresse; // werden konnte. Frueher fielen diese Zeilen durch den INNER
echo "<tr style='background-color:". $farbe. ";'><td>$userausgabe <br> $mail <br>Tel:<a href='tel:".$tel."'>$tel</a></td><td>$adresse</td><td>$ordnungsstring - $anfrageart <br>$WeitereInfos</td><td>$datumausgabe</td><td>$update_time<br>$checkausgabe<br>$ausgabeworker</td><td> // JOIN komplett aus der Liste.
$hatPerson = ($row["vorname"] !== null || $row["nachname"] !== null);
if($hatPerson){
$userausgabe = $vorname . " " . $nachname . "<br>" . $ausgabegeburstag;
$adresse = $plz . " " . $ort . "<br>" . $strasse ;
$kontakt = "$mail <br>Tel:<a href='tel:$tel'>$tel</a>";
}else{
$userausgabe = "<i>Kein Patient zugeordnet</i>";
$adresse = "-";
$kontakt = "<i>Kontaktdaten siehe Nachricht</i>";
}
echo "<tr style='background-color:". $farbe. ";'><td>$userausgabe <br> $kontakt</td><td>$adresse</td><td>$ordnungsstring - $anfrageart <br>$WeitereInfos</td><td>$datumausgabe</td><td>$update_time<br>$checkausgabe<br>$ausgabeworker</td><td>";
// "Antworten" verschickt eine Mailvorlage. Ohne zugeordnete Person
// gibt es keine Adresse, der Knopf wuerde ins Leere laufen.
if($hatPerson){
echo "
<div style='float: left;margin:15px; height: 20px;'> <div style='float: left;margin:15px; height: 20px;'>
<form action='". self_action() ."' method=POST> <form action='". self_action() ."' method=POST>
<input type=hidden name=aktion value=2> <input type=hidden name=aktion value=2>
<input type=hidden name=anfrageid value=$anfrageid> <input type=hidden name=anfrageid value=$anfrageid>
<input type=submit class='btn btn-primary' value='Antworten'> <input type=submit class='btn btn-primary' value='Antworten'>
</form> </form>
</div> </div>";
}
echo "
<div style='float: left;margin:15px; height: 20px;'> <div style='float: left;margin:15px; height: 20px;'>
<form action='". self_action() ."' method=POST> <form action='". self_action() ."' method=POST>
<input type=hidden name=aktion value=20> <input type=hidden name=aktion value=20>
@@ -308,8 +327,8 @@ if(!check_worker()){
p.ort, p.plz, p.strasse, p.ort, p.plz, p.strasse,
aa.artname aa.artname
FROM anfragen a FROM anfragen a
INNER JOIN persons p ON a.requester_person_id = p.person_id LEFT JOIN persons p ON a.requester_person_id = p.person_id
INNER JOIN anfrageart aa ON a.anforderungart = aa.artid LEFT JOIN anfrageart aa ON a.anforderungart = aa.artid
WHERE a.anfrageid = ? WHERE a.anfrageid = ?
LIMIT 1 LIMIT 1
"; ";
@@ -323,6 +342,24 @@ if(!check_worker()){
exit; exit;
} }
// Ohne zugeordnete Person gibt es keine Mailadresse - die
// Antwortvorlagen unten wuerden ins Leere laufen. Betrifft vor
// allem Telefonanfragen ohne erkannten Anrufer.
if ($row["vorname"] === null && $row["nachname"] === null) {
echo "<div class='alert alert-warning' role='alert'>";
echo "<b>Dieser Anfrage ist kein Patient zugeordnet.</b><br>";
echo "Herkunft: " . e(GetAnfrageHerkunft($row["source"] ?? "mail", $row["sicherenachricht"] ?? null)) . "<br>";
echo "Eine Antwort per Mail ist deshalb nicht moeglich. ";
echo "Bitte telefonisch beantworten und die Anfrage anschliessend ";
echo "ueber <b>Telefonisch beantwortet</b> abschliessen.";
echo "</div>";
echo "<b>Nachricht:</b><br>" . nl2br(e((string)$row["nachricht"])) . "<br><br>";
ZuruckzumAnfrageOverView();
echo "</form>";
include(__DIR__ . "/templates/footer.inc.php");
exit;
}
// Ticket und Antwort ansehen. // Ticket und Antwort ansehen.
$abholort = $row["abholort"] ?? null; $abholort = $row["abholort"] ?? null;
$sicherenachricht = $row["sicherenachricht"] ?? null; $sicherenachricht = $row["sicherenachricht"] ?? null;
@@ -858,7 +895,7 @@ if(!check_worker()){
$stmt = $pdo->prepare(" $stmt = $pdo->prepare("
SELECT * SELECT *
FROM anfragen a FROM anfragen a
INNER JOIN persons p ON p.person_id = a.requester_person_id LEFT JOIN persons p ON p.person_id = a.requester_person_id
WHERE a.anfrageid = :anfrageid WHERE a.anfrageid = :anfrageid
LIMIT 1 LIMIT 1
"); ");
@@ -875,16 +912,22 @@ if(!check_worker()){
$vorname = $rowtime["vorname"]; $vorname = $rowtime["vorname"];
$nachname = $rowtime["nachname"]; $nachname = $rowtime["nachname"];
$userausgabe = $vorname . " " . $nachname; // Telefonanfragen ohne erkannten Anrufer haben keine Person.
$hatPerson = ($vorname !== null || $nachname !== null);
$userausgabe = $hatPerson ? ($vorname . " " . $nachname) : "Kein Patient zugeordnet";
echo "Name:<br>$userausgabe<br>Anforderung: $impfstofftext<br>"; echo "Name:<br>$userausgabe<br>Anforderung: $impfstofftext<br>";
echo "Wollen Sie wirklich diesen Eintrag löschen?<br>Dieses ist nicht rückgängig zu machen!<br>Dann bestätigen Sie die Abmeldung:<br>"; echo "Wollen Sie wirklich diesen Eintrag löschen?<br>Dieses ist nicht rückgängig zu machen!<br>Dann bestätigen Sie die Abmeldung:<br>";
echo "<form action='". self_action() . "' method=POST>"; // Loeschen mit Mail setzt eine Mailadresse voraus.
echo '<input type="hidden" name="aktion" id="aktion" value="9" />'; if ($hatPerson) {
echo '<input type="hidden" name="anfrageid" id="anfrageid" value="'. $anfrageid .'" /><br>'; echo "<form action='". self_action() . "' method=POST>";
echo '<input type="submit" class="btn btn-primary" id="submitbox" value="Anforderung löschen (mit Mail)" />'; echo '<input type="hidden" name="aktion" id="aktion" value="9" />';
echo "<br>"; echo '<input type="hidden" name="anfrageid" id="anfrageid" value="'. $anfrageid .'" /><br>';
echo '<input type="submit" class="btn btn-primary" id="submitbox" value="Anforderung löschen (mit Mail)" />';
echo "</form>";
echo "<br>";
}
echo "<form action='". self_action() . "' method=POST>"; echo "<form action='". self_action() . "' method=POST>";
echo '<input type="hidden" name="aktion" id="aktion" value="10" />'; echo '<input type="hidden" name="aktion" id="aktion" value="10" />';
echo '<input type="hidden" name="anfrageid" id="anfrageid" value="'. $anfrageid .'" /><br>'; echo '<input type="hidden" name="anfrageid" id="anfrageid" value="'. $anfrageid .'" /><br>';
@@ -971,7 +1014,7 @@ if(!check_worker()){
p.tele, p.tele,
p.geburtstag p.geburtstag
FROM anfragen a FROM anfragen a
INNER JOIN persons p ON p.person_id = a.requester_person_id LEFT JOIN persons p ON p.person_id = a.requester_person_id
WHERE a.anfrageid = :anfrageid WHERE a.anfrageid = :anfrageid
LIMIT 1 LIMIT 1
"); ");
@@ -1051,8 +1094,8 @@ if(!check_worker()){
aa.artname AS anfrageart_name aa.artname AS anfrageart_name
FROM anfragen a FROM anfragen a
INNER JOIN persons p ON p.person_id = a.requester_person_id LEFT JOIN persons p ON p.person_id = a.requester_person_id
INNER JOIN anfrageart aa ON a.anforderungart = aa.artid LEFT JOIN anfrageart aa ON a.anforderungart = aa.artid
WHERE a.anfrageid = :anfrageid WHERE a.anfrageid = :anfrageid
LIMIT 1 LIMIT 1
"); ");
+22
View File
@@ -611,6 +611,28 @@ function GetOrdnungsid($wert){
} }
/**
* Herkunft einer Anfrage als Text.
*
* Nur der Fall "telefon" kommt aus anfragen.source. Die Unterscheidung
* intern/Mail bleibt bewusst an sicherenachricht haengen: source="portal"
* ist dafuer unbrauchbar, weil insertAnfrage() kein source setzt und interne
* Anfragen deshalb als source="mail" in der Tabelle stehen.
* Seit 02.09.2026 legt die Telefonanlage Anfragen mit source="telefon" an;
* diese haben oft keine requester_person_id, weil der Anrufer nicht
* zugeordnet werden konnte.
*/
function GetAnfrageHerkunft($source, $sicherenachricht){
if($source == "telefon"){
$text = "Telefonanfrage";
}else if($sicherenachricht == "1"){
$text = "Interne Anfrage";
}else{
$text = "Mailanfrage";
}
return $text;
}
function GetPatientenartName($Patientenart){ function GetPatientenartName($Patientenart){
if($Patientenart == "0"){ if($Patientenart == "0"){
$impfenangebot = "Neupatient"; $impfenangebot = "Neupatient";