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

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