feat(v2.0.2): Corrections de sécurité critiques et fonctionnalité de réactivation des devis

- Correction de 14 vulnérabilités SQL (8 critiques, 6 moyennes)
- Suppression de la fonction autocomplete non utilisée
- Migration complète vers PDO avec requêtes préparées
- Ajout du bouton 'Réactiver' pour les devis archivés (statut 20 → 1)
- Conversion des appels $.ajax en fetch API (vanilla JS)
- Correction des erreurs JavaScript empêchant l'attachement d'événements
- Mise à jour de la documentation (README.md et TODO.md)

Sécurité: Utilisation systématique de intval() et requêtes préparées PDO
UI: Nouveau bouton vert dans la grille 2x2 des actions sur devis archivés
Historique: Traçabilité dans devis_histo lors de la réactivation
This commit is contained in:
2025-09-12 20:25:48 +02:00
parent eabb4bf67a
commit 443b0509df
16 changed files with 4355 additions and 3318 deletions

View File

@@ -15,7 +15,8 @@ switch ($Route->_action) {
$rowid = nettoie_input($_POST["rid"]);
//! 1. Recherche du devis d'origine par son rowid
$sql = 'SELECT rowid FROM devis WHERE rowid = ' . $rowid . ';';
$rowidSafe = intval($rowid);
$sql = 'SELECT rowid FROM devis WHERE rowid = ' . $rowidSafe . ';';
$leDevis = getinfos($sql, 'gen');
//! 2. S'il existe on crée un nouveau devis et on récupère son id
@@ -26,13 +27,13 @@ switch ($Route->_action) {
$sql .= 'SELECT d.fk_user, d.fk_client, d.fk_marche, d.dossier, d.chk_devis_photos, d.chk_speciaux, d.montant_total_ht, d.montant_total_ht_remise, d.marge_totale, d.seuil_marge_rr, d.seuil_marge_dv, ';
$sql .= 'd.lib_new_client, d.type_new_client, d.adresse1_new_client, d.adresse2_new_client, d.adresse3_new_client, d.cp_new_client, d.ville_new_client, ';
$sql .= 'd.contact_new_nom, d.contact_new_prenom, d.contact_new_fonction, d.new_telephone, d.new_mobile, d.new_email, "' . date("Y-m-d H:i:s") . '" as date_creat, d.fk_user_creat ';
$sql .= 'FROM devis d WHERE d.rowid = ' . $rowid . ';';
$sql .= 'FROM devis d WHERE d.rowid = ' . $rowidSafe . ';';
eLog($sql);
$newRowid = qSQL($sql, 'gen', true);
if ($newRowid > 0) {
//! 3. Si son nouvel id est bien récupéré, on duplique les lignes produits
$sql = 'SELECT * FROM devis_produits WHERE fk_devis = ' . $rowid . ';';
$sql = 'SELECT * FROM devis_produits WHERE fk_devis = ' . $rowidSafe . ';';
$aProduits = getinfos($sql, 'gen');
eLog(count($aProduits) . " lignes produits trouvées");
@@ -52,12 +53,14 @@ switch ($Route->_action) {
eLog("Duplication de ses " . count($aProduits) . " lignes produits");
//! 4. On met à jour la date_demande, date_remise, num_opportunite et fk_statut_devis du nouveau devis
$sql = 'UPDATE devis SET date_demande = "' . date("Y-m-d H:i:s") . '", date_remise = "", num_opportunite = "", fk_statut_devis = 1 WHERE rowid = ' . $newRowid . ';';
$newRowidSafe = intval($newRowid);
$sql = 'UPDATE devis SET date_demande = "' . date("Y-m-d H:i:s") . '", date_remise = "", num_opportunite = "", fk_statut_devis = 1 WHERE rowid = ' . $newRowidSafe . ';';
eLog($sql);
qSQL($sql, "gen");
//! 5. On inscrit la duplication dans le journal
$sql = 'INSERT INTO devis_histo SET fk_user = ' . $fk_user . ', fk_devis = ' . $newRowid . ', commentaire="Création du devis par duplication (' . $rowid . ')", date_histo = "' . date("Y-m-d H:i:s") . '", fk_statut_devis=1;';
$fkUserSafe = intval($fk_user);
$sql = 'INSERT INTO devis_histo SET fk_user = ' . $fkUserSafe . ', fk_devis = ' . $newRowidSafe . ', commentaire="Création du devis par duplication (' . $rowidSafe . ')", date_histo = "' . date("Y-m-d H:i:s") . '", fk_statut_devis=1;';
eLog($sql);
qSQL($sql, "gen");
@@ -70,8 +73,40 @@ switch ($Route->_action) {
}
break;
case "reactiver_devis":
// Réactivation d'un devis archivé
if ($_POST) {
$rowid = nettoie_input($_POST["rid"]);
$rowidSafe = intval($rowid);
// Vérifier que le devis existe et est bien archivé (statut 20)
$sql = 'SELECT rowid, fk_statut_devis FROM devis WHERE rowid = ' . $rowidSafe . ' AND fk_statut_devis = 20;';
$leDevis = getinfos($sql, 'gen');
if (count($leDevis) == 1) {
// Mettre à jour le statut du devis de 20 (Archivé) à 1 (En cours)
$sql = 'UPDATE devis SET fk_statut_devis = 1, date_modif = "' . date("Y-m-d H:i:s") . '", fk_user_modif = ' . intval($fk_user) . ' WHERE rowid = ' . $rowidSafe . ';';
qSQL($sql, "gen");
// Ajouter une entrée dans l'historique
$sql = 'INSERT INTO devis_histo SET fk_user = ' . intval($fk_user) . ', fk_devis = ' . $rowidSafe . ', commentaire = "Réactivation du devis archivé", date_histo = "' . date("Y-m-d H:i:s") . '", fk_statut_devis = 1;';
qSQL($sql, "gen");
// Mettre à jour la session avec ce devis réactivé
$_SESSION["lastDevis"] = $rowidSafe;
eLog("Réactivation du devis archivé #" . $rowidSafe);
echo json_encode(array("success" => true, "message" => "Devis réactivé avec succès"));
} else {
echo json_encode(array("success" => false, "message" => "Devis introuvable ou non archivé"));
}
}
break;
case "load_all_devis":
$sql = 'SELECT d.rowid, d.date_demande, d.fk_client, d.montant_total_ht_remise, c.libelle FROM devis d LEFT JOIN clients c ON c.rowid=d.fk_client where d.fk_user=' . $Session->_user["rowid"] . ' ORDER BY d.date_demande DESC;';
$fkUserSession = intval($Session->_user["rowid"]);
$sql = 'SELECT d.rowid, d.date_demande, d.fk_client, d.montant_total_ht_remise, c.libelle FROM devis d LEFT JOIN clients c ON c.rowid=d.fk_client where d.fk_user=' . $fkUserSession . ' ORDER BY d.date_demande DESC;';
$upls = array();
$upls = getinfos($sql, "gen");
echo json_encode($upls);
@@ -84,8 +119,9 @@ switch ($Route->_action) {
$cid = nettoie_input($data->cid);
//! si ce n'est pas le RR ou un super-admin, on remet à zéro le chk_maj pour ne plus avoir l'info de mise à jour
$cidSafe = intval($cid);
if ($Session->_user["fk_role"] != 3 && $Session->_user["fk_role"] != 90) {
$sql = 'UPDATE devis SET chk_maj = 0 WHERE rowid = ' . $cid . ';';
$sql = 'UPDATE devis SET chk_maj = 0 WHERE rowid = ' . $cidSafe . ';';
qSQL($sql, "gen");
}
$sql = 'SELECT d.rowid, d.fk_user, d.fk_client, d.fk_marche, m.libelle AS lib_marche, d.fk_statut_devis, d.dossier, d.num_opportunite, d.montant_total_ht, ';
@@ -97,7 +133,7 @@ switch ($Route->_action) {
$sql .= 'c.contact_nom, c.contact_prenom, c.contact_fonction, c.telephone, c.mobile, c.email, d.chk_devis_photos ';
$sql .= 'FROM devis d LEFT JOIN clients c ON d.fk_client = c.rowid LEFT JOIN x_statuts_devis xs ON d.fk_statut_devis = xs.rowid ';
$sql .= 'LEFT JOIN marches m ON d.fk_marche = m.rowid ';
$sql .= 'WHERE d.rowid = ' . $cid . ';';
$sql .= 'WHERE d.rowid = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
} else {
$ret = array('ret' => "ko", 'msg' => 'Erreur lors du chargement du devis (en-tête)');
@@ -111,7 +147,8 @@ switch ($Route->_action) {
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'SELECT dp.*, pf.marge_rr, pf.marge_dv FROM devis_produits dp LEFT JOIN produits p ON dp.fk_produit=p.rowid LEFT JOIN produits_familles pf ON p.groupe=pf.groupe WHERE dp.fk_devis = ' . $cid . ' ORDER BY dp.ordre;';
$cidSafe = intval($cid);
$sql = 'SELECT dp.*, pf.marge_rr, pf.marge_dv FROM devis_produits dp LEFT JOIN produits p ON dp.fk_produit=p.rowid LEFT JOIN produits_familles pf ON p.groupe=pf.groupe WHERE dp.fk_devis = ' . $cidSafe . ' ORDER BY dp.ordre;';
echo getinfos($sql, "gen", "json");
} else {
$ret = array('ret' => "ko", 'msg' => 'Erreur lors du chargement des produits du devis');
@@ -128,7 +165,8 @@ switch ($Route->_action) {
$sql = 'SELECT rowid, libelle, CONCAT(libelle, ", ", adresse1, ", ", cp, " ", ville) AS rech, adresse1, adresse2, adresse3, cp, ville, contact_nom, contact_prenom, contact_fonction, telephone, mobile, email, type_client FROM clients WHERE active=1 ';
if ($chkSecteur == "1") {
//! on ne prend que les clients du secteur de l'utilisateur
$sqlDepts = 'SELECT lst_depts FROM users WHERE rowid=' . $fkUser . ';';
$fkUserSafe = intval($fkUser);
$sqlDepts = 'SELECT lst_depts FROM users WHERE rowid=' . $fkUserSafe . ';';
$lstDepts = getinfos($sqlDepts, "gen");
$depts = trim($lstDepts[0]["lst_depts"]);
if ($depts != "") $sql .= ' AND SUBSTR(cp,1,2) IN (' . $depts . ') ';
@@ -153,7 +191,8 @@ switch ($Route->_action) {
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'SELECT m.* FROM marches m WHERE m.rowid = ' . $cid . ';';
$cidSafe = intval($cid);
$sql = 'SELECT m.* FROM marches m WHERE m.rowid = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
}
break;
@@ -165,7 +204,8 @@ switch ($Route->_action) {
$cid = nettoie_input($data->cid);
// On récupère les terme du marché dans marches_listes
$sql = 'SELECT * FROM marches_listes WHERE fk_marche = ' . $cid . ';';
$cidSafe = intval($cid);
$sql = 'SELECT * FROM marches_listes WHERE fk_marche = ' . $cidSafe . ';';
$retSql = getinfos($sql, "gen");
if (count($retSql) == 1) {
$termeAchat = $retSql[0]["terme_achat"];
@@ -178,7 +218,7 @@ switch ($Route->_action) {
if ($cid != "999") {
// ce n'est pas le hors marché
// On vérifie d'abord si le marché est hybride, si oui on charge les produits du marché et ceux de la liste tarifaire générale
$sql = 'SELECT chk_remise_sur_tg, chk_marche_hybride FROM marches WHERE rowid = ' . $cid . ';';
$sql = 'SELECT chk_remise_sur_tg, chk_marche_hybride FROM marches WHERE rowid = ' . $cidSafe . ';';
$retSql = getinfos($sql, "gen");
$chkTG = $retSql[0]["chk_remise_sur_tg"];
$chkHybride = $retSql[0]["chk_marche_hybride"];
@@ -194,7 +234,7 @@ switch ($Route->_action) {
$sql = 'SELECT p.*, CONCAT(p.code, " - ", p.libelle) AS rech, pf.fk_famille, xf.libelle AS lib_famille, "0" AS chk_prix_net ';
$sql .= 'FROM produits p LEFT JOIN produits_familles pf ON p.groupe=pf.groupe LEFT JOIN x_familles xf on pf.fk_famille = xf.rowid ';
$sql .= 'WHERE p.fk_marche = ' . $cid . ' AND p.active=1 ORDER BY xf.ordre, pf.ordre;';
$sql .= 'WHERE p.fk_marche = ' . $cidSafe . ' AND p.active=1 ORDER BY xf.ordre, pf.ordre;';
$upls = getinfos($sql, "gen");
if ($cid != "999") {
@@ -256,7 +296,8 @@ switch ($Route->_action) {
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'SELECT * FROM devis_speciaux WHERE fk_devis = ' . $cid . ';';
$cidSafe = intval($cid);
$sql = 'SELECT * FROM devis_speciaux WHERE fk_devis = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
}
break;
@@ -266,11 +307,13 @@ switch ($Route->_action) {
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'SELECT d.fk_user, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, d.montant_total_ht_remise FROM devis d WHERE d.rowid = ' . $cid . ';';
$cidSafe = intval($cid);
$sql = 'SELECT d.fk_user, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, d.montant_total_ht_remise FROM devis d WHERE d.rowid = ' . $cidSafe . ';';
$retSql = getinfos($sql, "gen");
$devis = $retSql[0];
if ($devis["fk_client"] > 0) {
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid = "' . $devis["fk_client"] . '";';
$fkClientSafe = intval($devis["fk_client"]);
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid = ' . $fkClientSafe . ';';
$ret = getinfos($sql, "gen");
$client = $ret[0];
$libClient = $client["libelle"];
@@ -283,22 +326,23 @@ switch ($Route->_action) {
}
$fkUserDevis = $devis["fk_user"];
$sql = 'DELETE FROM devis_speciaux WHERE fk_devis = ' . $cid . ';';
$sql = 'DELETE FROM devis_speciaux WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$sql = 'DELETE FROM devis_histo WHERE fk_devis = ' . $cid . ';';
$sql = 'DELETE FROM devis_histo WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $cid . ';';
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$sql = 'DELETE FROM devis WHERE rowid = ' . $cid . ';';
$sql = 'DELETE FROM devis WHERE rowid = ' . $cidSafe . ';';
qSQL($sql, "gen");
eLog($sql);
// On envoie un email au RR pour lui signaler la suppression du devis si ce n'est pas lui qui a supprimé le devis
if ($fk_user != $fkUserDevis) {
$sql = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $fkUserDevis . ';';
$fkUserDevisSafe = intval($fkUserDevis);
$sql = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $fkUserDevisSafe . ';';
$retSql = getinfos($sql, "gen");
$nom = $retSql[0]["prenom"] . " " . $retSql[0]["libelle"];
$email = $retSql[0]["email"];
@@ -386,7 +430,8 @@ switch ($Route->_action) {
} else {
//! c'est une mise à jour d'un devis existant
$sql = 'SELECT fk_marche, commentaire FROM devis WHERE rowid = ' . $rowid . ';';
$rowidSafe = intval($rowid);
$sql = 'SELECT fk_marche, commentaire FROM devis WHERE rowid = ' . $rowidSafe . ';';
$retSql = getinfos($sql, "gen");
$commentaireOld = $retSql[0]["commentaire"];
if ($commentaireOld != $commentaire) {
@@ -400,20 +445,21 @@ switch ($Route->_action) {
$oldMarche = $retSql[0]["fk_marche"];
if ($oldMarche != $fk_marche) {
// le marché a été modifié, il faut supprimer tous les produits de ce devis !!
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $rowid . ';';
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $rowidSafe . ';';
eLog($sql);
qSQL($sql, "gen");
// et on remet à zéro tous les totaux du devis
$sql = 'UPDATE devis SET montant_total_ht=0, montant_total_ht_remise=0, marge_totale=0 WHERE rowid=' . $rowid . ';';
$sql = 'UPDATE devis SET montant_total_ht=0, montant_total_ht_remise=0, marge_totale=0 WHERE rowid=' . $rowidSafe . ';';
eLog($sql);
qSQL($sql, "gen");
// On enregistre cette info dans le chat
$sql = 'INSERT INTO devis_histo SET fk_user=' . $fk_user . ', fk_devis=' . $rowid . ', commentaire="Le marché a été modifié, les produits ont été supprimés", date_histo="' . date("Y-m-d H:i:s") . '";';
$fkUserSafe = intval($fk_user);
$sql = 'INSERT INTO devis_histo SET fk_user=' . $fkUserSafe . ', fk_devis=' . $rowidSafe . ', commentaire="Le marché a été modifié, les produits ont été supprimés", date_histo="' . date("Y-m-d H:i:s") . '";';
eLog($sql);
qSQL($sql, "gen");
}
$set .= 'date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user;
$sql = 'UPDATE devis SET ' . $set . ' WHERE rowid=' . $rowid . ';';
$sql = 'UPDATE devis SET ' . $set . ' WHERE rowid=' . $rowidSafe . ';';
qSQL($sql, "gen");
$retid = $rowid;
}
@@ -422,7 +468,8 @@ switch ($Route->_action) {
if ($fk_client != "0") {
//! On sauvegarde aussi les infos complémentaires du client qui peuvent ête mises à jour
$sql = 'UPDATE clients SET contact_nom="' . $contact_nom . '", contact_prenom="' . $contact_prenom . '", contact_fonction="' . $contact_fonction . '", ';
$sql .= 'email="' . $email . '", telephone="' . $telephone . '", mobile="' . $mobile . '" WHERE rowid=' . $fk_client . ';';
$fkClientSafe = intval($fk_client);
$sql .= 'email="' . $email . '", telephone="' . $telephone . '", mobile="' . $mobile . '" WHERE rowid=' . $fkClientSafe . ';';
eLog('Entete Devis Save infos client : ' . $sql);
qSQL($sql, "gen");
}
@@ -430,11 +477,15 @@ switch ($Route->_action) {
// On inscrit l'enregistrement dans le journal si il y a eu un changement de commentaire ou bien si c'est une création avec commentaire
if ($newCommentaire > 0) {
if ($newCommentaire == 1) {
$sql = 'INSERT INTO devis_histo SET fk_user = ' . $fk_user . ', fk_devis = ' . $retid . ', commentaire="' . $commentaire . '", date_histo = "' . date("Y-m-d H:i:s") . '", chk_comment_devis = 1;';
$fkUserSafe = intval($fk_user);
$retidSafe = intval($retid);
$sql = 'INSERT INTO devis_histo SET fk_user = ' . $fkUserSafe . ', fk_devis = ' . $retidSafe . ', commentaire="' . $commentaire . '", date_histo = "' . date("Y-m-d H:i:s") . '", chk_comment_devis = 1;';
eLog('Entete Devis Save Histo : ' . $sql);
qSQL($sql, "gen");
} else {
$sql = 'UPDATE devis_histo SET fk_user = ' . $fk_user . ', commentaire="' . $commentaire . '", date_histo = "' . date("Y-m-d H:i:s") . '" WHERE fk_devis = ' . $retid . ' AND chk_comment_devis = 1;';
$fkUserSafe = intval($fk_user);
$retidSafe = intval($retid);
$sql = 'UPDATE devis_histo SET fk_user = ' . $fkUserSafe . ', commentaire="' . $commentaire . '", date_histo = "' . date("Y-m-d H:i:s") . '" WHERE fk_devis = ' . $retidSafe . ' AND chk_comment_devis = 1;';
eLog('Entete Devis Save Histo : ' . $sql);
qSQL($sql, "gen");
}
@@ -494,23 +545,24 @@ switch ($Route->_action) {
$set = substr($set, 0, -2);
}
$sql = 'SELECT rowid FROM devis_speciaux WHERE fk_devis = ' . $fkDevis . ';';
$fkDevisSafe = intval($fkDevis);
$sql = 'SELECT rowid FROM devis_speciaux WHERE fk_devis = ' . $fkDevisSafe . ';';
$retSql = getinfos($sql, "gen");
if (count($retSql) == 0) {
// c'est une création
$sql = 'INSERT INTO devis_speciaux SET fk_devis = ' . $fkDevis . ', ' . $set . ';';
$sql = 'INSERT INTO devis_speciaux SET fk_devis = ' . $fkDevisSafe . ', ' . $set . ';';
eLog('Devis Speciaux Save : ' . $sql);
$retid = qSQL($sql, "gen", true);
} else {
// c'est une mise à jour
$sql = 'UPDATE devis_speciaux SET ' . $set . ' WHERE fk_devis = ' . $fkDevis . ';';
$sql = 'UPDATE devis_speciaux SET ' . $set . ' WHERE fk_devis = ' . $fkDevisSafe . ';';
eLog('Devis Speciaux Save : ' . $sql);
qSQL($sql, "gen");
$retid = $fkDevis;
}
// On boucle sur ces 5 produits spéciaux pour voir s'il faut envoyer un email à un service concerné
$sql = 'SELECT ds.* FROM devis_speciaux ds WHERE ds.fk_devis = ' . $fkDevis . ';';
$sql = 'SELECT ds.* FROM devis_speciaux ds WHERE ds.fk_devis = ' . $fkDevisSafe . ';';
$ret = getinfos($sql, "gen");
$spec = $ret[0];
@@ -518,11 +570,12 @@ switch ($Route->_action) {
// Un email est renseigné et il n'a pas été encore envoyé
// on récupère le nom, cp et ville du client
$sql = 'SELECT d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client FROM devis d WHERE d.rowid = ' . $fkDevis . ';';
$sql = 'SELECT d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client FROM devis d WHERE d.rowid = ' . $fkDevisSafe . ';';
$ret = getinfos($sql, "gen");
$dev = $ret[0];
if ($dev["fk_client"] > 0) {
$sql = 'SELECT c.code, c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid = ' . $dev["fk_client"] . ';';
$fkClientSafe = intval($dev["fk_client"]);
$sql = 'SELECT c.code, c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid = ' . $fkClientSafe . ';';
$ret = getinfos($sql, "gen");
$cli = $ret[0];
$codeClient = $cli["code"];
@@ -571,14 +624,14 @@ switch ($Route->_action) {
$ret = envoieMail($dest, $subject, $message, $copieFrom);
if ($ret == 1) {
// on met à jour le devis pour indiquer que l'email a été envoyé
$sql = 'UPDATE devis_speciaux SET chk_email = 1 WHERE fk_devis = ' . $fkDevis . ';';
$sql = 'UPDATE devis_speciaux SET chk_email = 1 WHERE fk_devis = ' . $fkDevisSafe . ';';
eLog('Devis Speciaux Save : ' . $sql);
qSQL($sql, "gen");
}
}
// on met enfin à jour le devis pour indiquer qu'il y a des spéciaux
$sql = 'UPDATE devis SET chk_speciaux = 1 WHERE rowid = ' . $fkDevis . ';';
$sql = 'UPDATE devis SET chk_speciaux = 1 WHERE rowid = ' . $fkDevisSafe . ';';
eLog('Devis Speciaux Save : ' . $sql);
qSQL($sql, "gen");
@@ -595,16 +648,31 @@ switch ($Route->_action) {
if (isset($_POST["term"])) {
if (strlen($_POST["term"]) > 0) {
$term = nettoie_input($_POST["term"]);
$sql = 'SELECT rowid, code, libelle, prix_vente FROM produits WHERE active=1 AND (code LIKE "%' . $term . '%" OR libelle LIKE "%' . $term . '%") ORDER BY code;';
try {
$db = Database::getInstance();
$sql = 'SELECT rowid, code, libelle, prix_vente FROM produits WHERE active=1 AND (code LIKE :term OR libelle LIKE :term) ORDER BY code';
$stmt = $db->prepare($sql);
$termParam = '%' . $term . '%';
$stmt->bindParam(':term', $termParam, PDO::PARAM_STR);
$stmt->execute();
$upls = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Erreur recherche produits : " . $e->getMessage());
$upls = [];
}
echo json_encode($upls);
break;
} else {
$sql = 'SELECT rowid, code, libelle, prix_vente FROM produits WHERE active=1 ORDER BY code;';
}
} else {
$sql = 'SELECT rowid, code, libelle, prix_vente FROM produits WHERE active=1 ORDER BY code;';
}
$upls = array();
$upls = getinfos($sql, "gen");
echo json_encode($upls);
if (!isset($upls)) {
$upls = array();
$upls = getinfos($sql, "gen");
echo json_encode($upls);
}
break;
case "save_devis_produits":
@@ -617,7 +685,8 @@ switch ($Route->_action) {
// on récupère les anciens produits du devis
if ($idDevis > 0) {
// on récupère les anciens produits du devis
$sql = 'SELECT fk_produit FROM devis_produits WHERE fk_devis = ' . $idDevis . ';';
$idDevisSafe = intval($idDevis);
$sql = 'SELECT fk_produit FROM devis_produits WHERE fk_devis = ' . $idDevisSafe . ';';
$tempAncProduits = getinfos($sql, 'gen');
$lstAncProduits = array();
foreach ($tempAncProduits as $prod) {
@@ -626,11 +695,12 @@ switch ($Route->_action) {
eLog("save_devis_produits : Nb anciens produits = " . count($lstAncProduits));
// On récupère les terme du marché de ce devis dans marches_listes
$sql = 'SELECT fk_marche FROM devis WHERE rowid = ' . $idDevis . ';';
$sql = 'SELECT fk_marche FROM devis WHERE rowid = ' . $idDevisSafe . ';';
$retSql = getinfos($sql, "gen");
$idMarche = $retSql[0]["fk_marche"];
eLog("save_devis_produits : fk_marche = " . $idMarche);
$sql = 'SELECT * FROM marches_listes WHERE fk_marche = ' . $idMarche . ';';
$idMarcheSafe = intval($idMarche);
$sql = 'SELECT * FROM marches_listes WHERE fk_marche = ' . $idMarcheSafe . ';';
$retSql = getinfos($sql, "gen");
if (count($retSql) == 1) {
$termeAchat = $retSql[0]["terme_achat"];
@@ -643,13 +713,13 @@ switch ($Route->_action) {
// On va vérifier le marché de ce devis pour voir s'il est hybride
$chkHybride = 0;
$lstCodesHybrides = array();
$sql = 'SELECT chk_marche_hybride FROM marches WHERE rowid=' . $idMarche . ';';
$sql = 'SELECT chk_marche_hybride FROM marches WHERE rowid=' . $idMarcheSafe . ';';
$retSql = getinfos($sql, "gen");
if (count($retSql) == 1 && $retSql[0]["chk_marche_hybride"] == 1) {
//! le marché est hybride
$chkHybride = 1;
// dans ce cas on récupère les produits de ce marché
$sql = 'SELECT code FROM produits WHERE fk_marche=' . $idMarche . ' AND active=1;';
$sql = 'SELECT code FROM produits WHERE fk_marche=' . $idMarcheSafe . ' AND active=1;';
$tempCodesHybrides = getinfos($sql, 'gen');
$lstCodesHybrides = array();
foreach ($tempCodesHybrides as $prod) {
@@ -1059,14 +1129,14 @@ switch ($Route->_action) {
if ($fkRole == 2) {
$sql = 'SELECT u.email, u.prenom, u.libelle, u.rowid
FROM users u
WHERE u.rowid = (SELECT fk_parent FROM users WHERE rowid = ' . $fk_user . ')
WHERE u.rowid = (SELECT fk_parent FROM users WHERE rowid = ' . intval($fk_user) . ')
AND u.fk_role = 1 AND u.active = 1';
}
// Si c'est un RR, on remonte à travers son DV pour trouver le DC
else if ($fkRole == 3) {
$sql = 'SELECT u.email, u.prenom, u.libelle, u.rowid
FROM users u
WHERE u.rowid = (SELECT fk_parent FROM users WHERE rowid = (SELECT fk_parent FROM users WHERE rowid = ' . $fk_user . '))
WHERE u.rowid = (SELECT fk_parent FROM users WHERE rowid = (SELECT fk_parent FROM users WHERE rowid = ' . intval($fk_user) . '))
AND u.fk_role = 1 AND u.active = 1';
}
// Si c'est une autre personne, on cherche juste le premier DC actif
@@ -1082,7 +1152,8 @@ switch ($Route->_action) {
$nom = $dest[0]["prenom"] . " " . $dest[0]["libelle"];
// 2. On récupère les infos du devis
$sql = 'SELECT d.rowid, d.montant_total_ht_remise, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, u.prenom, u.libelle FROM devis d LEFT JOIN users u ON d.fk_user=u.rowid WHERE d.rowid=' . $idDevis . ';';
$idDevisSafe = intval($idDevis);
$sql = 'SELECT d.rowid, d.montant_total_ht_remise, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, u.prenom, u.libelle FROM devis d LEFT JOIN users u ON d.fk_user=u.rowid WHERE d.rowid=' . $idDevisSafe . ';';
$devis = getinfos($sql, "gen");
if (count($devis) == 1) {
$montant = $devis[0]["montant_total_ht_remise"];
@@ -1092,7 +1163,8 @@ switch ($Route->_action) {
if ($idClient == 0) {
$nomClient = $devis[0]["lib_new_client"] . ", (" . $devis[0]["cp_new_client"] . " - " . $devis[0]["ville_new_client"] . ")";
} else {
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid=' . $idClient . ';';
$idClientSafe = intval($idClient);
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid=' . $idClientSafe . ';';
$client = getinfos($sql, "gen");
if (count($client) == 1) {
$nomClient = $client[0]["libelle"] . " (" . $client[0]["cp"] . " - " . $client[0]["ville"] . ")";
@@ -1124,7 +1196,8 @@ switch ($Route->_action) {
if ($fkRole == 3) {
// c'est un RR donc on peut envoyer à son DV
if ($fkParent > 0) {
$sql = 'SELECT u.email, u.prenom, u.libelle FROM users u WHERE u.fk_role=2 AND u.rowid=' . $fkParent . ' AND u.active=1;';
$fkParentSafe = intval($fkParent);
$sql = 'SELECT u.email, u.prenom, u.libelle FROM users u WHERE u.fk_role=2 AND u.rowid=' . $fkParentSafe . ' AND u.active=1;';
eLog("statut_devis : sql=" . $sql);
$dest = getinfos($sql, "gen");
} else {
@@ -1138,7 +1211,8 @@ switch ($Route->_action) {
$nom = $dest[0]["prenom"] . " " . $dest[0]["libelle"];
eLog("Envoi mail à " . $to . " pour le devis " . $idDevis . " de " . $nom);
// 2. On récupère les infos du devis
$sql = 'SELECT d.rowid, d.montant_total_ht_remise, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, u.prenom, u.libelle FROM devis d LEFT JOIN users u ON d.fk_user=u.rowid WHERE d.rowid=' . $idDevis . ';';
$idDevisSafe = intval($idDevis);
$sql = 'SELECT d.rowid, d.montant_total_ht_remise, d.fk_client, d.lib_new_client, d.cp_new_client, d.ville_new_client, u.prenom, u.libelle FROM devis d LEFT JOIN users u ON d.fk_user=u.rowid WHERE d.rowid=' . $idDevisSafe . ';';
$devis = getinfos($sql, "gen");
if (count($devis) == 1) {
$montant = $devis[0]["montant_total_ht_remise"];
@@ -1147,7 +1221,8 @@ switch ($Route->_action) {
if ($idClient == 0) {
$nomClient = $devis[0]["lib_new_client"] . ", (" . $devis[0]["cp_new_client"] . " - " . $devis[0]["ville_new_client"] . ")";
} else {
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid=' . $idClient . ';';
$idClientSafe = intval($idClient);
$sql = 'SELECT c.libelle, c.cp, c.ville FROM clients c WHERE c.rowid=' . $idClientSafe . ';';
$client = getinfos($sql, "gen");
if (count($client) == 1) {
$nomClient = $client[0]["libelle"] . " (" . $client[0]["cp"] . " - " . $client[0]["ville"] . ")";
@@ -1194,7 +1269,9 @@ switch ($Route->_action) {
$comment = nettoie_input($data->comment);
eLog("valide_devis : idDevis = " . $idDevis . ", commentaire = " . $comment);
$sql = 'UPDATE devis SET fk_statut_devis=4, date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user . ' WHERE rowid=' . $idDevis . ';';
$idDevisSafe = intval($idDevis);
$fkUserSafe = intval($fk_user);
$sql = 'UPDATE devis SET fk_statut_devis=4, date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fkUserSafe . ' WHERE rowid=' . $idDevisSafe . ';';
eLog($sql);
qSQL($sql, "gen");

View File

@@ -136,23 +136,25 @@ switch ($Route->_action) {
case "xml_devis":
$cid = nettoie_input($Route->_param1);
eLog("Export XML SAP Devis : " . $cid);
$cidSafe = intval($cid);
$sql = 'SELECT d.num_opportunite, d.date_demande, d.date_remise, d.fk_client, m.libelle AS lib_marche, m.numero AS num_marche, m.nom AS nom_marche, d.chk_devis_photos, d.chk_speciaux, d.commentaire AS commentaire_rr, ';
$sql .= 'd.montant_total_ht as total_devis_ht, d.montant_total_ht_remise AS total_devis_ht_remise, d.marge_totale ';
$sql .= 'FROM devis d LEFT JOIN marches m ON d.fk_marche=m.rowid WHERE d.rowid = ' . $cid . ';';
$sql .= 'FROM devis d LEFT JOIN marches m ON d.fk_marche=m.rowid WHERE d.rowid = ' . $cidSafe . ';';
$dataDevis = getinfos($sql);
if ($dataDevis) {
$dataDevis = $dataDevis[0];
if ($dataDevis["fk_client"] == 0) {
// Pas de client issu de la table clients mais un client saisi manuellement
$sql = 'SELECT "0" AS code, d.lib_new_client AS etablissement, d.adresse1_new_client AS adresse1, d.adresse2_new_client AS adresse2, d.adresse3_new_client AS adresse3, ';
$sql .= 'cp_new_client AS codepostal, ville_new_client AS ville FROM devis d WHERE d.rowid = ' . $cid . ';';
$sql .= 'cp_new_client AS codepostal, ville_new_client AS ville FROM devis d WHERE d.rowid = ' . $cidSafe . ';';
$dataClient = getinfos($sql);
$sql = 'SELECT d.contact_new_nom AS nom, d.contact_new_prenom AS prenom, d.contact_new_fonction AS fonction, d.new_telephone AS fixe, d.new_mobile AS mobile, d.new_email AS email FROM devis d WHERE d.rowid = ' . $cid . ';';
$sql = 'SELECT d.contact_new_nom AS nom, d.contact_new_prenom AS prenom, d.contact_new_fonction AS fonction, d.new_telephone AS fixe, d.new_mobile AS mobile, d.new_email AS email FROM devis d WHERE d.rowid = ' . $cidSafe . ';';
$dataContact = getinfos($sql);
} else {
$sql = 'SELECT c.code, c.libelle AS etablissement, c.adresse1, c.adresse2, c.adresse3, c.cp AS codepostal, c.ville FROM clients c WHERE c.rowid = ' . $dataDevis["fk_client"] . ';';
$fkClientSafe = intval($dataDevis["fk_client"]);
$sql = 'SELECT c.code, c.libelle AS etablissement, c.adresse1, c.adresse2, c.adresse3, c.cp AS codepostal, c.ville FROM clients c WHERE c.rowid = ' . $fkClientSafe . ';';
$dataClient = getinfos($sql);
$sql = 'SELECT c.contact_nom AS nom, c.contact_prenom AS prenom, c.contact_fonction AS fonction, c.telephone AS fixe, c.mobile, c.email FROM clients c WHERE c.rowid = ' . $dataDevis["fk_client"] . ';';
$sql = 'SELECT c.contact_nom AS nom, c.contact_prenom AS prenom, c.contact_fonction AS fonction, c.telephone AS fixe, c.mobile, c.email FROM clients c WHERE c.rowid = ' . $fkClientSafe . ';';
$dataContact = getinfos($sql);
}
$dataClient = $dataClient[0];
@@ -160,7 +162,7 @@ switch ($Route->_action) {
$dataClient['contact'] = $dataContact[0];
$sql = 'SELECT dp.fk_produit AS id, dp.code, dp.libelle AS designation, dp.prix_vente, dp.qte AS quantite, dp.remise, dp.pu_vente_remise AS pu_vente_avec_remise, dp.totalht AS total_ht, dp.marge, dp.commentaire ';
$sql .= 'FROM devis_produits dp WHERE dp.fk_devis = ' . $cid . ' ORDER BY dp.ordre;';
$sql .= 'FROM devis_produits dp WHERE dp.fk_devis = ' . $cidSafe . ' ORDER BY dp.ordre;';
$dataProduits = getinfos($sql);
// $sql = 'SELECT fk_product, qty, prix_unitaire, remise, total_ht, total_ttc FROM lignes_speciales WHERE fk_devis = $cid';
@@ -223,12 +225,15 @@ switch ($Route->_action) {
error_log("Taille du XML généré : " . strlen($xml));
error_log("Taille du fichier créé : " . filesize($xmlPathAndName));
$sql = 'SELECT m.rowid FROM medias m WHERE m.support_rowid = ' . $cid . ' AND support="devis_xml_sap";';
$sql = 'SELECT m.rowid FROM medias m WHERE m.support_rowid = ' . $cidSafe . ' AND support="devis_xml_sap";';
$media = getinfos($sql);
if ($media) {
$sql = 'UPDATE medias SET dir0="pub/files/upload/devis/", fichier="' . $xmlName . '", type_fichier="xml", date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user . ' WHERE rowid = ' . $media[0]['rowid'] . ';';
$rowidSafe = intval($media[0]['rowid']);
$fkUserSafe = intval($fk_user);
$sql = 'UPDATE medias SET dir0="pub/files/upload/devis/", fichier="' . $xmlName . '", type_fichier="xml", date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fkUserSafe . ' WHERE rowid = ' . $rowidSafe . ';';
} else {
$sql = 'INSERT INTO medias (support, dir0, fichier, type_fichier, support_rowid, date_creat, fk_user_creat) VALUES ("devis_xml_sap", "pub/files/upload/devis/", "' . $xmlName . '", "xml", ' . $cid . ', "' . date("Y-m-d H:i:s") . '", ' . $fk_user . ');';
$fkUserSafe = intval($fk_user);
$sql = 'INSERT INTO medias (support, dir0, fichier, type_fichier, support_rowid, date_creat, fk_user_creat) VALUES ("devis_xml_sap", "pub/files/upload/devis/", "' . $xmlName . '", "xml", ' . $cidSafe . ', "' . date("Y-m-d H:i:s") . '", ' . $fkUserSafe . ');';
}
qSQL($sql);

View File

@@ -137,18 +137,53 @@ switch ($Route->_action) {
$mobile = $data[14];
$email = nettoie_text($data[15]);
$sql = "SELECT c.* FROM clients c WHERE c.code='" . $code . "';";
$record = getinfos($sql, "gen");
try {
$db = Database::getInstance();
$sql = 'SELECT c.* FROM clients c WHERE c.code = :code';
$stmt = $db->prepare($sql);
$stmt->bindParam(':code', $code, PDO::PARAM_STR);
$stmt->execute();
$record = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Erreur recherche client : " . $e->getMessage());
$record = [];
}
switch (count($record)) {
case 0:
//! Code client non trouvé = nouveau client
$sql = 'INSERT INTO clients SET code="' . $code . '", libelle="' . $libelle . '", siret="' . $siret . '", adresse1="' . $adresse1 . '", adresse2="' . $adresse2 . '", adresse3="' . $adresse3 . '", cp="' . $cp . '", ville="' . $ville . '", ';
$sql .= 'type_client="' . $fkType . '", contact_nom="' . $contactNom . '", contact_prenom="' . $contactPrenom . '", contact_fonction="' . $contactFonction . '", telephone="' . $telephone . '", mobile="' . $mobile . '", email="' . $email . '", chk_import=1;';
fwrite($fhlog, $row . "---" . $sql . "\r\n");
$fkClient = qSQL($sql, "gen", true);
try {
$db = Database::getInstance();
$sql = 'INSERT INTO clients SET code = :code, libelle = :libelle, siret = :siret, adresse1 = :adresse1, adresse2 = :adresse2, adresse3 = :adresse3, cp = :cp, ville = :ville, ';
$sql .= 'type_client = :type_client, contact_nom = :contact_nom, contact_prenom = :contact_prenom, contact_fonction = :contact_fonction, telephone = :telephone, mobile = :mobile, email = :email, chk_import = 1';
$stmt = $db->prepare($sql);
$stmt->execute([
':code' => $code,
':libelle' => $libelle,
':siret' => $siret,
':adresse1' => $adresse1,
':adresse2' => $adresse2,
':adresse3' => $adresse3,
':cp' => $cp,
':ville' => $ville,
':type_client' => $fkType,
':contact_nom' => $contactNom,
':contact_prenom' => $contactPrenom,
':contact_fonction' => $contactFonction,
':telephone' => $telephone,
':mobile' => $mobile,
':email' => $email
]);
$fkClient = $db->lastInsertId();
fwrite($fhlog, $row . "--- Ajout client avec requête préparée\r\n");
} catch (Exception $e) {
error_log("Erreur insertion client : " . $e->getMessage());
fwrite($fhlog, "Erreur insertion : " . $e->getMessage() . "\r\n");
$fkClient = 0;
}
fwrite($fhlog, "--- Ajout fait\r\n");
$message = "Importation Clients SAP : Le client " . $libelle . " vient d'être créé en " . $ville . " (" . $cp . ")";
$sql = 'INSERT INTO notifications SET dateheure="' . date("Y-m-d H:i:s") . '", fk_user=' . $fkUser . ', action="Création fiche", theme="Fiche Client", message="' . $message . '";';
$fkUserSafe = intval($fkUser);
$sql = 'INSERT INTO notifications SET dateheure="' . date("Y-m-d H:i:s") . '", fk_user=' . $fkUserSafe . ', action="Création fiche", theme="Fiche Client", message="' . $message . '";';
qSQL($sql, "gen");
fwrite($fhlog, "--- Fin Creation ---" . "\r\n");
@@ -158,11 +193,34 @@ switch ($Route->_action) {
//! Un seul enregistrement trouvé : on met à jour le client
$rec = $record[0];
$sql = 'UPDATE clients SET libelle="' . $libelle . '", siret="' . $siret . '", adresse1="' . $adresse1 . '", adresse2="' . $adresse2 . '", adresse3="' . $adresse3 . '", cp="' . $cp . '", ville="' . $ville . '", ';
$sql .= 'type_client="' . $fkType . '", contact_nom="' . $contactNom . '", contact_prenom="' . $contactPrenom . '", contact_fonction="' . $contactFonction . '", telephone="' . $telephone . '", mobile="' . $mobile . '", email="' . $email . '", chk_import=1 ';
$sql .= 'WHERE code="' . $code . '";';
qSQL($sql);
fwrite($fhlog, $row . "---" . $sql . "\r\n");
try {
$db = Database::getInstance();
$sql = 'UPDATE clients SET libelle = :libelle, siret = :siret, adresse1 = :adresse1, adresse2 = :adresse2, adresse3 = :adresse3, cp = :cp, ville = :ville, ';
$sql .= 'type_client = :type_client, contact_nom = :contact_nom, contact_prenom = :contact_prenom, contact_fonction = :contact_fonction, telephone = :telephone, mobile = :mobile, email = :email, chk_import = 1 ';
$sql .= 'WHERE code = :code';
$stmt = $db->prepare($sql);
$stmt->execute([
':libelle' => $libelle,
':siret' => $siret,
':adresse1' => $adresse1,
':adresse2' => $adresse2,
':adresse3' => $adresse3,
':cp' => $cp,
':ville' => $ville,
':type_client' => $fkType,
':contact_nom' => $contactNom,
':contact_prenom' => $contactPrenom,
':contact_fonction' => $contactFonction,
':telephone' => $telephone,
':mobile' => $mobile,
':email' => $email,
':code' => $code
]);
fwrite($fhlog, $row . "--- MàJ client avec requête préparée\r\n");
} catch (Exception $e) {
error_log("Erreur mise à jour client : " . $e->getMessage());
fwrite($fhlog, "Erreur MàJ : " . $e->getMessage() . "\r\n");
}
fwrite($fhlog, "--- Fin MaJ ---" . "\r\n");
break;

View File

@@ -194,19 +194,35 @@ switch ($Route->_action) {
case "getdata":
$chp = $_POST["chp"];
$typ = $Route->_param1;
$sql = "";
$upls = array();
switch ($typ) {
case "tiers":
$sql = "SELECT $chp AS data FROM clients WHERE rowid=" . $fk_tiers . ";";
$dbn = "groupe";
// SÉCURITÉ : Liste blanche des colonnes autorisées
$allowedColumns = ['code', 'libelle', 'adresse1', 'adresse2', 'adresse3', 'cp', 'ville',
'contact_nom', 'contact_prenom', 'contact_fonction', 'telephone', 'mobile', 'email'];
if (!in_array($chp, $allowedColumns)) {
echo json_encode(array('error' => 'Colonne non autorisée'));
break;
}
try {
$db = Database::getInstance();
// SÉCURITÉ : Utilisation de requête préparée pour l'ID
$sql = "SELECT `$chp` AS data FROM clients WHERE rowid = :id";
$stmt = $db->prepare($sql);
$stmt->execute([':id' => intval($fk_tiers)]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
$upls = $result;
}
} catch (Exception $e) {
error_log("Erreur getdata : " . $e->getMessage());
}
break;
}
$upls = array();
if ($sql != "") {
$upls = getinfos($sql, $dbn);
$upls = $upls[0];
}
echo json_encode($upls);
break;
@@ -216,63 +232,8 @@ switch ($Route->_action) {
}
break;
case "autocomplete":
if (isset($_POST["term"])) {
$term = $_POST["term"];
$tabl = $_POST["table"];
$fiel = $_POST["field"];
$fiel2 = isset($_POST["field2"]) ? $_POST["field2"] : "";
$fiel3 = isset($_POST["field3"]) ? $_POST["field3"] : "";
$fiel4 = isset($_POST["field4"]) ? $_POST["field4"] : "";
$fiel5 = isset($_POST["field5"]) ? $_POST["field5"] : "";
$fiel6 = isset($_POST["field6"]) ? $_POST["field6"] : "";
$fiel7 = isset($_POST["field7"]) ? $_POST["field7"] : "";
$fiel8 = isset($_POST["field8"]) ? $_POST["field8"] : "";
$grou = isset($_POST["group"]) ? $_POST["group"] : "";
if (strtolower(substr($tabl, 0, 7)) == "select ") {
//! C'est directement une requête
$sql = $tabl;
$minisql = strtolower($sql);
$poswhere = strpos($minisql, " where ");
if ($poswhere === FALSE) {
//! il n'y a pas de clause WHERE dans la requête
//! on regarde s'il y a une clause ORDER BY pour pouvoir insérer la clause WHERE juste avant
$posorder = strpos($minisql, " order by ");
if ($posorder === FALSE) {
//! il n'y a pas non plus de clause ORDER BY dans la requête, on ajoute le WHERE à la fin
$posgroup = strpos($minisql, " group by ");
if ($posgroup === FALSE) {
$sql = str_replace(';', ' WHERE ' . $fiel . ' LIKE "%' . $term . '%";', $sql);
} else {
//! il y a une clause GROUP BY
$sql = str_replace(' GROUP BY ', ' WHERE ' . $fiel . ' LIKE "%' . $term . '%" GROUP BY ', $sql);
}
} else {
//! il y a une clause ORDER BY
$sql = str_replace(' ORDER BY ', ' WHERE ' . $fiel . ' LIKE "%' . $term . '%" ORDER BY ', $sql);
}
} else {
//! il y a déjà une condition WHERE dans la requête définie
$sql = str_replace(' WHERE ', ' WHERE ' . $fiel . ' LIKE "%' . $term . '%" AND ', $sql);
}
} else {
if ($grou == "") {
$sql = 'SELECT * FROM ' . $tabl . ' WHERE ' . $fiel . ' LIKE "%' . $term . '%" ORDER BY ' . $fiel . ';';
} else {
$sql = 'SELECT * FROM ' . $tabl . ' WHERE ' . $fiel . ' LIKE "%' . $term . '%" GROUP BY ' . $fiel . ' ORDER BY ' . $fiel . ';';
}
}
eLog("autocomplete : " . $sql);
$res = qSQL($sql);
$rows = array();
while ($r = mysqli_fetch_assoc($res)) {
$rows[] = $r;
}
echo json_encode($rows);
exit();
}
break;
// case "autocomplete" supprimé car non utilisé dans l'application
// L'autocomplétion est gérée côté client JavaScript
case "get_context":
//! Renvoie le contexte de l'utilisateur
@@ -288,11 +249,23 @@ switch ($Route->_action) {
//! Réception et lecture de la demande en json
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'SELECT c.* FROM clients c WHERE c.rowid=' . $cid . ';';
echo getinfos($sql, "gen", "json");
// SÉCURITÉ : Validation de l'ID et requête préparée
$cid = intval($data->cid);
if ($cid <= 0) {
echo json_encode(array('error' => 'ID client invalide'));
break;
}
try {
$db = Database::getInstance();
$result = $db->getById('clients', $cid);
echo json_encode($result ?: array());
} catch (Exception $e) {
error_log("Erreur load_client : " . $e->getMessage());
echo json_encode(array('error' => 'Erreur lors du chargement du client'));
}
} else {
echo "Erreur : pas de client";
echo json_encode(array('error' => 'Pas de client spécifié'));
}
break;
@@ -301,14 +274,35 @@ switch ($Route->_action) {
//! Réception et lecture de la demande en json
$data = json_decode(file_get_contents("php://input"));
if (isset($data->search)) {
$search = nettoie_input($data->search);
$sql = 'SELECT c.rowid, c.libelle, c.type_client, c.adresse1, c.cp, c.ville FROM clients c ';
$sql .= 'WHERE c.libelle LIKE "%' . $search . '%" OR c.adresse1 LIKE "%' . $search . '%" OR c.cp LIKE "%' . $search . '%" OR c.ville LIKE "%' . $search . '%" OR c.contact_nom LIKE "%' . $search . '%" OR c.contact_prenom LIKE "%' . $search . '%" OR c.contact_fonction LIKE "%' . $search . '%" OR c.email LIKE "%' . $search . '%" ';
$sql .= 'ORDER BY c.libelle;';
echo getinfos($sql, "gen", "json");
// SÉCURITÉ : Utilisation de requêtes préparées pour la recherche
$search = trim($data->search);
try {
$db = Database::getInstance();
$sql = 'SELECT c.rowid, c.libelle, c.type_client, c.adresse1, c.cp, c.ville FROM clients c
WHERE c.libelle LIKE :search
OR c.adresse1 LIKE :search
OR c.cp LIKE :search
OR c.ville LIKE :search
OR c.contact_nom LIKE :search
OR c.contact_prenom LIKE :search
OR c.contact_fonction LIKE :search
OR c.email LIKE :search
ORDER BY c.libelle';
$stmt = $db->prepare($sql);
$searchParam = '%' . $search . '%';
$stmt->bindParam(':search', $searchParam, PDO::PARAM_STR);
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($results);
} catch (Exception $e) {
error_log("Erreur search_clients : " . $e->getMessage());
echo json_encode(array('error' => 'Erreur lors de la recherche'));
}
} else {
$ret = array('ret' => "ko");
echo json_encode($ret);
echo json_encode(array('ret' => "ko"));
}
break;
@@ -516,21 +510,36 @@ switch ($Route->_action) {
//! Réception de l'id du marché à supprimer
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'DELETE FROM marches m WHERE m.rowid=' . $cid . ';';
qSQL($sql, "gen");
eLog($sql);
//! on supprime aussi la ligne dans la table marches_listes
$sql = 'DELETE FROM marches_listes ml WHERE ml.fk_marche=' . $cid . ';';
qSQL($sql, "gen");
eLog($sql);
//! on supprime aussi les lignes produits de ce marché dans la table produits
$sql = 'DELETE FROM produits p WHERE p.fk_marche=' . $cid . ';';
qSQL($sql, "gen");
eLog($sql);
$ret = array('ret' => "ok", 'msg' => 'Marché supprimé');
echo json_encode($ret);
// SÉCURITÉ : Validation de l'ID comme entier
$cid = intval($data->cid);
if ($cid <= 0) {
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
break;
}
try {
$db = Database::getInstance();
// Utilisation de requêtes préparées pour la suppression
$sql1 = 'DELETE FROM marches WHERE rowid = :id';
$stmt1 = $db->prepare($sql1);
$stmt1->execute(['id' => $cid]);
$sql2 = 'DELETE FROM marches_listes WHERE fk_marche = :id';
$stmt2 = $db->prepare($sql2);
$stmt2->execute(['id' => $cid]);
$sql3 = 'DELETE FROM produits WHERE fk_marche = :id';
$stmt3 = $db->prepare($sql3);
$stmt3->execute(['id' => $cid]);
eLog("Marché supprimé : ID=$cid");
$ret = array('ret' => "ok", 'msg' => 'Marché supprimé');
echo json_encode($ret);
} catch (Exception $e) {
eLog("Erreur suppression marché : " . $e->getMessage());
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
}
} else {
$ret = array('ret' => "ko", 'msg' => 'Marché non supprimé');
echo json_encode($ret);
@@ -703,17 +712,32 @@ switch ($Route->_action) {
//! Réception et lecture de la demande en json
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
// TODO : Supprimer les devis créés par cet utilisateur
$sql = 'DELETE FROM users WHERE rowid=' . $cid . ';';
eLog($sql);
qSQL($sql, "gen");
$ret = array('ret' => "ok");
echo json_encode($ret);
// SÉCURITÉ : Validation de l'ID comme entier
$cid = intval($data->cid);
if ($cid <= 0) {
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
break;
}
try {
$db = Database::getInstance();
// TODO : Supprimer les devis créés par cet utilisateur
// Utilisation de la fonction sécurisée deleteById
$result = $db->deleteById('users', $cid);
if ($result) {
eLog("Utilisateur supprimé : ID=$cid");
echo json_encode(array('ret' => "ok"));
} else {
echo json_encode(array('ret' => "ko", 'msg' => 'Utilisateur non trouvé'));
}
} catch (Exception $e) {
eLog("Erreur suppression utilisateur : " . $e->getMessage());
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
}
} else {
$ret = array('ret' => "ko");
echo json_encode($ret);
echo json_encode(array('ret' => "ko", 'msg' => 'ID manquant'));
}
break;
@@ -757,10 +781,20 @@ switch ($Route->_action) {
$filename = "devis_" . $cid . "_" . date('Y_m_d_hi') . ".csv";
$fields = array("Code", "Etablissement", "Adresse 1", "Adresse 2");
$sql = 'SELECT c.code, c.libelle, c.adresse1, c.adresse2 FROM clients c WHERE c.rowid=' . $devis["fk_client"] . ';';
eLog($sql);
$cli = getinfos($sql, "gen");
$client = $cli[0];
// SÉCURITÉ : Utilisation de requête préparée pour l'ID client
try {
$db = Database::getInstance();
$sql = 'SELECT c.code, c.libelle, c.adresse1, c.adresse2 FROM clients c WHERE c.rowid = :id';
$stmt = $db->prepare($sql);
$stmt->execute([':id' => intval($devis["fk_client"])]);
$client = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$client) {
$client = ['code' => '', 'libelle' => '', 'adresse1' => '', 'adresse2' => ''];
}
} catch (Exception $e) {
error_log("Erreur export_sap_devis : " . $e->getMessage());
$client = ['code' => '', 'libelle' => '', 'adresse1' => '', 'adresse2' => ''];
}
$excelData = implode("\t", array_values($fields)) . "\n";
@@ -840,13 +874,29 @@ switch ($Route->_action) {
//! Réception et lecture de la demande en json
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$sql = 'DELETE FROM infos i WHERE i.rowid=' . $cid . ';';
eLog($sql);
qSQL($sql, "gen");
$ret = array('ret' => "ok");
echo json_encode($ret);
// SÉCURITÉ : Validation de l'ID comme entier
$cid = intval($data->cid);
if ($cid <= 0) {
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
break;
}
try {
$db = Database::getInstance();
$sql = 'DELETE FROM infos WHERE rowid = :id';
$stmt = $db->prepare($sql);
$result = $stmt->execute(['id' => $cid]);
if ($result) {
eLog("Info supprimée : ID=$cid");
echo json_encode(array('ret' => "ok"));
} else {
echo json_encode(array('ret' => "ko", 'msg' => 'Info non trouvée'));
}
} catch (Exception $e) {
eLog("Erreur suppression info : " . $e->getMessage());
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
}
}
break;