Files
Cleo/controllers/cjxdevis.php
Pierre 443b0509df 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
2025-09-12 20:25:48 +02:00

1308 lines
66 KiB
PHP

<?php
//! Page des requêtes AJAX de la page devis
global $Session;
global $Conf;
global $Route;
$fk_user = $Session->_user["rowid"];
$fk_role = $Session->_user["fk_role"];
switch ($Route->_action) {
case "duplic_devis":
// duplication d'un devis
if ($_POST) {
$rowid = nettoie_input($_POST["rid"]);
//! 1. Recherche du devis d'origine par son 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
if (count($leDevis) == 1) {
$sql = 'INSERT INTO devis (fk_user, fk_client, fk_marche, dossier, chk_devis_photos, chk_speciaux, montant_total_ht, montant_total_ht_remise, marge_totale, seuil_marge_rr, seuil_marge_dv, ';
$sql .= 'lib_new_client, type_new_client, adresse1_new_client, adresse2_new_client, adresse3_new_client, cp_new_client, ville_new_client, ';
$sql .= 'contact_new_nom, contact_new_prenom, contact_new_fonction, new_telephone, new_mobile, new_email, date_creat, fk_user_creat) ';
$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 = ' . $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 = ' . $rowidSafe . ';';
$aProduits = getinfos($sql, 'gen');
eLog(count($aProduits) . " lignes produits trouvées");
foreach ($aProduits as $aProd) {
$sql = 'INSERT INTO devis_produits SET fk_devis = ' . $newRowid . ', fk_produit = ' . $aProd["fk_produit"] . ', code="' . $aProd["code"] . '", libelle="' . $aProd["libelle"] . '", ';
$sql .= 'qte = ' . $aProd["qte"] . ', totalht = ' . $aProd["totalht"] . ', remise = ' . $aProd["remise"] . ', marge = ' . $aProd["marge"] . ', ';
$sql .= 'prix_achat_net = ' . $aProd["prix_achat_net"] . ', prix_vente = ' . $aProd["prix_vente"] . ', pu_vente_remise = ' . $aProd["pu_vente_remise"] . ', ';
$sql .= 'prc_discount_1 = ' . $aProd["prc_discount_1"] . ', quantite_1 = ' . $aProd["quantite_1"] . ', prc_discount_2 = ' . $aProd["prc_discount_2"] . ', ';
$sql .= 'quantite_2 = ' . $aProd["quantite_2"] . ', prc_discount_3 = ' . $aProd["prc_discount_3"] . ', quantite_3 = ' . $aProd["quantite_3"] . ', ';
$sql .= 'prc_discount_4 = ' . $aProd["prc_discount_4"] . ', quantite_4 = ' . $aProd["quantite_4"] . ', prc_discount_5 = ' . $aProd["prc_discount_5"] . ', ';
$sql .= 'quantite_5 = ' . $aProd["quantite_5"] . ', prc_discount_6 = ' . $aProd["prc_discount_6"] . ', quantite_6 = ' . $aProd["quantite_6"] . ', ';
$sql .= 'commentaire = "' . $aProd["commentaire"] . '", chk_variante = ' . $aProd["chk_variante"] . ';';
eLog($sql);
qSQL($sql, "gen");
}
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
$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
$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");
// on met à jour la session avec le rowid de ce nouveau devis dupliqué
$_SESSION["lastDevis"] = $newRowid;
eLog("Mise à jour des infos du nouveau devis");
}
}
}
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":
$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);
break;
case "load_devis":
//! On récupère les infos du devis (en-tête)
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$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 = ' . $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, ';
$sql .= 'd.date_demande, d.date_remise, d.montant_total_ht_remise, d.marge_totale, d.commentaire, d.comment_devis, d.chk_clients_secteur, d.chk_speciaux, ';
$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, ';
$sql .= 'd.comment_geste_comm, d.comment_validat, d.chk_validat, d.fk_user_validat, d.date_validat, ';
$sql .= 'xs.libelle as lib_statut_devis, c.code, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.cp, c.ville, c.type_client, ';
$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 = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
} else {
$ret = array('ret' => "ko", 'msg' => 'Erreur lors du chargement du devis (en-tête)');
echo json_encode($ret);
}
break;
case "load_devis_produits":
// On récupère les infos des produits enregistrés pour ce devis
// ainsi que les seuils de marge RR et DV enregistrés dans la table produits_familles
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$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');
echo json_encode($ret);
}
break;
case "load_clients_devis":
//! On récupère les infos des clients de son secteur ou de toute la France, suivant le devis chk_clients_secteur, utilisé aussi pour l'autocomplete de la recherche de clients
$data = json_decode(file_get_contents("php://input"));
if (isset($data->secteur)) {
$chkSecteur = nettoie_input($data->secteur);
$fkUser = nettoie_input($data->user);
$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
$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 . ') ';
}
$sql .= 'ORDER BY libelle;';
eLog($sql);
echo getinfos($sql, "gen", "json");
} else {
$ret = array('ret' => "ko", 'msg' => 'Erreur lors du chargement des clients');
echo json_encode($ret);
}
break;
case "load_familles":
//! On récupère les infos des familles de produits
$sql = 'SELECT * FROM x_familles;';
echo getinfos($sql, "gen", "json");
break;
case "load_devis_marche_infos":
//! On récupère les infos du marché lié au devis
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$cidSafe = intval($cid);
$sql = 'SELECT m.* FROM marches m WHERE m.rowid = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
}
break;
case "load_devis_marche_produits":
//! Charge les produits enregistrés pour un marché
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
// On récupère les terme du marché dans marches_listes
$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"];
$termeVente = $retSql[0]["terme_vente"];
} else {
$termeAchat = "";
$termeVente = "";
}
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 = ' . $cidSafe . ';';
$retSql = getinfos($sql, "gen");
$chkTG = $retSql[0]["chk_remise_sur_tg"];
$chkHybride = $retSql[0]["chk_marche_hybride"];
if ($chkTG) {
// On charge uniquement les produits de la liste tarifaire générale TG ou Hors Marché
$cid = 999;
$termeAchat = '';
$termeVente = '';
$chkHybride = 0;
}
}
$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 = ' . $cidSafe . ' AND p.active=1 ORDER BY xf.ordre, pf.ordre;';
$upls = getinfos($sql, "gen");
if ($cid != "999") {
// ce n'est pas le hors marché
// On crée une liste des codes produits récupérés
$codes = array();
foreach ($upls as $line) {
$codes[] = '"' . $line["code"] . '"';
}
// et on crée une chaîne de caractères à partir de cette liste avec les codes séparés par des virgules
$lstCodes = implode(",", $codes);
if ($termeAchat == 'Purchasing') {
// cela veut dire qu'on doit aller chercher dans le hors marché le prix d'achat net des produits de ce marché
foreach ($upls as $index => $line) {
$sql = 'SELECT p.prix_achat_net, prc_discount_1, quantite_1, prc_discount_2, quantite_2, prc_discount_3, quantite_3, prc_discount_4, quantite_4, prc_discount_5, quantite_5, prc_discount_6, quantite_6 ';
$sql .= 'FROM produits p WHERE p.code = "' . $line["code"] . '" AND p.fk_marche=999;';
$retSql = getinfos($sql, "gen");
if (count($retSql) == 1) {
$upls[$index]["prix_achat_net"] = $retSql[0]["prix_achat_net"];
$upls[$index]["prc_discount_1"] = $retSql[0]["prc_discount_1"];
$upls[$index]["quantite_1"] = $retSql[0]["quantite_1"];
$upls[$index]["prc_discount_2"] = $retSql[0]["prc_discount_2"];
$upls[$index]["quantite_2"] = $retSql[0]["quantite_2"];
$upls[$index]["prc_discount_3"] = $retSql[0]["prc_discount_3"];
$upls[$index]["quantite_3"] = $retSql[0]["quantite_3"];
$upls[$index]["prc_discount_4"] = $retSql[0]["prc_discount_4"];
$upls[$index]["quantite_4"] = $retSql[0]["quantite_4"];
$upls[$index]["prc_discount_5"] = $retSql[0]["prc_discount_5"];
$upls[$index]["quantite_5"] = $retSql[0]["quantite_5"];
$upls[$index]["prc_discount_6"] = $retSql[0]["prc_discount_6"];
$upls[$index]["quantite_6"] = $retSql[0]["quantite_6"];
}
}
}
//! On vérifie si des produits ont bien été récupérés, sinon on charge les produits de la liste tarifaire générale
if ($chkHybride == 1) {
// AJOUT 20/02/25 : si marché hybride, les produits de ce marché uniquement sont en prix nets
foreach ($upls as $index => $line) {
$upls[$index]["chk_prix_net"] = "1";
}
// AJOUT 20/02/25 : On ajoute une colonne chk_prix_net qui indique que les autres produits du marché TG n'ont pas de prix_net
$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=999 AND p.code not in (' . $lstCodes . ') AND p.active=1 ORDER BY xf.ordre, pf.ordre;';
eLog($sql);
// Et enfin, on fusionne les 2 tableaux
$upls = array_merge($upls, getinfos($sql, "gen"));
}
}
echo json_encode($upls);
}
break;
case "load_devis_speciaux":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->cid);
$cidSafe = intval($cid);
$sql = 'SELECT * FROM devis_speciaux WHERE fk_devis = ' . $cidSafe . ';';
echo getinfos($sql, "gen", "json");
}
break;
case "delete_devis":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$cid = nettoie_input($data->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) {
$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"];
$cpClient = $client["cp"];
$villeClient = $client["ville"];
} else {
$libClient = $devis["lib_new_client"];
$cpClient = $devis["cp_new_client"];
$villeClient = $devis["ville_new_client"];
}
$fkUserDevis = $devis["fk_user"];
$sql = 'DELETE FROM devis_speciaux WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$sql = 'DELETE FROM devis_histo WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $cidSafe . ';';
qSQL($sql, "gen");
$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) {
$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"];
$sujet = "Suppression d'un de vos devis";
$message = "Bonjour " . $nom . ",<br><br>";
$message .= "Votre devis #" . $cid . " vient d'être supprimé.<br><br>";
$message .= "Client : " . $libClient . ", " . $cpClient . " " . $villeClient . "<br>";
$message .= "Pour un montant total HT remisé de " . $devis["montant_total_ht_remise"] . " €<br><br>";
$message .= "Cordialement,<br>";
$message .= "Message généré automatiquement par l'application CLEO de gestion des devis<br>";
eLog("Envoi d'un email à " . $email . " pour la suppression du devis #" . $cid);
envoieMail($email, $sujet, $message);
}
echo json_encode(array("success" => true));
}
break;
case "save_devis_entete":
// Enregistre l'onglet Entête d'un devis en Création ou Modification
if ($_POST) {
$rowid = nettoie_input($_POST["rowid"]);
$fk_client = nettoie_input($_POST["fk_client"]);
$fk_user = nettoie_input($_POST["fk_user"]);
$fk_marche = nettoie_input($_POST["fk_marche"]);
$num_opportunite = nettoie_input($_POST["num_opportunite"]);
// On récupère les dates au format MySQL
$date_demande = $_POST["date_demande"];
if (strlen($date_demande) != 10) $date_demande = "";
$date_remise = $_POST["date_remise"];
if (strlen($date_remise) != 10) $date_remise = "";
if (isset($_POST["chk_devis_photos"])) {
if ($_POST["chk_devis_photos"] == false || $_POST["chk_devis_photos"] == 0) {
$chk_devis_photos = 0;
} else {
$chk_devis_photos = 1;
}
} else {
$chk_devis_photos = 0;
}
$commentaire = nettoie_input($_POST["commentaire"]);
$newCommentaire = 0;
$contact_nom = nettoie_input($_POST["contact_nom"]);
$contact_prenom = nettoie_input($_POST["contact_prenom"]);
$contact_fonction = nettoie_input($_POST["contact_fonction"]);
$email = nettoie_input($_POST["email"]);
$telephone = formattel(nettoie_input($_POST["telephone"]));
$mobile = formattel(nettoie_input($_POST["mobile"]));
$set = 'fk_client=' . $fk_client . ', num_opportunite="' . $num_opportunite . '", date_demande="' . $date_demande . '", date_remise="' . $date_remise . '", ';
$set .= 'fk_user=' . $fk_user . ', fk_marche=' . $fk_marche . ', commentaire="' . $commentaire . '", chk_devis_photos=' . $chk_devis_photos . ', ';
if ($fk_client == 0) {
//! C'est un nouveau client : on enregistre ces infos et celle du contact dans le devis et non au niveau de la table clients
$libNewClient = nettoie_input($_POST["lib_client"]);
$typNewClient = nettoie_input($_POST["type_client"]);
$adr1NewClient = nettoie_input($_POST["adresse1"]);
$adr2NewClient = nettoie_input($_POST["adresse2"]);
$adr3NewClient = nettoie_input($_POST["adresse3"]);
$cpNewClient = nettoie_input($_POST["cp"]);
// Si le CP a une longueur de 4, on rajoute un 0 devant
if (strlen($cpNewClient) == 4) $cpNewClient = "0" . $cpNewClient;
$villeNewClient = nettoie_input($_POST["ville"]);
$set .= 'lib_new_client="' . $libNewClient . '", type_new_client="' . $typNewClient . '", adresse1_new_client="' . $adr1NewClient . '", adresse2_new_client="' . $adr2NewClient . '", adresse3_new_client="' . $adr3NewClient . '", cp_new_client="' . $cpNewClient . '", ville_new_client="' . $villeNewClient . '", ';
$set .= 'contact_new_nom="' . $contact_nom . '", contact_new_prenom="' . $contact_prenom . '", contact_new_fonction="' . $contact_fonction . '", new_email="' . $email . '", new_telephone="' . $telephone . '", new_mobile="' . $mobile . '", ';
}
if ($_POST["rowid"] == 0) {
//! C'est un nouveau devis
//! On le range dans un dossier
if ($commentaire != "") $newCommentaire = 1;
$cp = nettoie_input($_POST["cp"]);
// Si le CP a une longueur de 4, on rajoute un 0 devant
if (strlen($cp) == 4) $cp = "0" . $cp;
$dossier = substr($cp, 0, 2);
$set .= 'dossier="' . $dossier . '", fk_statut_devis=1, date_creat="' . date("Y-m-d H:i:s") . '", fk_user_creat=' . $fk_user;
$sql = 'INSERT INTO devis SET ' . $set . ';';
$retid = qSQL($sql, "gen", true);
} else {
//! c'est une mise à jour d'un devis existant
$rowidSafe = intval($rowid);
$sql = 'SELECT fk_marche, commentaire FROM devis WHERE rowid = ' . $rowidSafe . ';';
$retSql = getinfos($sql, "gen");
$commentaireOld = $retSql[0]["commentaire"];
if ($commentaireOld != $commentaire) {
// le commentaire a été modifié
if ($commentaireOld == "") {
$newCommentaire = 1;
} else {
$newCommentaire = 2;
}
}
$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 = ' . $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=' . $rowidSafe . ';';
eLog($sql);
qSQL($sql, "gen");
// On enregistre cette info dans le chat
$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=' . $rowidSafe . ';';
qSQL($sql, "gen");
$retid = $rowid;
}
eLog('Entete Devis Save : ' . $sql);
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 . '", ';
$fkClientSafe = intval($fk_client);
$sql .= 'email="' . $email . '", telephone="' . $telephone . '", mobile="' . $mobile . '" WHERE rowid=' . $fkClientSafe . ';';
eLog('Entete Devis Save infos client : ' . $sql);
qSQL($sql, "gen");
}
// 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) {
$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 {
$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");
}
}
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $retid;
// on renvoie en json le rowid du devis créé ou mis à jour
$upls = array("retid" => $retid);
echo json_encode($upls);
}
break;
case "save_devis_speciaux":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->idDevis_speciaux)) {
$fkDevis = $data->idDevis_speciaux;
(isset($data->chk_livr_multi)) ? $chk_livr_multi = 1 : $chk_livr_multi = 0;
$date_livr_1 = $data->date_livr_1;
$nb_livr = $data->nb_livr;
if ($nb_livr == "") $nb_livr = 0;
$email = $data->specialEmail;
$set = 'chk_livr_multi=' . $chk_livr_multi . ', date_livr_1="' . $date_livr_1 . '", nb_livr=' . $nb_livr . ', email="' . $email . '", ';
for ($i = 1; $i <= 5; $i++) {
if ($data->{"specialFkProduit_" . $i} > 0) {
$fk_produit = $data->{"specialFkProduit_" . $i};
$code = $data->{"specialCode_" . $i};
$libelle = $data->{"specialLibe_" . $i};
$qte = $data->{"specialQte_" . $i};
$concurrent = $data->{"specialConcurrent_" . $i};
$surcout = $data->{"specialCout_" . $i} == "" ? 0 : $data->{"specialCout_" . $i};
(isset($data->{"chk_specialEchantillon_" . $i})) ? $chk_echantillon = 1 : $chk_echantillon = 0;
$datech = $data->{"specialDate_" . $i};
$description = $data->{"specialDescription_" . $i};
} else {
// on vide les champs sinon
$fk_produit = 0;
$code = "";
$libelle = "";
$qte = 0;
$concurrent = "";
$surcout = 0;
$chk_echantillon = 0;
$datech = "";
$description = "";
}
$set .= 'fk_produit_' . $i . '=' . $fk_produit . ', code_produit_' . $i . '="' . $code . '", lib_produit_' . $i . '="' . $libelle . '", qte_' . $i . '=' . $qte . ', ';
$set .= 'lib_concurrent_' . $i . '="' . $concurrent . '", surcout_' . $i . '=' . $surcout . ', chk_echantillon_' . $i . '=' . $chk_echantillon . ', ';
$set .= 'date_echantillon_' . $i . '="' . $datech . '", description_' . $i . '="' . $description . '", ';
}
if (substr($set, -2) == ", ") {
$set = substr($set, 0, -2);
}
$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 = ' . $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 = ' . $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 = ' . $fkDevisSafe . ';';
$ret = getinfos($sql, "gen");
$spec = $ret[0];
if ($spec["email"] != "" && $spec["chk_email"] == 0) {
// 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 = ' . $fkDevisSafe . ';';
$ret = getinfos($sql, "gen");
$dev = $ret[0];
if ($dev["fk_client"] > 0) {
$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"];
$libelle = $cli["libelle"];
$cp = $cli["cp"];
$ville = $cli["ville"];
} else {
$codeClient = "Nouveau client";
$libelle = $dev["lib_new_client"];
$cp = $dev["cp_new_client"];
$ville = $dev["ville_new_client"];
}
$dest = $spec["email"];
$subject = "Demande de produits spéciaux";
$message = "[Ce message est envoyé automatiquement par le système de gestion de devis]<br/><br/>";
$message .= "Bonjour,<br/><br/>sur le devis #" . $fkDevis . ", <br/>";
$message .= "pour le client " . $libelle . ", " . $cp . " " . $ville . ", code : " . $codeClient . "<br/><br/>";
$message .= "Livraisons multiples : ";
$spec["chk_livr_multi"] == 1 ? $message .= "Oui, en " . $spec["nb_livr"] . " fois" : $message .= "Non";
$message .= "<br/>Date de la 1ère livraison : " . affiche_date($spec["date_livr_1"]) . "<br/><br/>";
$message .= "-----------------------------------------------<br/><br/>";
$message .= "Les produits spéciaux suivants sont demandés :<br/><br/>";
for ($i = 1; $i <= 5; $i++) {
if ($spec["fk_produit_" . $i] > 0) {
$message .= "Produit : " . $spec["code_produit_" . $i] . " - " . $spec["lib_produit_" . $i] . "<br/>";
$message .= "Quantité : " . $spec["qte_" . $i] . "<br/>";
$message .= "Concurrent : " . $spec["lib_concurrent_" . $i] . "<br/>";
$message .= "Surcoût accepté : " . $spec["surcout_" . $i] . "<br/>";
if ($spec["chk_echantillon_" . $i] == 1) {
$message .= "Echantillon demandé : Oui<br/>";
$message .= "Date d'envoi de l'échantillon : " . $spec["date_echantillon_" . $i] . "<br/>";
} else {
$message .= "Echantillon demandé : Non<br/><br/>";
}
$message .= "Description : " . $spec["description_" . $i] . "<br/>";
$message .= "------------------<br/><br/>";
}
}
$message .= "-----------------------------------------------<br/><br/>";
$message .= "Cordialement.<br/>";
$message .= $Session->_user["prenom"] . " " . $Session->_user["libelle"];
$copieFrom = $Session->_user["email"];
$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 = ' . $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 = ' . $fkDevisSafe . ';';
eLog('Devis Speciaux Save : ' . $sql);
qSQL($sql, "gen");
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $fkDevis;
// on renvoie le rowid du devis et le nombre de produits renseignés
$upls = array("success" => true, "retid" => $fkDevis);
echo json_encode($upls);
}
break;
case "load_devis_produits_search":
if (isset($_POST["term"])) {
if (strlen($_POST["term"]) > 0) {
$term = nettoie_input($_POST["term"]);
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;';
}
if (!isset($upls)) {
$upls = array();
$upls = getinfos($sql, "gen");
echo json_encode($upls);
}
break;
case "save_devis_produits":
// Enregistre l'onglet Produits d'un devis (les produits sélectionnés)
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$idDevis = nettoie_input($data->cid);
eLog("save_devis_produits : idDevis = " . $idDevis);
// on récupère les anciens produits du devis
if ($idDevis > 0) {
// on récupère les anciens produits du devis
$idDevisSafe = intval($idDevis);
$sql = 'SELECT fk_produit FROM devis_produits WHERE fk_devis = ' . $idDevisSafe . ';';
$tempAncProduits = getinfos($sql, 'gen');
$lstAncProduits = array();
foreach ($tempAncProduits as $prod) {
$lstAncProduits[] = $prod['fk_produit'];
}
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 = ' . $idDevisSafe . ';';
$retSql = getinfos($sql, "gen");
$idMarche = $retSql[0]["fk_marche"];
eLog("save_devis_produits : 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"];
$termeVente = $retSql[0]["terme_vente"];
} else {
$termeAchat = "";
$termeVente = "";
}
// 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=' . $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=' . $idMarcheSafe . ' AND active=1;';
$tempCodesHybrides = getinfos($sql, 'gen');
$lstCodesHybrides = array();
foreach ($tempCodesHybrides as $prod) {
$lstCodesHybrides[] = $prod['code'];
}
}
eLog("on a " . count($lstCodesHybrides) . " codes hybrides");
if (!empty($data->produits)) {
//! il y a au moins 1 produit sélectionné à enregistrer
$lstProduits = $data->produits;
//! on supprime le premier caractère séparateur
$lstProduits = substr($lstProduits, 1);
//! et on transforme la chaîne en tableau
$newProduits = explode(";", $lstProduits);
eLog("save_devis_produits : on a " . count($newProduits) . " produits à enregistrer");
foreach ($newProduits as $newProd) {
//! pour chaque produit sélectionné
eLog("save_devis_produits : on va tester si le produit " . $newProd . " existe dans la liste des ancien produits (anciennes lignes)");
//! 1. on regarde s'il est déjà enregistré
if (!in_array($newProd, $lstAncProduits)) {
//! ce produit n'existe pas, on le rajoute
eLog("save_devis_produits : le produit " . $newProd . " n'existe pas dans la liste des ancien produits (anciennes lignes)");
//! on récupère d'abord les prix d'achat et de vente du produit
$sql = 'SELECT code, libelle, prix_achat_net, prix_vente, prc_discount_1, quantite_1, prc_discount_2, quantite_2, ';
$sql .= 'prc_discount_3, quantite_3, prc_discount_4, quantite_4, prc_discount_5, quantite_5, prc_discount_6, quantite_6 ';
$sql .= 'FROM produits WHERE rowid=' . $newProd . ';';
$prodInfos = getinfos($sql);
eLog(count($prodInfos));
$prix_achat_net = $prodInfos[0]["prix_achat_net"];
$prix_vente = $prodInfos[0]["prix_vente"];
$code = $prodInfos[0]["code"];
$libelle = $prodInfos[0]["libelle"];
eLog("On teste s'il est hybride dans les " . count($lstCodesHybrides) . " codes hybrides ? ");
// on vérifie si le code produit existe dans la liste des codes hybrides
if (in_array($code, $lstCodesHybrides)) {
$chk_prix_net = 1;
} else {
$chk_prix_net = 0;
}
eLog("Produit " . $code . " existe dans la liste des codes hybrides ? " . $chk_prix_net);
if ($prix_achat_net == 0 && $termeAchat == "Purchasing") {
//! le prix d'achat est à 0, et le marché n'enregistre que les prix de vente donc on va cherche le prix d'achat net dans le hors marché
$sql = 'SELECT p.prix_achat_net, prc_discount_1, quantite_1, prc_discount_2, quantite_2, prc_discount_3, quantite_3, ';
$sql .= 'prc_discount_4, quantite_4, prc_discount_5, quantite_5, prc_discount_6, quantite_6 ';
$sql .= 'FROM produits p WHERE p.code="' . $code . '" AND fk_marche=999;';
$prodInfos = getinfos($sql, "gen");
$prix_achat_net = $prodInfos[0]["prix_achat_net"];
}
$discount1 = $prodInfos[0]["prc_discount_1"];
$quantite1 = $prodInfos[0]["quantite_1"];
$discount2 = $prodInfos[0]["prc_discount_2"];
$quantite2 = $prodInfos[0]["quantite_2"];
$discount3 = $prodInfos[0]["prc_discount_3"];
$quantite3 = $prodInfos[0]["quantite_3"];
$discount4 = $prodInfos[0]["prc_discount_4"];
$quantite4 = $prodInfos[0]["quantite_4"];
$discount5 = $prodInfos[0]["prc_discount_5"];
$quantite5 = $prodInfos[0]["quantite_5"];
$discount6 = $prodInfos[0]["prc_discount_6"];
$quantite6 = $prodInfos[0]["quantite_6"];
//! puis on l'enregistre
$sql = 'INSERT INTO devis_produits SET fk_devis=' . $idDevis . ', fk_produit=' . $newProd . ', code="' . $code . '", libelle="' . $libelle . '", ';
$sql .= 'prix_achat_net=' . $prix_achat_net . ', prix_vente=' . $prix_vente . ', prc_discount_1=' . $discount1 . ', quantite_1=' . $quantite1 . ', ';
$sql .= 'prc_discount_2=' . $discount2 . ', quantite_2=' . $quantite2 . ', prc_discount_3=' . $discount3 . ', quantite_3=' . $quantite3 . ', ';
$sql .= 'prc_discount_4=' . $discount4 . ', quantite_4=' . $quantite4 . ', prc_discount_5=' . $discount5 . ', quantite_5=' . $quantite5 . ', ';
$sql .= 'prc_discount_6=' . $discount6 . ', quantite_6=' . $quantite6 . ', chk_prix_net=' . $chk_prix_net . ';';
eLog($sql);
qSQL($sql, "gen");
}
}
//! Enfin, on compare les 2 listes et on supprime les produits enregistrés mais non sélectionnés
if (count($lstAncProduits) > 0) {
foreach ($lstAncProduits as $ancProd) {
if (!in_array($ancProd, $newProduits)) {
if ($ancProd != "") {
//! ce produit était enregistré, mais n'est plus dans la nouvelle sélection, on le supprime
$sql = 'DELETE FROM devis_produits WHERE fk_devis=' . $idDevis . ' AND fk_produit=' . $ancProd . ';';
eLog($sql);
qSQL($sql, "gen");
}
}
}
}
} else {
//! Aucun produit sélectionné : on supprime les éventuels anciens produits enregistrés de ce devis
$sql = 'DELETE FROM devis_produits WHERE fk_devis = ' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
}
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $idDevis;
//! on retourne la liste des produits du devis à jour
$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 = ' . $idDevis . ';';
$result = getinfos($sql, "gen", "json");
elog("result : " . $result);
// Vérification si le résultat est vide
if (empty($result) || $result === "null" || $result === "[]") {
echo json_encode([]);
} else {
echo $result;
}
}
}
break;
case "save_devis":
//! on enregistre la page finale du devis
$data = json_decode(file_get_contents("php://input"));
if (isset($data->inpIdDevis)) {
$idDevis = nettoie_input($data->inpIdDevis);
eLog("save_devis final : idDevis = " . $idDevis);
// TODO: enregistrer le prix d'achat et de vente de chaque produit au moment du devis
//! loop sur les datas commençant par inpQte_
foreach ($data as $key => $value) {
if (substr($key, 0, 7) == "inpQte_") {
//! on a une ligne de produit
$idProd = substr($key, 7);
$qte = nettoie_input($value);
$qte = "" ? 0 : $qte;
$rem = nettoie_input($data->{"inpRemise_" . $idProd});
$rem = "" ? 0 : $rem;
$ht = nettoie_input($data->{"inpHT_" . $idProd});
$ht = "" ? 0 : $ht;
// si $ht contient un espace (délimiteur millier), on le supprime
$ht = str_replace(" ", "", $ht);
$mg = nettoie_input($data->{"inpMG_" . $idProd});
$mg = "" ? 0 : $mg;
$ha = nettoie_input($data->{"achat_" . $idProd});
$ha = "" ? 0 : $ha;
$ha = str_replace(" ", "", $ha);
$pv = nettoie_input($data->{"vente_" . $idProd});
$pv = "" ? 0 : $pv;
$pv = str_replace(" ", "", $pv);
$pu = nettoie_input($data->{"inpPUVenteRem_" . $idProd});
$pu = "" ? 0 : $pu;
$pu = str_replace(" ", "", $pu);
$varOpt = 0;
if (isset($data->{"chkVariante_" . $idProd})) {
$varOpt = 1;
}
$comment = nettoie_input($data->{"inpCom_" . $idProd});
$ordre = nettoie_input($data->{"inpOrdre_" . $idProd});
if ($ordre == "") {
$ordre = 0;
}
$sql = 'UPDATE devis_produits SET qte=' . $qte . ', remise=' . $rem . ', totalht=' . $ht . ', marge=' . $mg . ', prix_achat_net=' . $ha . ', ';
$sql .= 'prix_vente=' . $pv . ', pu_vente_remise=' . $pu . ', chk_variante=' . $varOpt . ', commentaire="' . $comment . '", ordre=' . $ordre . ' ';
$sql .= 'WHERE fk_devis=' . $idDevis . ' AND fk_produit=' . $idProd . ';';
eLog($sql);
qSQL($sql, "gen");
}
}
//! on enregistre les totaux dans la table devis
$totalHT = nettoie_input($data->inpTotalHT);
$totalRemHT = nettoie_input($data->inpTotalRemHT);
$totalMarge = nettoie_input($data->inpTotalMarge);
$totalHT == "" ? 0 : $totalHT;
// si $totalHT contient un espace (délimiteur millier), on le supprime
$totalHT = str_replace(" ", "", $totalHT);
$totalRemHT == "" ? 0 : $totalRemHT;
$totalRemHT = str_replace(" ", "", $totalRemHT);
$totalMarge == "" ? 0 : $totalMarge;
$totalMarge = str_replace(" ", "", $totalMarge);
$commentDevis = nettoie_input($data->commentDevis);
$commentGesteComm = nettoie_input($data->commentGesteComm);
$sql = 'UPDATE devis SET montant_total_ht=' . $totalHT . ', montant_total_ht_remise=' . $totalRemHT . ', marge_totale=' . $totalMarge . ', comment_devis="' . $commentDevis . '", comment_geste_comm="' . $commentGesteComm . '", ';
$sql .= 'date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user . ' ';
$sql .= 'WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
// On vérifie le statut du devis
$sql = 'SELECT d.fk_statut_devis, d.chk_validat, d.fk_user_validat, d.fk_user FROM devis d WHERE d.rowid=' . $idDevis . ';';
$res = getinfos($sql, "gen");
$statutDevis = $res[0]["fk_statut_devis"];
$fkUserDevis = $res[0]["fk_user"];
$chkValidat = $res[0]["chk_validat"];
$fkUserValidat = $res[0]["fk_user_validat"];
if ($statutDevis > 1 && $statutDevis < 7) {
//! le devis n'est plus en statut "En cours de création" : il faut prévenir les interlocuteurs qu'il a fait une mise à jour
switch ($statutDevis) {
case 2:
//! le devis est en statut "En attente de validation du DIR-CO" : on lui envoie un mail et on check la nouveauté dans le devis
$sqlMail = "";
if ($fkUserDevis != $fk_user) {
//! l'utilisateur qui a créé le devis n'est pas celui qui le modifie : on prévient l'utilisateur initial
$sqlMail = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $res[0]["fk_user"] . ';';
} else {
//! l'utilisateur qui a créé le devis est celui qui le modifie : on prévient le DIR-CO
$fkUserDirCo = 0;
if ($fk_role == 3) {
// C'est un commercial RR, on va chercher le parent de son DV
if ($Session->_user["fk_parent"] > 0) {
$sql = 'SELECT u.fk_parent FROM users u WHERE u.rowid = ' . $Session->_user["fk_parent"] . ' AND u.fk_role=2;';
$res = getinfos($sql, "gen");
$fkUserDirCo = $res[0]["fk_parent"];
}
} else {
// C'est le DV, on récupère son responsable le DIR-CO
$fkUserDirCo = $Session->_user["fk_parent"];
}
if ($fkUserDirCo > 0) {
$sqlMail = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $fkUserDirCo . ';';
}
}
if ($sqlMail != "") {
$res = getinfos($sqlMail, "gen");
$dest = $res[0];
$nomDest = $dest["prenom"] . " " . $dest["libelle"];
$emailDest = $dest["email"];
}
break;
case 3:
//! le devis est en statut "En attente de validation du DV" : on lui envoie un mail et on check la nouveauté dans le devis
$sqlMail = "";
if ($fkUserDevis != $fk_user) {
//! l'utilisateur qui a créé le devis n'est pas celui qui le modifie : on prévient l'utilisateur initial
$sqlMail = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $res[0]["fk_user"] . ';';
} else {
//! l'utilisateur qui a créé le devis est celui qui le modifie : on prévient le DV
if ($Session->_user["fk_parent"] > 0) {
$sqlMail = 'SELECT u.prenom, u.libelle, u.email FROM users u WHERE u.rowid = ' . $Session->_user["fk_parent"] . ' AND u.fk_role=2;';
}
}
if ($sqlMail != "") {
$res = getinfos($sqlMail, "gen");
$dest = $res[0];
$nomDest = $dest["prenom"] . " " . $dest["libelle"];
$emailDest = $dest["email"];
}
break;
default:
// Pour tous les autres cas il faut prévenir l'ADV
break;
}
if (isset($emailDest)) {
$sujet = "Mise à jour du devis n°" . $idDevis . " en cours de validation";
$message = "Bonjour " . $nomDest . ",<br><br>";
$message .= "Le devis n°" . $idDevis . " a été mis à jour par " . $Session->_user["prenom"] . " " . $Session->_user["libelle"] . ".<br>";
$message .= "<a href='https://cleo.unikoffice.com/devis'>Vous pouvez le consulter en cliquant sur ce lien</a><br><br>";
$message .= "Cordialement,<br>";
$message .= "Email généré automatiquement par l'application CLEO de gestion des devis";
eLog("Envoi d'un email à : " . $emailDest . " - Sujet : " . $sujet . " - Message : " . $message);
envoieMail($emailDest, $sujet, $message);
}
if ($fkUserDevis == $fk_user) {
if ($chkValidat == 0 && $fkUserValidat > 0) {
//! le devis a été refusé par le DIR-CO ou le DV, et ce devis vient d'être à nouveau modifié par le commercial, on supprime les traces du refus
$sql = 'UPDATE devis SET fk_user_validat=0, date_validat="", comment_validat="" WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
}
}
// On enregistre cette info dans le chat du devis
$sql = 'INSERT INTO devis_histo SET fk_devis=' . $idDevis . ', fk_user=' . $fk_user . ', date_histo="' . date("Y-m-d H:i:s") . '", commentaire="Mise à jour du devis";';
eLog($sql);
qSQL($sql, "gen");
// On check la nouveauté du devis
$sql = 'UPDATE devis SET chk_maj=1 WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
}
if (strlen($commentDevis) > 0) {
//! on enregistre le commentaire dans la table devis_histo (table historique des commentaires des devis pour le chat)
$sql = 'SELECT dh.commentaire FROM devis_histo dh WHERE dh.fk_devis=' . $idDevis . ' AND chk_comment_devis_pro=1;';
$res = getinfos($sql, "gen");
if (count($res) == 1) {
//! on met à jour le commentaire
$sql = 'UPDATE devis_histo SET commentaire="' . $commentDevis . '", date_histo="' . date("Y-m-d H:i:s") . '", fk_user=' . $fk_user . ' ';
$sql .= 'WHERE fk_devis=' . $idDevis . ' AND chk_comment_devis_pro=1;';
eLog($sql);
qSQL($sql, "gen");
} else {
//! on insère le commentaire
$sql = 'INSERT INTO devis_histo (fk_devis, fk_user, date_histo, commentaire, chk_comment_devis_pro) VALUES (' . $idDevis . ', ' . $fk_user . ', "' . date("Y-m-d H:i:s") . '", "' . $commentDevis . '", 1);';
eLog($sql);
qSQL($sql, "gen");
}
} else {
// Si le commentaire est vide on supprime un éventuel commentaire existant
$sql = 'DELETE FROM devis_histo WHERE fk_devis = ' . $idDevis . ' AND chk_comment_devis_pro = 1;';
eLog($sql);
qSQL($sql, "gen");
}
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $idDevis;
$upls = array("ret" => "ok", "rid" => $idDevis, "totalremht" => $totalRemHT, "totalmarge" => $totalMarge);
echo json_encode($upls);
} else {
$upls = array("ret" => "ko", "rid" => 0, "totalremht" => 0);
echo json_encode($upls);
}
break;
case "validat_devis":
// Validation ou refus du devis par le DV ou le DIR-CO
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$idDevis = nettoie_input($data->cid);
$chk_validat = nettoie_input($data->chk_validat);
$commentaire = nettoie_input($data->commentaire);
$sql = 'UPDATE devis SET comment_validat="' . $commentaire . '", chk_validat=' . $chk_validat . ', date_validat="' . date("Y-m-d H:i:s") . '", fk_user_validat=' . $fk_user . ' WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
$comment_histo = $chk_validat == 1 ? "Devis validé : " : "Devis refusé : ";
$comment_histo .= $commentaire;
$sql = 'INSERT INTO devis_histo SET fk_devis=' . $idDevis . ', fk_user=' . $fk_user . ', date_histo="' . date("Y-m-d H:i:s") . '", commentaire="' . $comment_histo . '";';
eLog($sql);
qSQL($sql, "gen");
if ($chk_validat == 1) {
// On change le statut du devis pour le mettre directement en Traitement SAP : 4
$sql = 'UPDATE devis SET fk_statut_devis=4 WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
}
// On envoie un email au responsable du devis pour le prévenir que son devis a été validé ou refusé
$sql = 'SELECT d.fk_user, u.email, u.libelle, u.prenom, u.fk_role, u.fk_parent FROM users u LEFT JOIN devis d ON d.fk_user=u.rowid WHERE d.rowid=' . $idDevis . ';';
$res = getinfos($sql, "gen");
if (count($res) == 1) {
$respDevis = $res[0];
$email = $respDevis["email"];
$nom = $respDevis["prenom"] . " " . $res[0]["libelle"];
$sujet = $chk_validat == 1 ? "Devis validé" : "Devis refusé";
$etat = $chk_validat == 1 ? "validé" : "refusé";
$message = "Bonjour " . $nom . ",<br><br>";
$message .= "Votre devis n°" . $idDevis . " a été " . $etat . " par " . $Session->_user["prenom"] . " " . $Session->_user["libelle"] . ".<br>";
$message .= "<a href='https://cleo.unikoffice.com/devis'>Vous pouvez le consulter en cliquant sur ce lien</a><br><br>";
$message .= "Cordialement,<br>";
$message .= "Email généré automatiquement par l'application CLEO de gestion des devis";
eLog("Envoi d'un email au responsable du devis : " . $email . " - Sujet : " . $sujet . " - Message : " . $message);
envoieMail($email, $sujet, $message);
// On vérifie que le responsable de ce devis est bien un RR Commercial, si c'est le cas il faut aussi envoyer un email à son DV
if ($respDevis["fk_role"] == 3) {
$sql = 'SELECT u.email, u.libelle, u.prenom FROM users u WHERE u.rowid=' . $respDevis["fk_parent"] . ';';
$res = getinfos($sql, "gen");
$dv = $res[0];
$email = $dv["email"];
$nomDV = $dv["prenom"] . " " . $dv["libelle"];
$message = "Bonjour " . $nomDV . ",<br><br>";
$message .= "Le devis n°" . $idDevis . " de " . $nom . " a été " . $etat . " par " . $Session->_user["prenom"] . " " . $Session->_user["libelle"] . ".<br>";
$message .= "<a href='https://cleo.unikoffice.com/devis'>Vous pouvez le consulter en cliquant sur ce lien</a><br><br>";
$message .= "Cordialement,<br>";
$message .= "Email généré automatiquement par l'application CLEO de gestion des devis";
eLog("Envoi d'un email au DV : " . $email . " - Sujet : " . $sujet . " - Message : " . $message);
envoieMail($email, $sujet, $message);
}
}
}
break;
case "statut_devis":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$idDevis = nettoie_input($data->cid);
$statut = nettoie_input($data->statut);
$commentaire = nettoie_input($data->commentaire);
eLog("statut_devis : idDevis = " . $idDevis . ", statut = " . $statut . ", commentaire = " . $commentaire);
$sql = 'UPDATE devis SET fk_statut_devis=' . $statut . ', date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user . ' WHERE rowid=' . $idDevis . ';';
eLog($sql);
qSQL($sql, "gen");
$sql = 'INSERT INTO devis_histo SET fk_devis=' . $idDevis . ', fk_statut_devis=' . $statut . ', fk_user=' . $fk_user . ', date_histo="' . date("Y-m-d H:i:s") . '", commentaire="' . $commentaire . '";';
eLog($sql);
qSQL($sql, "gen");
elog("statut_devis : Ensuite on envoie un email suivant son statut : " . $statut);
switch ($statut) {
case 2:
// Le devis part en Validation DIR-CO, on envoie un email au DIR-CO
// 1. On récupère les infos du DIR-CO
// Si c'est un DV qui envoie le devis, on utilise son fk_parent
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 = ' . 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 = ' . 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
else {
$sql = 'SELECT u.email, u.prenom, u.libelle, u.rowid
FROM users u
WHERE u.fk_role = 1 AND u.fk_region=18 AND u.active = 1 LIMIT 1';
}
$dest = getinfos($sql, "gen");
if (count($dest) == 1) {
$to = $dest[0]["email"];
$nom = $dest[0]["prenom"] . " " . $dest[0]["libelle"];
// 2. On récupère les infos du devis
$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"];
$idClient = $devis[0]["fk_client"];
$nomClient = "";
$nomRR = $devis[0]["prenom"] . " " . $devis[0]["libelle"];
if ($idClient == 0) {
$nomClient = $devis[0]["lib_new_client"] . ", (" . $devis[0]["cp_new_client"] . " - " . $devis[0]["ville_new_client"] . ")";
} else {
$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"] . ")";
}
}
$sujet = "Nouveau devis à valider";
$message = "Bonjour " . $nom . ",<br/><a href='https://cleo.unikoffice.com'>Un nouveau devis est à valider.</a><br/><br/>";
$message .= "Devis n°" . $idDevis . " de " . $nomRR . "<br/>";
$message .= "Client : " . $nomClient . "<br/>";
$message .= "Montant HT avec remise : " . $montant . "€.<br/><br/>";
$message .= "Cordialement.<br/>";
$message .= "Email généré automatiquement par l'application CLEO de gestion des devis";
envoieMail($to, $sujet, $message);
eLog("Mail envoyé à " . $to . " pour le devis " . $idDevis . " de " . $nomRR . " en statut " . $statut);
}
}
break;
case 3:
// Le devis part en Validation DV, on envoie un email au DV
// 1. On récupère les infos du DV responsable de ce RR
elog("statut_devis : on est dans le cas 3 envoi à son DV");
$fkRole = $Session->_user["fk_role"];
$fkParent = $Session->_user["fk_parent"];
eLog("statut_devis : fkRole=" . $fkRole . ", fkParent=" . $fkParent);
if ($fkRole == 3) {
// c'est un RR donc on peut envoyer à son DV
if ($fkParent > 0) {
$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 {
// c'est un RR sans DV, on envoie au 1er DV trouvé
$sql = 'SELECT u.email, u.prenom, u.libelle FROM users u WHERE u.fk_role=2 AND u.active=1 LIMIT 1;';
$dest = getinfos($sql, "gen");
}
if (count($dest) == 1) {
$to = $dest[0]["email"];
$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
$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"];
$idClient = $devis[0]["fk_client"];
$nomRR = $devis[0]["prenom"] . " " . $devis[0]["libelle"];
if ($idClient == 0) {
$nomClient = $devis[0]["lib_new_client"] . ", (" . $devis[0]["cp_new_client"] . " - " . $devis[0]["ville_new_client"] . ")";
} else {
$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"] . ")";
}
}
$sujet = "Nouveau devis à valider";
$message = "Bonjour " . $nom . ",<br/><a href='https://cleo.unikoffice.com'>Un nouveau devis est à valider.</a><br/><br/>";
$message .= "Devis n°" . $idDevis . " de " . $nomRR . "<br/>";
$message .= "Client : " . $nomClient . "<br/>";
$message .= "Montant HT avec remise : " . $montant . "€.<br/><br/>";
$message .= "Cordialement.<br/>";
$message .= "Email généré automatiquement par l'application CLEO de gestion des devis";
envoieMail($to, $sujet, $message);
eLog("Mail envoyé à " . $to . " pour le devis " . $idDevis . " de " . $nomRR . " en statut " . $statut);
}
}
}
break;
case 4:
$statut = "Refusé";
break;
case 5:
$statut = "Annulé";
break;
default:
$statut = "Inconnu";
break;
}
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $idDevis;
echo json_encode(array("ret" => "ok"));
}
break;
case "valide_devis":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$idDevis = nettoie_input($data->cid);
$comment = nettoie_input($data->comment);
eLog("valide_devis : idDevis = " . $idDevis . ", commentaire = " . $comment);
$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");
$sql = 'INSERT INTO devis_histo SET fk_devis=' . $idDevis . ', fk_statut_devis=4, fk_user=' . $fk_user . ', date_histo="' . date("Y-m-d H:i:s") . '", commentaire="' . $comment . '";';
eLog($sql);
qSQL($sql, "gen");
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $idDevis;
echo json_encode(array("success" => "true", "message" => "Devis validé avec succès"));
}
break;
case "refuse_devis":
$data = json_decode(file_get_contents("php://input"));
if (isset($data->cid)) {
$idDevis = nettoie_input($data->cid);
$comment = nettoie_input($data->comment);
eLog("refuse_devis : idDevis = " . $idDevis . ", commentaire = " . $comment);
$sql = 'INSERT INTO devis_histo SET fk_devis=' . $idDevis . ', fk_user=' . $fk_user . ', date_histo="' . date("Y-m-d H:i:s") . '", commentaire="' . $comment . '";';
eLog($sql);
qSQL($sql, "gen");
// on met à jour la session avec le rowid de ce dernier devis créé ou mis à jour
$_SESSION["lastDevis"] = $idDevis;
echo json_encode(array("success" => "true", "message" => "Devis refusé avec succès"));
}
break;
}
exit();