Files
adminandClaude Opus 5 3dfbf1c9c7 Kunden und Adressen auf Prepared Statements umgebaut
incs/saveNchange.php neu geschrieben: Adressen, Telefonnummern, Kontakte,
Notizen und Konten laufen ueber db_abfrage() mit Platzhaltern, mehrschrittiges
Speichern in einer Transaktion. Weil sich die Speicherfunktionen gegenseitig
aufrufen, klammern beginneSpeichern()/beendeSpeichern() die Verschachtelung;
incs/rechnung.php nutzt sie ebenfalls.

Kunden- und Lieferantenseiten waren zwei fast gleiche Kopien und teilen sich
jetzt partnerAddSeite(), partnerChangeSeite() und partnerShowDaten().

Dabei behoben:
- SQL-Injektion ueber die Suchbegriffe der Kunden-, Lieferanten-, Adress-,
  Kommissions- und Projektsuche sowie ueber die Artikel-Autovervollstaendigung
- gespeichertes XSS: Notizen (nl2br escapt nicht), Bankname, Dokumenttyp,
  Namen und Adressen in allen Trefferlisten
- sites/liefershow.php war unter PHP 8 ein Fatal ($kdnres.id)
- "Telefonnummer loeschen" im Kundenbereich lief in einen Fatal, die Nummern
  einer geloeschten Adresse blieben stehen (Spalte hiess adress_id statt
  adresse_id, mysql_fetch_assoc gibt es nicht mehr)
- Geburtstag ohne Jahr wurde im Formular verschluckt, die IBAN kam beim
  Bearbeiten aus $_GET statt aus dem Konto
- die Versionskette eines Kunden brach nach einem Schritt ab
- Kommissionsadressen speicherten die Ortsangabe der Adresse statt der des
  Telefonformulars und einen Adresstyp als Telefontyp
- Blaettern in den Trefferlisten: ohne ORDER BY konnte dieselbe Zeile zweimal
  oder gar nicht erscheinen; ajax_searchadress() bekam die Seite nicht
- Hauptadresse laesst sich nicht mehr loeschen, Kundendaten nicht mehr ueber
  die Lieferantenseite (und umgekehrt)
- ajax/auto/* baute JSON von Hand zusammen, ein Anfuehrungszeichen im Ort
  machte die Liste unbrauchbar

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 19:47:01 +02:00

1347 lines
51 KiB
PHP

<?php
/*
* Kunden, Lieferanten und alles, was an ihnen hängt: Adressen, Telefon-
* nummern, Kontaktmöglichkeiten, Notizen und Bankverbindungen.
*
* Kunden (partner.typ_id = 1) und Lieferanten (partner.typ_id = 2) sind
* dieselben Datensätze mit unterschiedlichem Typ. Die Seiten in sites/
* unterscheiden sich deshalb nur noch in diesem Typ und rufen hier die
* gemeinsamen Funktionen auf.
*/
require_once(__DIR__."/db.php");
/* ---------------------------------------------------------------------
* Formularwerte
*
* Liegen hier statt im Rechnungsmodul, weil das Rechnungsmodul diese Datei
* einbindet, nicht umgekehrt.
* ------------------------------------------------------------------ */
/* Getrimmter Text aus $_POST, fehlend oder kein Text ergibt "" */
function formularText($name)
{
return isset($_POST[$name]) && is_string($_POST[$name]) ? trim($_POST[$name]) : "";
}
/*
* Zahl aus $_POST in deutscher Schreibweise. Steht ein Komma darin, ist es
* der Dezimaltrenner und Punkte sind Tausendertrenner ("1.234,50"). Ohne
* Komma gilt ein Punkt als Dezimaltrenner ("12.50", so liefert ihn die
* Artikel-Autovervollständigung). Leere oder ungültige Eingaben werden 0 -
* so hat sie der frühere, nicht strikte Modus gespeichert.
*/
function formularZahl($name)
{
$wert = str_replace(" ", "", formularText($name));
if(str_contains($wert, ","))
$wert = str_replace(array(".", ","), array("", "."), $wert);
return is_numeric($wert) ? $wert : "0";
}
/* Ganzzahl aus $_POST, gerundet wie MariaDB beim Speichern */
function formularGanzzahl($name)
{
return (int)round((float)formularZahl($name));
}
/* Ganzzahl aus der URL ($_GET), fehlend oder unbrauchbar ergibt 0 */
function parameterGanzzahl($name)
{
return isset($_GET[$name]) && is_scalar($_GET[$name]) ? (int)$_GET[$name] : 0;
}
/*
* Geburtsdatum aus dem Formular als Datum für die Datenbank.
*
* Die Spalte ist NOT NULL, deshalb gibt es zwei Ersatzwerte: Ohne Angabe
* steht der 01.01.2100 für "kein Geburtstag bekannt", eine Angabe ohne
* Jahr ("24.12.") bekommt das Jahr 2099. Die Anzeige erkennt beides wieder
* (siehe geburtstagAnzeigen()). Unbrauchbare Eingaben zählen als fehlend;
* der strikte Modus würde sie sonst als Fehler abweisen.
*/
function formularGeburtsdatum($name)
{
$wert = rtrim(formularText($name), ".");
if($wert === "")
return "2100-01-01";
if(substr_count($wert, ".") < 2)
$wert .= ".2099";
$datum = DateTime::createFromFormat("!d.m.Y", $wert);
$fehler = DateTime::getLastErrors();
if(!$datum || ($fehler && ($fehler["warning_count"] || $fehler["error_count"])))
return "2100-01-01";
return $datum->format("Y-m-d");
}
/*
* Gegenstück zu formularGeburtsdatum(): "" wenn kein Geburtstag hinterlegt
* ist, "24.12." wenn nur Tag und Monat bekannt sind, sonst das volle Datum.
*/
function geburtstagAnzeigen($datum)
{
if(!$datum || $datum == "01.01.2100" || $datum == "00.00.0000")
return "";
if(substr($datum, 6, 4) == "2099")
return substr($datum, 0, 5);
return $datum;
}
/* ---------------------------------------------------------------------
* Änderungsprotokoll
* ------------------------------------------------------------------ */
/*
* $qrystr und $undoqry sind reiner Text zur Nachvollziehbarkeit (siehe
* db_sql_text()), sie werden nie ausgeführt. $type ist ein Eintrag aus
* accesstype ("anlegen", "ändern", "löschen").
*/
function saveLog($dbconn,$qrystr,$undoqry,$type)
{
$err = 0;
$typId = db_wert($dbconn, "SELECT id FROM accesstype WHERE typ = ?", array($type));
if($typId === false)
return error("Fehler beim Eintragen der Aktion in die LOG:<br />".mysqli_error($dbconn));
db_abfrage($dbconn, "INSERT INTO log SET typ_id = ?, datetime = NOW(), qry = ?, undo_qry = ?, user_id = ?",
array((int)$typId, $qrystr, $undoqry, $_SESSION["user"]))
or $err = error("Fehler beim LOGGEN der Aktion:<br />".mysqli_error($dbconn));
return $err;
}
/* ---------------------------------------------------------------------
* Transaktionen
*
* Die Speicherfunktionen rufen sich gegenseitig auf (savePart ->
* saveAdress -> updateKunde -> saveAdress), MariaDB kennt aber keine
* geschachtelten Transaktionen. Deshalb zählt ein Zähler die Verschachtelung
* mit: nur der äußerste Aufruf öffnet und schließt wirklich.
* ------------------------------------------------------------------ */
function transaktionsTiefe($aenderung = 0)
{
static $tiefe = 0;
$tiefe += $aenderung;
return $tiefe;
}
function beginneSpeichern($dbconn)
{
if(transaktionsTiefe() == 0)
mysqli_begin_transaction($dbconn);
transaktionsTiefe(1);
}
/* Gibt $err unverändert zurück, damit sich der Aufruf ans return anhängen lässt */
function beendeSpeichern($dbconn, $err)
{
transaktionsTiefe(-1);
if(transaktionsTiefe() > 0)
return $err;
if($err)
mysqli_rollback($dbconn);
else
mysqli_commit($dbconn);
return $err;
}
/* ---------------------------------------------------------------------
* Stammdaten: Land, Ort, Straße, Bank
*
* Diese Tabellen wachsen beim Erfassen mit. Gibt es den Eintrag schon, wird
* er wiederverwendet, sonst angelegt und protokolliert.
* ------------------------------------------------------------------ */
/*
* $spalten sind die Werte, die den Eintrag eindeutig machen. $kontext
* landet im Protokolltext ("beim adresse anlegen"). Rückgabe ist die id
* oder false bei Fehlern.
*/
function findeOderLege($dbconn, $tabelle, $spalten, $kontext)
{
$bedingung = array();
$zuweisung = array();
foreach(array_keys($spalten) as $spalte)
{
$bedingung[] = "`$spalte` = ?";
$zuweisung[] = "`$spalte` = ?";
}
$werte = array_values($spalten);
$id = db_wert($dbconn, "SELECT id FROM `$tabelle` WHERE ".implode(" AND ", $bedingung), $werte);
if($id === false)
{
error("Fehler beim suchen in $tabelle:<br />".mysqli_error($dbconn));
return false;
}
if($id !== null)
return $id;
$sql = "INSERT INTO `$tabelle` SET ".implode(", ", $zuweisung);
if(!db_abfrage($dbconn, $sql, $werte))
{
error("Fehler beim anlegen in $tabelle:<br />".mysqli_error($dbconn));
return false;
}
$id = mysqli_insert_id($dbconn);
if(saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [hat ID $id ($kontext)]", "DELETE FROM `$tabelle` WHERE id = $id", "anlegen"))
return false;
return $id;
}
function landId($dbconn, $land, $kontext)
{
return findeOderLege($dbconn, "land", array("land" => $land), $kontext);
}
function ortId($dbconn, $land_id, $ort, $plz, $ortsteil, $kontext)
{
return findeOderLege($dbconn, "ort", array("land_id" => $land_id, "ort" => $ort, "plz" => $plz, "ortsteil" => $ortsteil), $kontext);
}
function strasseId($dbconn, $ort_id, $str, $kontext)
{
return findeOderLege($dbconn, "strasse", array("ort_id" => $ort_id, "str" => $str), $kontext);
}
function bankId($dbconn, $bank, $blz, $kontext)
{
return findeOderLege($dbconn, "bank", array("bank" => $bank, "blz" => $blz), $kontext);
}
/*
* Land, Ort und Straße in einem Zug. $ortsangabe enthält land, ort, plz,
* ortsteil und (optional) str. Rückgabe ist array(land_id, ort_id, str_id)
* oder false bei Fehlern; ohne str bleibt str_id 0.
*/
function ortsangabeIds($dbconn, $ortsangabe, $kontext)
{
$land_id = landId($dbconn, $ortsangabe["land"], $kontext);
if($land_id === false)
return false;
$ort_id = ortId($dbconn, $land_id, $ortsangabe["ort"], $ortsangabe["plz"], $ortsangabe["ortsteil"], $kontext);
if($ort_id === false)
return false;
$str_id = 0;
if(isset($ortsangabe["str"]))
{
$str_id = strasseId($dbconn, $ort_id, $ortsangabe["str"], $kontext);
if($str_id === false)
return false;
}
return array($land_id, $ort_id, $str_id);
}
/* Auswahlliste für html_options: array(ids, Texte) */
function auswahlliste($dbconn, $sql, $params = array())
{
$zuordnung = db_zuordnung($dbconn, $sql, $params);
if($zuordnung === false)
return array(array(), array());
return array(array_keys($zuordnung), array_values($zuordnung));
}
//##############################################
//########## ADRESSEN ######################
//##############################################
/* Die Adressfelder aus newadress.tpl bzw. newpar.tpl */
function adressFormularwerte()
{
return array(
"firma" => formularText("firma"),
"vname" => formularText("vname"),
"nname" => formularText("nname"),
"vname2" => formularText("vname2"),
"nname2" => formularText("nname2"),
"anrede_id" => formularGanzzahl("anrede"),
"titel_id" => formularGanzzahl("titel"),
"anrede2_id" => formularGanzzahl("anrede2"),
"titel2_id" => formularGanzzahl("titel2"),
"hnr" => formularText("hnr"),
"zusatz" => formularText("zusatz"),
"gebdat" => formularGeburtsdatum("gebdat"),
"gebdat2" => formularGeburtsdatum("gebdat2"),
);
}
/*
* Adresse anlegen oder ändern.
*
* Drei Fälle:
* - bestehende Adresse und "überschreiben": die Adresse wird geändert,
* alte Rechnungen zeigen danach auf den neuen Stand.
* - Hauptadresse (typ 1) ohne "überschreiben": es entsteht eine neue
* Version des Kunden (updateKunde()), alte Rechnungen behalten die alte.
* - sonst: neue Adresse.
*
* $kunde, $typ und $adressid überschreiben die Werte aus der Anfrage -
* savePart() und updateKunde() legen darüber die Hauptadresse eines frisch
* angelegten Partners an.
*/
function saveAdress($dbconn, $kunde = null, $typ = null, $adressid = null)
{
$adressid = $adressid === null ? parameterGanzzahl("adressid") : (int)$adressid;
$kunde = $kunde === null ? parameterGanzzahl("kunde") : (int)$kunde;
$typ_id = $typ === null ? formularGanzzahl("typ") : (int)$typ;
$ueberschreiben = formularGanzzahl("overwrite") != 0;
$err = 0;
if($adressid && $ueberschreiben)
{
message("Adresse wird geändert...");
$act = "ändern";
}
elseif($adressid)
{
message("Neue Adresse (update)...");
$act = "update";
$updatedBy = db_wert($dbconn, "SELECT updated_by FROM partner WHERE id = ?", array($kunde));
if($updatedBy === false)
$err = error("Fehler testen auf aktualität:<br />".mysqli_error($dbconn));
elseif($updatedBy)
$err = error("Eine solche Adressänderung kann nur mit der aktuellsten Version des Kunden durchgeführt werden.<br />Bitte wechseln Sie zur aktuellsten Version und führen Sie die gewünschen Änderungen dort durch.");
}
else
{
message("Adresse wird angelegt...");
$act = "anlegen";
}
if($err)
return $err;
beginneSpeichern($dbconn);
$ids = ortsangabeIds($dbconn, array(
"land" => formularText("land"),
"ort" => formularText("ort"),
"plz" => formularText("plz"),
"ortsteil" => formularText("oteil"),
"str" => formularText("str"),
), "beim adresse $act");
if($ids === false)
return beendeSpeichern($dbconn, 1);
list($land_id, $ort_id, $str_id) = $ids;
$felder = array_merge(array("str_id" => $str_id, "typ_id" => $typ_id), adressFormularwerte());
$zuweisung = array();
foreach(array_keys($felder) as $spalte)
$zuweisung[] = "`$spalte` = ?";
$set = implode(", ", $zuweisung);
if($adressid && $ueberschreiben)
{
$alt = db_zeile($dbconn, "SELECT * FROM adresse WHERE id = ?", array($adressid));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim ändern der Adresse:<br />".mysqli_error($dbconn)));
$sql = "UPDATE adresse SET $set WHERE id = ?";
$werte = array_merge(array_values($felder), array($adressid));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim ändern der Adresse:<br />".mysqli_error($dbconn)));
$altWerte = array();
foreach(array_keys($felder) as $spalte)
$altWerte[] = $alt[$spalte];
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [adresse change]",
db_sql_text($dbconn, $sql, array_merge($altWerte, array($adressid))), "ändern");
}
elseif($typ_id != 1 || !$adressid)
{
$sql = "INSERT INTO adresse SET $set, partner_id = ?";
$werte = array_merge(array_values($felder), array($kunde));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim Anlegen der Adresse:<br />".mysqli_error($dbconn)));
$adressid = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $adressid]",
"DELETE FROM adresse WHERE id = $adressid", "anlegen");
}
else
{
// Hauptadresse ändern heißt: neue Version des Kunden anlegen
return beendeSpeichern($dbconn, updateKunde($dbconn, $kunde));
}
/*
* Kommissionsadressen (typ 5) haben eine eigene Telefonnummer, die im
* selben Formular steht. Wird der Typ zurückgestellt, fällt sie weg.
*/
if(!$err && $adressid)
{
if($typ_id != 5)
{
db_abfrage($dbconn, "DELETE FROM tel WHERE adresse_id = ?", array($adressid))
or $err = error("Fehler beim löschen der Telefonnummer der Adresse:<br />".mysqli_error($dbconn));
}
elseif(formularText("nr") !== "")
{
$telid = db_wert($dbconn, "SELECT id FROM tel WHERE adresse_id = ? ORDER BY id LIMIT 1", array($adressid));
if($telid === false)
$err = error("Fehler beim suchen der Telefonnummer der Adresse:<br />".mysqli_error($dbconn));
else
$err = speichereTelefon($dbconn, array(
"telid" => (int)$telid,
"adresse_id" => $adressid,
"partner_id" => $kunde,
// newadress.tpl kennt keine Typauswahl für die Nummer
"typ_id" => 1,
"name" => "",
"nr" => formularText("nr"),
"vwahl" => formularText("vwahl"),
"land" => formularText("telland"),
"ort" => formularText("telort"),
"plz" => formularText("telplz"),
"ortsteil" => formularText("teloteil"),
));
}
}
return beendeSpeichern($dbconn, $err);
}
function dispAdressForm($dbconn,$smarty,$typ=1)
{
$adressid = parameterGanzzahl("adressid");
$kunde = parameterGanzzahl("kunde");
if(!$adressid)
{
$smarty->assign("head","Neue Adresse anlegen");
// Firma, Anrede und Namen der Hauptadresse als Vorbelegung
$res = db_zeile($dbconn, "SELECT anrede_id, titel_id, firma, vname, nname, vname2, nname2
FROM adresse
WHERE adresse.partner_id = ? AND adresse.typ_id = 1", array($kunde));
}
else
{
$smarty->assign("head","Adresse ändern");
$res = db_zeile($dbconn, "SELECT anrede_id, zusatz, titel_id, anrede2_id, titel2_id,
DATE_FORMAT(gebdat,'%d.%m.%Y') AS gebdat, DATE_FORMAT(gebdat2,'%d.%m.%Y') AS gebdat2,
firma, vname, nname, vname2, nname2, str, hnr, ort, ortsteil, plz, land, typ_id, partner_id
FROM adresse
JOIN strasse ON strasse.id = adresse.str_id
JOIN ort ON strasse.ort_id = ort.id
JOIN land ON land.id = ort.land_id
WHERE adresse.id = ?", array($adressid));
}
if($res === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if(!$res)
$res = array();
if(!empty($res["partner_id"]))
$kunde = $res["partner_id"];
foreach(array("firma","vname","nname","vname2","nname2","ort","plz","hnr","land","str","zusatz") as $feld)
$smarty->assign($feld, isset($res[$feld]) ? $res[$feld] : "");
$smarty->assign("titel", isset($res["titel_id"]) ? $res["titel_id"] : "");
$smarty->assign("anrede", isset($res["anrede_id"]) ? $res["anrede_id"] : "");
$smarty->assign("titel2", isset($res["titel2_id"]) ? $res["titel2_id"] : "");
$smarty->assign("anrede2", isset($res["anrede2_id"]) ? $res["anrede2_id"] : "");
$smarty->assign("oteil", isset($res["ortsteil"]) ? $res["ortsteil"] : "");
$smarty->assign("typ", isset($res["typ_id"]) ? $res["typ_id"] : "");
$smarty->assign("gebdat", geburtstagAnzeigen(isset($res["gebdat"]) ? $res["gebdat"] : ""));
$smarty->assign("gebdat2", geburtstagAnzeigen(isset($res["gebdat2"]) ? $res["gebdat2"] : ""));
// Telefonnummer einer Kommissionsadresse: eigene Felder im Formular
$telres = db_zeile($dbconn, "SELECT tel.id AS telid, ort, name, vwahl, ortsteil, land, plz, typ_id, partner_id, nr
FROM tel
JOIN ort ON tel.ort_id = ort.id
JOIN land ON land.id = ort.land_id
WHERE tel.adresse_id = ? ORDER BY tel.id LIMIT 1", array($adressid));
if($telres === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if($telres)
{
$smarty->assign("nr",$telres["nr"]);
$smarty->assign("vwahl",$telres["vwahl"]);
$smarty->assign("telplz",$telres["plz"]);
$smarty->assign("telort",$telres["ort"]);
$smarty->assign("teloteil",$telres["ortsteil"]);
$smarty->assign("telland",$telres["land"]);
$smarty->assign("telid",$telres["telid"]);
if(!$kunde)
$kunde = $telres["partner_id"];
}
$smarty->assign("kunde",$kunde);
$smarty->assign("adressid",$adressid);
list($anrids, $anrnamen) = auswahlliste($dbconn, "SELECT id, anrede FROM anrede WHERE id < 4");
$smarty->assign("anrids",$anrids);
$smarty->assign("anrs",$anrnamen);
list($titelids, $titelnamen) = auswahlliste($dbconn, "SELECT id, titel FROM titel");
$smarty->assign("titelids",$titelids);
$smarty->assign("titels",$titelnamen);
list($typids, $typnamen) = auswahlliste($dbconn, "SELECT id, typ FROM adresstyp WHERE id != 1");
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnamen);
$smarty->assign("frmact", $typ == 2 ? "lieferchange" : "kundenchange");
$smarty->display("newadress.tpl");
return 0;
}
//##############################################
//########## TEL.NRN. ######################
//##############################################
/*
* Legt eine Telefonnummer an oder ändert sie. $daten enthält telid,
* adresse_id, partner_id, typ_id, name, nr, vwahl und die Ortsangaben
* land/ort/plz/ortsteil.
*/
function speichereTelefon($dbconn, $daten)
{
$telid = (int)$daten["telid"];
$act = $telid ? "ändern" : "anlegen";
message($telid ? "Telefonnummer wird geändert..." : "Telefonnummer wird angelegt...");
beginneSpeichern($dbconn);
$ids = ortsangabeIds($dbconn, $daten, "beim telefon $act");
if($ids === false)
return beendeSpeichern($dbconn, 1);
list($land_id, $ort_id) = $ids;
// Die Vorwahl hängt am Ort, nicht an der Nummer
$alteVorwahl = db_wert($dbconn, "SELECT vwahl FROM ort WHERE id = ?", array($ort_id));
if($alteVorwahl === false)
return beendeSpeichern($dbconn, error("Fehler beim ermitteln der Daten für die LOG:<br />".mysqli_error($dbconn)));
$err = 0;
if($alteVorwahl !== $daten["vwahl"])
{
$sql = "UPDATE ort SET vwahl = ? WHERE id = ?";
$werte = array($daten["vwahl"], $ort_id);
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim anlegen der Vorwahl:<br />".mysqli_error($dbconn)));
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [(beim telefon $act)]",
db_sql_text($dbconn, $sql, array($alteVorwahl, $ort_id)), "ändern");
}
if($err)
return beendeSpeichern($dbconn, $err);
$felder = array(
"ort_id" => $ort_id,
"typ_id" => (int)$daten["typ_id"],
"name" => $daten["name"],
"adresse_id" => (int)$daten["adresse_id"],
"nr" => $daten["nr"],
);
$zuweisung = array();
foreach(array_keys($felder) as $spalte)
$zuweisung[] = "`$spalte` = ?";
$set = implode(", ", $zuweisung);
if($telid)
{
$alt = db_zeile($dbconn, "SELECT * FROM tel WHERE id = ?", array($telid));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim ermitteln der Daten für die LOG:<br />".mysqli_error($dbconn)));
$sql = "UPDATE tel SET $set WHERE id = ?";
$werte = array_merge(array_values($felder), array($telid));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim ändern der Telefonnummer:<br />".mysqli_error($dbconn)));
$altWerte = array();
foreach(array_keys($felder) as $spalte)
$altWerte[] = $alt[$spalte];
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [tel change]",
db_sql_text($dbconn, $sql, array_merge($altWerte, array($telid))), "ändern");
}
else
{
$sql = "INSERT INTO tel SET $set, partner_id = ?";
$werte = array_merge(array_values($felder), array((int)$daten["partner_id"]));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim Anlegen der Telefonnummer:<br />".mysqli_error($dbconn)));
$telid = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [hat ID $telid]",
"DELETE FROM tel WHERE id = $telid", "anlegen");
}
return beendeSpeichern($dbconn, $err);
}
/* Telefonnummer aus dem eigenen Formular (newtel.tpl) */
function saveTel($dbconn)
{
return speichereTelefon($dbconn, array(
"telid" => parameterGanzzahl("telid"),
"adresse_id" => parameterGanzzahl("adressid"),
"partner_id" => parameterGanzzahl("kunde"),
"typ_id" => formularGanzzahl("typ"),
"name" => formularText("name"),
"nr" => formularText("nr"),
"vwahl" => formularText("vwahl"),
"land" => formularText("land"),
"ort" => formularText("ort"),
"plz" => formularText("plz"),
"ortsteil" => formularText("oteil"),
));
}
function dispTelForm($dbconn,$smarty,$typ=1)
{
$telid = parameterGanzzahl("telid");
$kunde = parameterGanzzahl("kunde");
if(!$telid)
{
$smarty->assign("head","Neue Telefonnummer anlegen");
// Ort und Name aus der Hauptadresse als Vorbelegung
$res = db_zeile($dbconn, "SELECT ort, vname, nname, vwahl, ortsteil, land, plz
FROM adresse
JOIN strasse ON strasse.id = adresse.str_id
JOIN ort ON ort.id = strasse.ort_id
JOIN land ON land.id = ort.land_id
WHERE adresse.partner_id = ? AND adresse.typ_id = 1", array($kunde));
}
else
{
$smarty->assign("head","Telefonnummer ändern");
$res = db_zeile($dbconn, "SELECT ort, name, vwahl, ortsteil, land, plz, typ_id, partner_id, nr
FROM tel
JOIN ort ON tel.ort_id = ort.id
JOIN land ON land.id = ort.land_id
WHERE tel.id = ?", array($telid));
}
if($res === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if(!$res)
$res = array();
if(!empty($res["vname"]) || !empty($res["nname"]))
$res["name"] = trim($res["vname"]." ".$res["nname"]);
if(!empty($res["partner_id"]))
$kunde = $res["partner_id"];
foreach(array("name","ort","plz","nr","vwahl","land") as $feld)
$smarty->assign($feld, isset($res[$feld]) ? $res[$feld] : "");
$smarty->assign("oteil", isset($res["ortsteil"]) ? $res["ortsteil"] : "");
$smarty->assign("typ", isset($res["typ_id"]) ? $res["typ_id"] : "");
$smarty->assign("kunde",$kunde);
$smarty->assign("telid",$telid);
list($typids, $typnamen) = auswahlliste($dbconn, "SELECT id, typ FROM teltyp");
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnamen);
$smarty->assign("frmact", $typ == 2 ? "lieferchange" : "kundenchange");
$smarty->display("newtel.tpl");
return 0;
}
//##############################################
//########## KONTAKTE ######################
//##############################################
function saveKontakt($dbconn)
{
$kontaktid = parameterGanzzahl("kontaktid");
$kunde = parameterGanzzahl("kunde");
$felder = array(
"kontakt" => formularText("kontakt"),
"typ_id" => formularGanzzahl("typ"),
);
$set = "kontakt = ?, typ_id = ?";
$err = 0;
beginneSpeichern($dbconn);
if($kontaktid)
{
message("Kontaktadresse wird geändert...");
$alt = db_zeile($dbconn, "SELECT kontakt, typ_id FROM kontakt WHERE id = ?", array($kontaktid));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim ermitteln der Daten für die LOG:<br />".mysqli_error($dbconn)));
$sql = "UPDATE kontakt SET $set WHERE id = ?";
$werte = array_merge(array_values($felder), array($kontaktid));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim ändern der Kontaktadresse:<br />".mysqli_error($dbconn)));
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [kontakt change]",
db_sql_text($dbconn, $sql, array($alt["kontakt"], $alt["typ_id"], $kontaktid)), "ändern");
}
else
{
message("Kontaktadresse wird angelegt...");
$sql = "INSERT INTO kontakt SET $set, partner_id = ?";
$werte = array_merge(array_values($felder), array($kunde));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim Anlegen der Kontaktadresse:<br />".mysqli_error($dbconn)));
$kontaktid = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $kontaktid]",
"DELETE FROM kontakt WHERE id = $kontaktid", "anlegen");
}
return beendeSpeichern($dbconn, $err);
}
function dispKontaktForm($dbconn,$smarty,$typ=1)
{
$kontaktid = parameterGanzzahl("kontaktid");
$kunde = parameterGanzzahl("kunde");
$res = array();
if(!$kontaktid)
$smarty->assign("head","Neue Kontaktadresse anlegen");
else
{
$smarty->assign("head","Kontaktadresse ändern");
$res = db_zeile($dbconn, "SELECT kontakt, typ_id, partner_id FROM kontakt WHERE id = ?", array($kontaktid));
if($res === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if(!$res)
$res = array();
}
if(!empty($res["partner_id"]))
$kunde = $res["partner_id"];
$smarty->assign("kunde",$kunde);
$smarty->assign("kontakt", isset($res["kontakt"]) ? $res["kontakt"] : "");
$smarty->assign("typ", isset($res["typ_id"]) ? $res["typ_id"] : "");
$smarty->assign("kontaktid",$kontaktid);
list($typids, $typnamen) = auswahlliste($dbconn, "SELECT id, typ FROM kontakttyp");
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnamen);
$smarty->assign("frmact", $typ == 2 ? "lieferchange" : "kundenchange");
$smarty->display("newkontakt.tpl");
return 0;
}
//##############################################
//########## NOTIZEN ######################
//##############################################
function saveNotiz($dbconn)
{
$notizid = parameterGanzzahl("notizid");
$kunde = parameterGanzzahl("kunde");
$felder = array(
"notiz" => formularText("notiz"),
"color" => formularText("color"),
);
$set = "notiz = ?, color = ?, datetime = NOW()";
$err = 0;
beginneSpeichern($dbconn);
if($notizid)
{
message("Notiz wird geändert...");
$alt = db_zeile($dbconn, "SELECT notiz, color, datetime FROM notiz WHERE id = ?", array($notizid));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim erfassen der Daten für die LOG:<br />".mysqli_error($dbconn)));
$sql = "UPDATE notiz SET $set WHERE id = ?";
$werte = array_merge(array_values($felder), array($notizid));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim ändern der Notiz:<br />".mysqli_error($dbconn)));
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [notiz change]",
db_sql_text($dbconn, "UPDATE notiz SET notiz = ?, color = ?, datetime = ? WHERE id = ?",
array($alt["notiz"], $alt["color"], $alt["datetime"], $notizid)), "ändern");
}
else
{
message("Notiz wird angelegt...");
$sql = "INSERT INTO notiz SET $set, partner_id = ?";
$werte = array_merge(array_values($felder), array($kunde));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim Anlegen der Notiz:<br />".mysqli_error($dbconn)));
$notizid = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $notizid]",
"DELETE FROM notiz WHERE id = $notizid", "anlegen");
}
if(!$err && !empty($_FILES["notefile"]["tmp_name"]))
$err = speichereNotizDatei($notizid);
return beendeSpeichern($dbconn, $err);
}
/*
* Anhang einer Notiz. Der Dateiname ist die Notiz-id, die Endung kommt aus
* dem Hochgeladenen - deshalb wird sie auf harmlose Zeichen begrenzt, sonst
* ließe sich über den Namen eine .php im Uploads-Verzeichnis ablegen.
*/
function speichereNotizDatei($notizid)
{
$ordner = "./".UPLOADS_PATH."notes/";
if(!is_dir($ordner))
return error("Pfad zum speichern existiert nicht");
$endung = strtolower(pathinfo($_FILES["notefile"]["name"], PATHINFO_EXTENSION));
if(!preg_match('/^[a-z0-9]{1,8}$/', $endung) || in_array($endung, array("php", "phtml", "phar", "htaccess")))
return error("Dieser Dateityp kann nicht gespeichert werden.");
del_files($ordner, "!^".preg_quote((string)$notizid, "!")."\..*$!");
if(!move_uploaded_file($_FILES["notefile"]["tmp_name"], $ordner.$notizid.".".$endung))
return error("Hochgeladene Datei konnte leider nicht gespeichert werden.");
return 0;
}
function dispNotizForm($dbconn,$smarty,$typ=1)
{
$notizid = parameterGanzzahl("notizid");
$kunde = parameterGanzzahl("kunde");
$res = array();
if(!$notizid)
$smarty->assign("head","Neue Notiz anlegen");
else
{
$smarty->assign("head","Notiz ändern");
$res = db_zeile($dbconn, "SELECT notiz, color, partner_id FROM notiz WHERE id = ?", array($notizid));
if($res === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if(!$res)
$res = array();
}
if(!empty($res["partner_id"]))
$kunde = $res["partner_id"];
$smarty->assign("kunde",$kunde);
$smarty->assign("notiz", isset($res["notiz"]) ? $res["notiz"] : "");
$smarty->assign("color", isset($res["color"]) ? $res["color"] : "");
$smarty->assign("notizid",$notizid);
$smarty->assign("colors",array("#fff"=>"<div class='colorbox' style='background-color: #fff;'></div>",
"#afa"=>"<div class='colorbox' style='background-color: #bfb;'></div>",
"#ee0"=>"<div class='colorbox' style='background-color: #ee0;'></div>",
"#fa0"=>"<div class='colorbox' style='background-color: #fa0;'></div>",
"#faa"=>"<div class='colorbox' style='background-color: #faa;'></div>",
"#faf"=>"<div class='colorbox' style='background-color: #faf;'></div>",
"#bbf"=>"<div class='colorbox' style='background-color: #bbf;'></div>",
"#aff"=>"<div class='colorbox' style='background-color: #0ff;'></div>",
"#ccc"=>"<div class='colorbox' style='background-color: #ddd;'></div>"));
$smarty->assign("frmact", $typ == 2 ? "lieferchange" : "kundenchange");
$smarty->display("newnotiz.tpl");
return 0;
}
//##############################################
//########## PARTNER ######################
//##############################################
/*
* Legt einen Partner samt Hauptadresse und erster Telefonnummer an
* (newpar.tpl). $typ ist 1 für Kunden, 2 für Lieferanten. Rückgabe ist
* array($err, $partner_id).
*/
function savePart($dbconn,$typ=1)
{
message("Partner wird angelegt...");
beginneSpeichern($dbconn);
$sql = "INSERT INTO partner SET datetime_new = NOW(), user_id = ?, typ_id = ?, zahlziel_id = 1";
$werte = array($_SESSION["user"], (int)$typ);
if(!db_abfrage($dbconn, $sql, $werte))
return array(beendeSpeichern($dbconn, error("Fehler beim anlegen des Parnters:<br />".mysqli_error($dbconn))), 0);
$partner_id = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $partner_id]",
"DELETE FROM partner WHERE id = $partner_id", "anlegen");
if(!$err)
$err = saveAdress($dbconn, $partner_id, 1, 0);
if(!$err && formularText("nr") !== "")
$err = speichereTelefon($dbconn, array(
"telid" => 0,
"adresse_id" => 0,
"partner_id" => $partner_id,
"typ_id" => formularGanzzahl("teltyp"),
"name" => formularText("name"),
"nr" => formularText("nr"),
"vwahl" => formularText("vwahl"),
"land" => formularText("telland"),
"ort" => formularText("telort"),
"plz" => formularText("telplz"),
"ortsteil" => formularText("teloteil"),
));
return array(beendeSpeichern($dbconn, $err), $partner_id);
}
function dispPartForm($dbconn,$smarty,$typ=1)
{
$smarty->assign("head","Neuen ".($typ == 2 ? "Zulieferer" : "Kunden")." anlegen");
list($anrids, $anrnamen) = auswahlliste($dbconn, "SELECT id, anrede FROM anrede WHERE id < 4");
$smarty->assign("anrids",$anrids);
$smarty->assign("anrs",$anrnamen);
list($titelids, $titelnamen) = auswahlliste($dbconn, "SELECT id, titel FROM titel");
$smarty->assign("titelids",$titelids);
$smarty->assign("titels",$titelnamen);
list($typids, $typnamen) = auswahlliste($dbconn, "SELECT id, typ FROM teltyp");
$smarty->assign("typids",$typids);
$smarty->assign("typs",$typnamen);
$smarty->assign("partyp",$typ);
$smarty->assign("frmact", $typ == 2 ? "lieferadd" : "kundenadd");
$smarty->display("newpar.tpl");
return 0;
}
/*
* Neue Version eines Kunden: Der alte Datensatz bleibt erhalten und zeigt
* über updated_by auf den neuen. Alte Rechnungen behalten dadurch die
* Adresse, unter der sie gestellt wurden.
*/
function updateKunde($dbconn,$oldkunde)
{
message("Update von Kunde wird angelegt...");
beginneSpeichern($dbconn);
$sql = "INSERT INTO partner SET datetime_new = NOW(), user_id = ?, typ_id = 1, zahlziel_id = 1";
$werte = array($_SESSION["user"]);
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim anlegen des Kunden:<br />".mysqli_error($dbconn)));
$partner_id = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $partner_id]",
"DELETE FROM partner WHERE id = $partner_id", "anlegen");
if(!$err)
{
$alt = db_zeile($dbconn, "SELECT datetime_lastchange, user_id, updated_by FROM partner WHERE id = ?", array($oldkunde));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim abrufen der infos für die LOG:<br />".mysqli_error($dbconn)));
$sql = "UPDATE partner SET datetime_lastchange = NOW(), user_id = ?, updated_by = ? WHERE id = ?";
$werte = array($_SESSION["user"], $partner_id, $oldkunde);
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim update des alten Kunden:<br />".mysqli_error($dbconn)));
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [kunde update]",
db_sql_text($dbconn, "UPDATE partner SET datetime_lastchange = ?, user_id = ?, updated_by = ? WHERE id = ?",
array($alt["datetime_lastchange"], $alt["user_id"], $alt["updated_by"], $oldkunde)), "ändern");
}
if(!$err)
$err = saveAdress($dbconn, $partner_id, 1, 0);
return beendeSpeichern($dbconn, $err);
}
//##############################################
//########## KONTOS ######################
//##############################################
function saveKonto($dbconn)
{
$kontoid = parameterGanzzahl("kontoid");
$kunde = parameterGanzzahl("kunde");
$act = $kontoid ? "ändern" : "anlegen";
message($kontoid ? "Konto wird geändert..." : "Konto wird angelegt...");
beginneSpeichern($dbconn);
$bank_id = bankId($dbconn, formularText("bank"), formularText("blz"), "beim konto $act");
if($bank_id === false)
return beendeSpeichern($dbconn, 1);
$felder = array(
"bank_id" => $bank_id,
"inhaber" => formularText("inhaber"),
"iban" => formularText("iban"),
"swift" => formularText("swift"),
"ktonr" => formularText("ktonr"),
);
$zuweisung = array();
foreach(array_keys($felder) as $spalte)
$zuweisung[] = "`$spalte` = ?";
$set = implode(", ", $zuweisung);
$err = 0;
if($kontoid)
{
$alt = db_zeile($dbconn, "SELECT * FROM konto WHERE id = ?", array($kontoid));
if($alt === false || $alt === null)
return beendeSpeichern($dbconn, error("Fehler beim ermitteln der Daten für die LOG:<br />".mysqli_error($dbconn)));
$sql = "UPDATE konto SET $set WHERE id = ?";
$werte = array_merge(array_values($felder), array($kontoid));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim ändern des Kontos:<br />".mysqli_error($dbconn)));
$altWerte = array();
foreach(array_keys($felder) as $spalte)
$altWerte[] = $alt[$spalte];
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [konto change]",
db_sql_text($dbconn, $sql, array_merge($altWerte, array($kontoid))), "ändern");
}
else
{
$sql = "INSERT INTO konto SET $set, partner_id = ?";
$werte = array_merge(array_values($felder), array($kunde));
if(!db_abfrage($dbconn, $sql, $werte))
return beendeSpeichern($dbconn, error("Fehler beim Anlegen des Kontos:<br />".mysqli_error($dbconn)));
$kontoid = mysqli_insert_id($dbconn);
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $werte)." [Hat ID $kontoid]",
"DELETE FROM konto WHERE id = $kontoid", "anlegen");
}
return beendeSpeichern($dbconn, $err);
}
function dispKontoForm($dbconn,$smarty,$typ=1)
{
$kontoid = parameterGanzzahl("kontoid");
$kunde = parameterGanzzahl("kunde");
if(!$kontoid)
{
$smarty->assign("head","Neues Konto anlegen");
// Inhaber aus der Hauptadresse vorbelegen
$res = db_zeile($dbconn, "SELECT vname, nname, firma, partner_id FROM adresse
WHERE partner_id = ? AND typ_id = 1", array($kunde));
}
else
{
$smarty->assign("head","Konto ändern");
$res = db_zeile($dbconn, "SELECT ktonr, iban, swift, blz, bank, inhaber, partner_id FROM konto
JOIN bank ON konto.bank_id = bank.id
WHERE konto.id = ?", array($kontoid));
}
if($res === false)
return error("Fehler beim Auslesen der Daten:<br />".mysqli_error($dbconn));
if(!$res)
$res = array();
if(!empty($res["vname"]) || !empty($res["nname"]))
$res["inhaber"] = trim($res["vname"]." ".$res["nname"]);
if(!empty($res["firma"]))
$res["inhaber"] = $res["firma"];
if(!empty($res["partner_id"]))
$kunde = $res["partner_id"];
foreach(array("iban","swift","ktonr","bank","blz","inhaber") as $feld)
$smarty->assign($feld, isset($res[$feld]) ? $res[$feld] : "");
$smarty->assign("kunde",$kunde);
$smarty->assign("kontoid",$kontoid);
$smarty->assign("frmact", $typ == 2 ? "lieferchange" : "kundenchange");
$smarty->display("newkonto.tpl");
return 0;
}
//##############################################
//########## LÖSCHEN ######################
//##############################################
/*
* Die Unterdatensätze eines Partners. "beschreibung" liefert den Text fürs
* Änderungsprotokoll, "form"/"save" die Funktionen der Pflegeseite.
* Tabellen- und Spaltennamen stammen ausschließlich von hier, nie aus der
* Anfrage - binden lassen sie sich nicht.
*/
function partnerBereiche()
{
return array(
"adress" => array(
"tabelle" => "adresse", "param" => "adressid", "was" => "Adresse",
"form" => "dispAdressForm", "save" => "saveAdress",
"beschreibung" => "SELECT CONCAT(adresstyp.typ, ' (', vname, ' ', nname, ' - ', firma, ')') FROM adresse JOIN adresstyp ON adresstyp.id = adresse.typ_id WHERE adresse.id = ?",
),
"tel" => array(
"tabelle" => "tel", "param" => "telid", "was" => "Telefonnummer",
"form" => "dispTelForm", "save" => "saveTel",
"beschreibung" => "SELECT CONCAT(teltyp.typ, ' ', tel.nr) FROM tel JOIN teltyp ON teltyp.id = tel.typ_id WHERE tel.id = ?",
),
"kontakt" => array(
"tabelle" => "kontakt", "param" => "kontaktid", "was" => "Kontaktinformation",
"form" => "dispKontaktForm", "save" => "saveKontakt",
"beschreibung" => "SELECT CONCAT(kontakttyp.typ, ' ', kontakt.kontakt) FROM kontakt JOIN kontakttyp ON kontakttyp.id = kontakt.typ_id WHERE kontakt.id = ?",
),
"notiz" => array(
"tabelle" => "notiz", "param" => "notizid", "was" => "Notiz",
"form" => "dispNotizForm", "save" => "saveNotiz",
"beschreibung" => "SELECT LEFT(notiz, 60) FROM notiz WHERE id = ?",
),
"konto" => array(
"tabelle" => "konto", "param" => "kontoid", "was" => "Konto",
"form" => "dispKontoForm", "save" => "saveKonto",
"beschreibung" => "SELECT CONCAT(bank.bank, ' ', konto.iban, konto.ktonr) FROM konto JOIN bank ON bank.id = konto.bank_id WHERE konto.id = ?",
),
);
}
/*
* Löscht einen Unterdatensatz eines Partners. Der JOIN auf partner stellt
* sicher, dass er wirklich zu einem Partner des erwarteten Typs gehört -
* sonst ließe sich über die Lieferantenseite ein Kunde bearbeiten.
*/
function loescheUnterdatensatz($dbconn, $bereich, $id, $partnertyp)
{
$tabelle = $bereich["tabelle"];
$partnerwort = $partnertyp == 2 ? "Lieferant" : "Kunde";
$kdnr = db_wert($dbconn, "SELECT $tabelle.partner_id FROM $tabelle
JOIN partner ON partner.id = $tabelle.partner_id
WHERE $tabelle.id = ? AND partner.typ_id = ?", array($id, $partnertyp));
if($kdnr === false)
return error("Fehler beim abrufen der Informationen für die LOG:<br />".mysqli_error($dbconn));
if(!$kdnr)
return error("Ungültiger $partnerwort!");
// Ohne Hauptadresse ist der Partner nicht mehr auffindbar, die
// Oberfläche bietet das Löschen dafür auch gar nicht erst an
if($tabelle == "adresse" && db_wert($dbconn, "SELECT typ_id FROM adresse WHERE id = ?", array($id)) == 1)
return error("Die Hauptadresse lässt sich nicht löschen.");
$beschreibung = db_wert($dbconn, $bereich["beschreibung"], array($id));
if($beschreibung === false)
$beschreibung = "";
beginneSpeichern($dbconn);
$err = 0;
if($tabelle == "adresse")
$err = loescheAdressAnhaenge($dbconn, $id);
if(!$err)
{
$sql = "DELETE FROM $tabelle WHERE id = ?";
if(!db_abfrage($dbconn, $sql, array($id)))
$err = error("Fehler beim löschen der ".$bereich["was"].":<br />".mysqli_error($dbconn));
else
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, array($id))." [$beschreibung von $partnerwort $kdnr]", "", "löschen");
}
if(!$err && $tabelle == "notiz")
del_files("./".UPLOADS_PATH."notes/", "!^".preg_quote((string)$id, "!")."\..*$!");
return beendeSpeichern($dbconn, $err);
}
/*
* Entwürfe (tmp_rechnung) samt Artikeln und Eigenschaften. $spalte ist
* "adresse_id" oder "partner_id"; die Reihenfolge ist wichtig, weil
* tmp_artikel per Fremdschlüssel an tmp_rechnung hängt.
*/
function loescheEntwuerfe($dbconn, $spalte, $wert)
{
$err = 0;
db_abfrage($dbconn, "DELETE tmp_eigensch FROM tmp_eigensch
JOIN tmp_artikel ON tmp_eigensch.art_id = tmp_artikel.id
JOIN tmp_rechnung ON tmp_artikel.rech_id = tmp_rechnung.id
WHERE tmp_rechnung.$spalte = ?", array($wert))
or $err = error("Fehler beim löschen der Entwurfs-Eigenschaften:<br />".mysqli_error($dbconn));
if(!$err)
db_abfrage($dbconn, "DELETE tmp_artikel FROM tmp_artikel
JOIN tmp_rechnung ON tmp_artikel.rech_id = tmp_rechnung.id
WHERE tmp_rechnung.$spalte = ?", array($wert))
or $err = error("Fehler beim löschen der Entwurfs-Artikel:<br />".mysqli_error($dbconn));
if(!$err)
db_abfrage($dbconn, "DELETE FROM tmp_rechnung WHERE $spalte = ?", array($wert))
or $err = error("Fehler beim löschen der Entwürfe:<br />".mysqli_error($dbconn));
return $err;
}
/*
* Alles, was auf eine Adresse zeigt: Telefonnummern und Dokumente. Die
* Oberfläche kündigt beim Löschen einer Adresse ausdrücklich an, dass die
* zugehörigen Rechnungen mit verschwinden - ohne das blieben sie mit einer
* ins Leere zeigenden Adresse zurück.
*/
function loescheAdressAnhaenge($dbconn, $adressid)
{
$err = 0;
$rechnungen = db_zeilen($dbconn, "SELECT id, rechnr FROM rechnung WHERE adresse_id = ?", array($adressid));
if($rechnungen === false)
return error("Fehler beim ermitteln verknüpfter Rechnungen:<br />".mysqli_error($dbconn));
foreach($rechnungen as $rechnung)
{
if(!$err)
db_abfrage($dbconn, "DELETE FROM artikelsks WHERE rechnr = ?", array($rechnung["rechnr"]))
or $err = error("Fehler beim löschen verknüpfter SKS Artikel:<br />".mysqli_error($dbconn));
if(!$err)
$err = delRechnung($dbconn, $rechnung["id"]);
}
if(!$err)
$err = loescheEntwuerfe($dbconn, "adresse_id", $adressid);
if(!$err)
db_abfrage($dbconn, "DELETE FROM tel WHERE adresse_id = ?", array($adressid))
or $err = error("Fehler beim löschen der zugehörigen Telefonnummern:<br />".mysqli_error($dbconn));
return $err;
}
/*
* Löscht einen Partner mit allem, was an ihm hängt. $typ ist 1 für Kunden,
* 2 für Lieferanten.
*
* Braucht das Rechnungsmodul (delRechnung), die aufrufende Seite muss
* incs/rechnung.php eingebunden haben.
*/
function loeschePartner($dbconn, $kundeid, $typ)
{
$partnerwort = $typ == 2 ? "Lieferant" : "Kunde";
$res = db_zeile($dbconn, "SELECT partner.id, vname, nname, firma FROM partner
JOIN adresse ON adresse.partner_id = partner.id
WHERE partner.id = ? AND adresse.typ_id = 1 AND partner.typ_id = ?",
array($kundeid, $typ));
if($res === false)
return error("Fehler beim ermitteln der Kundendaten für die LOG:<br />".mysqli_error($dbconn));
if(!$res)
return error("Ungültiger $partnerwort!");
$beschreibung = $res["vname"]." ".$res["nname"]." - ".$res["firma"];
beginneSpeichern($dbconn);
$err = 0;
$rechnungen = db_zeilen($dbconn, "SELECT id, rechnr FROM rechnung WHERE partner_id = ?", array($kundeid));
if($rechnungen === false)
$err = error("Fehler beim ermitteln verknüpfter Rechnungen:<br />".mysqli_error($dbconn));
foreach((array)$rechnungen as $rechnung)
{
if(!$err)
db_abfrage($dbconn, "DELETE FROM artikelsks WHERE rechnr = ?", array($rechnung["rechnr"]))
or $err = error("Fehler beim löschen verknüpfter SKS Artikel:<br />".mysqli_error($dbconn));
if(!$err)
$err = delRechnung($dbconn, $rechnung["id"]);
}
// Reihenfolge: erst alles, was auf partner oder adresse zeigt
if(!$err)
$err = loescheEntwuerfe($dbconn, "partner_id", $kundeid);
$aufraeumen = array(
"tel" => "Fehler beim Löschen verknüpfter Telefonnummern",
"adresse" => "Fehler beim Löschen verknüpfter Adressen",
"kontakt" => "Fehler beim Löschen verknüpfter Kontaktadressen",
"notiz" => "Fehler beim Löschen verknüpfter Notizen",
"konto" => "Fehler beim Löschen verknüpfter Konten",
);
foreach($aufraeumen as $tabelle => $meldung)
if(!$err)
db_abfrage($dbconn, "DELETE FROM $tabelle WHERE partner_id = ?", array($kundeid))
or $err = error($meldung.":<br />".mysqli_error($dbconn));
if(!$err)
db_abfrage($dbconn, "DELETE FROM partner WHERE id = ?", array($kundeid))
or $err = error("Fehler beim löschen des Kunden:<br />".mysqli_error($dbconn));
if(!$err)
$err = saveLog($dbconn, db_sql_text($dbconn, "DELETE FROM partner WHERE id = ?", array($kundeid))." [$beschreibung]", "", "löschen");
// Zeigte eine ältere Version auf diesen Datensatz, ist sie jetzt wieder aktuell
if(!$err)
db_abfrage($dbconn, "UPDATE partner SET updated_by = 0 WHERE updated_by = ?", array($kundeid))
or $err = error("Fehler beim unlinken einer eventuellen aktualisierung:<br />".mysqli_error($dbconn));
return beendeSpeichern($dbconn, $err);
}
//##############################################
//########## SEITEN ######################
//##############################################
/*
* sites/kundenadd.php und sites/lieferadd.php: Partner anlegen oder löschen.
* $typ ist 1 für Kunden, 2 für Lieferanten.
*/
function partnerAddSeite($dbconn, $smarty, $typ)
{
if(parameterGanzzahl("del") == 1)
{
$err = loeschePartner($dbconn, parameterGanzzahl("kundeid"), $typ);
if(!$err)
doneNreturn("Erfolgreich gelöscht!");
return $err;
}
if(parameterGanzzahl("formsent") == 1)
{
list($err, $partner_id) = savePart($dbconn, $typ);
$_SESSION["camefrom"] = ($typ == 2 ? "liefershow" : "kundenshow")."&id=".$partner_id;
if(!$err)
doneNreturn("Erfolgreich erledigt!");
return $err;
}
return dispPartForm($dbconn, $smarty, $typ);
}
/*
* sites/kundenchange.php und sites/lieferchange.php: Adressen, Telefon-
* nummern, Kontakte, Notizen und Konten eines Partners pflegen.
*/
function partnerChangeSeite($dbconn, $smarty, $typ)
{
$bereiche = partnerBereiche();
$name = isset($_GET["do"]) && is_string($_GET["do"]) ? $_GET["do"] : "";
if(!isset($bereiche[$name]))
return error("Unbekannter Bereich.");
$bereich = $bereiche[$name];
if(parameterGanzzahl("del") == 1)
{
$err = loescheUnterdatensatz($dbconn, $bereich, parameterGanzzahl($bereich["param"]), $typ);
if(!$err)
doneNreturn("Erfolgreich gelöscht!");
return $err;
}
if(parameterGanzzahl("formsent") == 1)
{
$err = call_user_func($bereich["save"], $dbconn);
if(!$err)
doneNreturn("Erfolgreich erledigt!");
return $err;
}
return call_user_func($bereich["form"], $dbconn, $smarty, $typ);
}
/*
* sites/kundenshow.php und sites/liefershow.php: alle Daten eines Partners
* für die Anzeige. Gibt false zurück, wenn es ihn nicht (mehr) gibt.
*/
function partnerShowDaten($dbconn, $smarty, $id, $typ)
{
$kdnres = db_zeile($dbconn, "SELECT * FROM partner WHERE id = ? AND typ_id = ?", array($id, $typ));
if($kdnres === false)
{
error("Fehler beim auslesen des Partners:<br />".mysqli_error($dbconn));
$kdnres = null;
}
$smarty->assign("kunde", $kdnres ? $kdnres : array());
if(!$kdnres)
return false;
// Versionskette in beide Richtungen: ältere Stände zeigen über
// updated_by auf diesen, neuere hängen an unserem updated_by
$smarty->assign("oldrecords", partnerVersionen($dbconn, $id, "vorgaenger"));
$smarty->assign("newrecords", partnerVersionen($dbconn, $kdnres["updated_by"], "nachfolger"));
$smarty->assign("anr", db_zuordnung($dbconn, "SELECT id, anrede FROM anrede") ?: array());
$smarty->assign("titel", db_zuordnung($dbconn, "SELECT id, titel FROM titel") ?: array());
$smarty->assign("telnrn", db_zeilen($dbconn, "SELECT name, typ, tel.id, nr, ort, ortsteil, plz, vwahl, ort.id AS ort_id
FROM tel
LEFT JOIN teltyp ON tel.typ_id = teltyp.id
LEFT JOIN ort ON tel.ort_id = ort.id
WHERE partner_id = ? AND tel.adresse_id = 0
ORDER BY tel.typ_id ASC", array($id)) ?: array());
$smarty->assign("contacts", db_zeilen($dbconn, "SELECT kontakt.id, kontakt, partner_id, typ
FROM kontakt LEFT JOIN kontakttyp ON kontakttyp.id = kontakt.typ_id
WHERE partner_id = ? ORDER BY kontakt.typ_id ASC", array($id)) ?: array());
$smarty->assign("kontos", db_zeilen($dbconn, "SELECT ktonr, iban, swift, blz, bank, partner_id, konto.id, inhaber
FROM konto JOIN bank ON konto.bank_id = bank.id
WHERE partner_id = ?", array($id)) ?: array());
$notes = db_zeilen($dbconn, "SELECT * FROM notiz WHERE partner_id = ?", array($id)) ?: array();
foreach($notes as $i => $note)
$notes[$i]["file"] = search_file("./".UPLOADS_PATH."notes/", "!^".preg_quote($note["id"], "!")."\..*$!");
// Mahnungen sind keine Notiz, werden aber wie eine angezeigt
$mahnungen = db_wert($dbconn, "SELECT COUNT(rechnr) FROM rechnung WHERE typ_id = 6 AND partner_id = ?", array($id));
if($mahnungen > 0)
$notes[] = array(
"notiz" => "ACHTUNG! Es sind bereits ".$mahnungen." Mahnungen für diesen Kunden vorhanden!!",
"color" => "#f76",
"datetime" => date("Y-m-d H:i:s"),
);
$smarty->assign("notes", $notes);
$smarty->assign("adressen", db_zeilen($dbconn, "SELECT plz, ortsteil, tel.nr, ort.vwahl, ort, str,
DATE_FORMAT(gebdat,'%d.%m.%Y') AS gebdat, DATE_FORMAT(gebdat2,'%d.%m.%Y') AS gebdat2,
hnr, vname, nname, vname2, nname2, firma, adresse.id, land,
anrede_id, titel_id, anrede2_id, titel2_id, adresstyp.typ, adresse.typ_id
FROM adresse
JOIN adresstyp ON adresstyp.id = adresse.typ_id
LEFT JOIN strasse ON str_id = strasse.id
LEFT JOIN ort ON ort_id = ort.id
LEFT JOIN land ON land_id = land.id
LEFT JOIN tel ON tel.adresse_id = adresse.id
WHERE adresse.partner_id = ? AND adresse.typ_id != 5
ORDER BY adresse.typ_id ASC", array($id)) ?: array());
$smarty->assign("kommadressen", db_wert($dbconn, "SELECT COUNT(*) FROM adresse WHERE partner_id = ? AND typ_id = 5", array($id)) > 0 ? 1 : 0);
$smarty->assign("rechtypen", db_zeilen($dbconn, "SELECT typ, id FROM rechtyp") ?: array());
return true;
}
/*
* Folgt der Versionskette eines Partners. "vorgaenger" sucht die älteren
* Stände (sie zeigen über updated_by hierher), "nachfolger" die neueren
* (jeder Stand zeigt über updated_by auf den nächsten). Nach 50 Schritten
* ist Schluss, damit ein ringförmiger Verweis die Seite nicht aufhängt.
*/
function partnerVersionen($dbconn, $start, $richtung)
{
$sql = $richtung == "vorgaenger"
? "SELECT id, datetime_new, updated_by FROM partner WHERE updated_by = ?"
: "SELECT id, datetime_new, updated_by FROM partner WHERE id = ?";
$versionen = array();
$id = $start;
while($id && count($versionen) < 50)
{
$res = db_zeile($dbconn, $sql, array($id));
if(!$res)
break;
$versionen[] = $res;
$id = $richtung == "vorgaenger" ? $res["id"] : $res["updated_by"];
}
return $versionen;
}
?>