feat(v2.0.4): Corrections diverses et tri des tableaux devis

- Correction affichage email contact dans SAP (models/msap.php)
- Ajout fonctionnalité tri des tableaux devis (jsap.js, jdevis.js)
- Améliorations diverses vues devis et SAP
- Mise à jour contrôleurs et modèles export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-05 10:32:19 +01:00
parent f6c5e96534
commit e96ad7a244
12 changed files with 1348 additions and 320 deletions

View File

@@ -1368,5 +1368,280 @@ switch ($Route->_action) {
}
}
break;
case "search_devis":
eLog("=== search_devis case appelé ===");
$rawData = file_get_contents("php://input");
eLog("Raw data: " . $rawData);
$data = json_decode($rawData);
eLog("Data decoded: " . print_r($data, true));
eLog("isset term: " . (isset($data->term) ? 'YES' : 'NO'));
if (isset($data->term)) {
$term = nettoie_input($data->term);
$context = nettoie_input($data->context);
if (strlen($term) < 3) {
echo json_encode(array("success" => false, "message" => "Le terme de recherche doit contenir au moins 3 caractères"));
break;
}
$termSafe = '%' . $term . '%';
$whereParams = [];
switch ($fk_role) {
case 1:
$whereRole = 'd.fk_user = :fkUser OR d.fk_statut_devis >= 2';
$whereParams[':fkUser'] = $fk_user;
break;
case 2:
try {
$db = Database::getInstance();
$sql = 'SELECT rowid FROM users WHERE fk_parent = :fkParent';
$aRR = $db->fetchAll($sql, [':fkParent' => $fk_user]);
$rrIds = array_column($aRR, 'rowid');
if (!empty($rrIds)) {
$placeholders = [];
foreach ($rrIds as $index => $id) {
$placeholder = ':rr' . $index;
$placeholders[] = $placeholder;
$whereParams[$placeholder] = $id;
}
$whereRole = 'd.fk_user = :fkUser OR (d.fk_statut_devis >= 3 AND d.fk_user IN (' . implode(',', $placeholders) . '))';
$whereParams[':fkUser'] = $fk_user;
} else {
$whereRole = 'd.fk_user = :fkUser';
$whereParams[':fkUser'] = $fk_user;
}
} catch (Exception $e) {
error_log("Erreur récupération RR : " . $e->getMessage());
$whereRole = 'd.fk_user = :fkUser';
$whereParams[':fkUser'] = $fk_user;
}
break;
default:
$whereRole = 'd.fk_user = :fkUser';
$whereParams[':fkUser'] = $fk_user;
break;
}
if ($context === "archives") {
$whereStatut = ' AND d.fk_statut_devis = 20';
} else {
$whereStatut = ' AND d.fk_statut_devis != 20';
}
$whereParams[':term1'] = $termSafe;
$whereParams[':term2'] = $termSafe;
$whereParams[':term3'] = $termSafe;
$whereParams[':term4'] = $termSafe;
$whereParams[':term5'] = $termSafe;
$whereParams[':term6'] = $termSafe;
$whereParams[':term7'] = $termSafe;
$whereParams[':term8'] = $termSafe;
$whereParams[':term9'] = $termSafe;
$whereParams[':term10'] = $termSafe;
$whereParams[':term11'] = $termSafe;
$whereParams[':term12'] = $termSafe;
$whereParams[':term13'] = $termSafe;
$whereParams[':term14'] = $termSafe;
$whereParams[':term15'] = $termSafe;
$whereParams[':term16'] = $termSafe;
$whereParams[':term17'] = $termSafe;
try {
$db = Database::getInstance();
$sql = 'SELECT DISTINCT d.rowid, d.dossier, d.date_demande, d.date_remise, d.num_opportunite, d.fk_client, d.montant_total_ht_remise, d.marge_totale, d.commentaire, d.chk_speciaux, c.libelle, c.ville, c.cp, d.fk_statut_devis, ';
$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, d.comment_devis, d.comment_geste_comm, ';
$sql .= 'd.contact_new_nom, d.contact_new_prenom, d.new_telephone, d.new_mobile, d.new_email, d.contact_new_fonction, LEFT(u.prenom,1) AS prenom, u.libelle as nom, ';
$sql .= 'xs.libelle as lib_statut, d.chk_new_statut, m.libelle as lib_marche, d.chk_validat, d.fk_user_validat, d.date_validat ';
$sql .= 'FROM devis d ';
$sql .= 'LEFT JOIN clients c ON c.rowid=d.fk_client ';
$sql .= 'LEFT JOIN x_statuts_devis xs ON xs.rowid=d.fk_statut_devis ';
$sql .= 'LEFT JOIN marches m ON m.rowid=d.fk_marche ';
$sql .= 'LEFT JOIN users u ON u.rowid=d.fk_user ';
$sql .= 'LEFT JOIN clients_contacts ct ON ct.fk_client=d.fk_client ';
$sql .= 'WHERE (' . $whereRole . ')' . $whereStatut . ' AND (';
$sql .= 'd.rowid LIKE :term1 OR ';
$sql .= 'c.libelle LIKE :term2 OR ';
$sql .= 'c.adresse1 LIKE :term3 OR ';
$sql .= 'c.adresse2 LIKE :term4 OR ';
$sql .= 'c.adresse3 LIKE :term5 OR ';
$sql .= 'c.cp LIKE :term6 OR ';
$sql .= 'c.ville LIKE :term7 OR ';
$sql .= 'm.libelle LIKE :term8 OR ';
$sql .= 'd.num_opportunite LIKE :term9 OR ';
$sql .= 'd.lib_new_client LIKE :term10 OR ';
$sql .= 'd.cp_new_client LIKE :term11 OR ';
$sql .= 'd.ville_new_client LIKE :term12 OR ';
$sql .= 'ct.nom LIKE :term13 OR ';
$sql .= 'ct.prenom LIKE :term14 OR ';
$sql .= 'ct.fonction LIKE :term15 OR ';
$sql .= 'ct.email LIKE :term16 OR ';
$sql .= 'd.commentaire LIKE :term17) ';
$sql .= 'ORDER BY d.dossier, d.date_remise DESC';
eLog("=== SEARCH DEVIS DEBUG ===");
eLog("Terme recherché: " . $term);
eLog("Context: " . $context);
eLog("SQL: " . $sql);
eLog("Params: " . print_r($whereParams, true));
$pdo = $db->getPDO();
$stmt = $pdo->prepare($sql);
$stmt->execute($whereParams);
$devis = $stmt->fetchAll(PDO::FETCH_ASSOC);
eLog("Nombre de devis trouvés: " . count($devis));
$nb_devis = array();
foreach ($devis as $dev) {
if (!isset($nb_devis[$dev["fk_statut_devis"]])) {
$nb_devis[$dev["fk_statut_devis"]] = 1;
} else {
$nb_devis[$dev["fk_statut_devis"]]++;
}
}
$dossiers = array();
foreach ($devis as $dev) {
if (!in_array($dev["dossier"], array_column($dossiers, 'dossier'))) {
$dossiers[] = array("dossier" => $dev["dossier"]);
}
}
echo json_encode(array(
"success" => true,
"devis" => $devis,
"nb_devis" => $nb_devis,
"dossiers" => $dossiers
));
} catch (Exception $e) {
error_log("Erreur recherche devis : " . $e->getMessage());
echo json_encode(array("success" => false, "message" => "Erreur lors de la recherche : " . $e->getMessage()));
}
}
break;
case "search_devis_sap":
eLog("=== search_devis_sap case appelé ===");
$rawData = file_get_contents("php://input");
eLog("Raw data: " . $rawData);
$data = json_decode($rawData);
eLog("Data decoded: " . print_r($data, true));
eLog("isset term: " . (isset($data->term) ? 'YES' : 'NO'));
if (isset($data->term)) {
$term = nettoie_input($data->term);
$context = nettoie_input($data->context);
if (strlen($term) < 3) {
echo json_encode(array("success" => false, "message" => "Le terme de recherche doit contenir au moins 3 caractères"));
break;
}
$termSafe = '%' . $term . '%';
$whereParams = [];
$whereRole = '1=1';
if ($context === "archives") {
$whereStatut = ' AND d.fk_statut_devis = 20';
} else {
$whereStatut = ' AND d.fk_statut_devis != 20';
}
$whereParams[':term1'] = $termSafe;
$whereParams[':term2'] = $termSafe;
$whereParams[':term3'] = $termSafe;
$whereParams[':term4'] = $termSafe;
$whereParams[':term5'] = $termSafe;
$whereParams[':term6'] = $termSafe;
$whereParams[':term7'] = $termSafe;
$whereParams[':term8'] = $termSafe;
$whereParams[':term9'] = $termSafe;
$whereParams[':term10'] = $termSafe;
$whereParams[':term11'] = $termSafe;
$whereParams[':term12'] = $termSafe;
$whereParams[':term13'] = $termSafe;
$whereParams[':term14'] = $termSafe;
$whereParams[':term15'] = $termSafe;
$whereParams[':term16'] = $termSafe;
$whereParams[':term17'] = $termSafe;
try {
$db = Database::getInstance();
$sql = 'SELECT DISTINCT d.rowid, d.dossier, d.date_demande, d.date_remise, d.num_opportunite, d.fk_client, d.montant_total_ht_remise, d.marge_totale, d.commentaire, d.chk_speciaux, c.libelle, c.ville, c.cp, d.fk_statut_devis, ';
$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, d.comment_devis, d.comment_geste_comm, ';
$sql .= 'd.contact_new_nom, d.contact_new_prenom, d.new_telephone, d.new_mobile, d.new_email, d.contact_new_fonction, LEFT(u.prenom,1) AS prenom, u.libelle as nom, ';
$sql .= 'xs.libelle as lib_statut, d.chk_new_statut, m.libelle as lib_marche, d.chk_validat, d.fk_user_validat, d.date_validat, c.code ';
$sql .= 'FROM devis d ';
$sql .= 'LEFT JOIN clients c ON c.rowid=d.fk_client ';
$sql .= 'LEFT JOIN x_statuts_devis xs ON xs.rowid=d.fk_statut_devis ';
$sql .= 'LEFT JOIN marches m ON m.rowid=d.fk_marche ';
$sql .= 'LEFT JOIN users u ON u.rowid=d.fk_user ';
$sql .= 'LEFT JOIN clients_contacts ct ON ct.fk_client=d.fk_client ';
$sql .= 'WHERE (' . $whereRole . ')' . $whereStatut . ' AND (';
$sql .= 'd.rowid LIKE :term1 OR ';
$sql .= 'c.libelle LIKE :term2 OR ';
$sql .= 'c.adresse1 LIKE :term3 OR ';
$sql .= 'c.adresse2 LIKE :term4 OR ';
$sql .= 'c.adresse3 LIKE :term5 OR ';
$sql .= 'c.cp LIKE :term6 OR ';
$sql .= 'c.ville LIKE :term7 OR ';
$sql .= 'c.code LIKE :term8 OR ';
$sql .= 'm.libelle LIKE :term9 OR ';
$sql .= 'd.num_opportunite LIKE :term10 OR ';
$sql .= 'd.lib_new_client LIKE :term11 OR ';
$sql .= 'd.cp_new_client LIKE :term12 OR ';
$sql .= 'd.ville_new_client LIKE :term13 OR ';
$sql .= 'ct.nom LIKE :term14 OR ';
$sql .= 'ct.prenom LIKE :term15 OR ';
$sql .= 'ct.fonction LIKE :term16 OR ';
$sql .= 'ct.email LIKE :term17) ';
$sql .= 'ORDER BY d.dossier, d.date_remise DESC';
eLog("=== SEARCH DEVIS SAP DEBUG ===");
eLog("Terme recherché: " . $term);
eLog("Context: " . $context);
eLog("SQL: " . $sql);
eLog("Params: " . print_r($whereParams, true));
$pdo = $db->getPDO();
$stmt = $pdo->prepare($sql);
$stmt->execute($whereParams);
$devis = $stmt->fetchAll(PDO::FETCH_ASSOC);
eLog("Nombre de devis trouvés: " . count($devis));
$nb_devis = array();
foreach ($devis as $dev) {
if (!isset($nb_devis[$dev["fk_statut_devis"]])) {
$nb_devis[$dev["fk_statut_devis"]] = 1;
} else {
$nb_devis[$dev["fk_statut_devis"]]++;
}
}
$dossiers = array();
foreach ($devis as $dev) {
if (!in_array($dev["dossier"], array_column($dossiers, 'dossier'))) {
$dossiers[] = array("dossier" => $dev["dossier"]);
}
}
echo json_encode(array(
"success" => true,
"devis" => $devis,
"nb_devis" => $nb_devis,
"dossiers" => $dossiers
));
} catch (Exception $e) {
error_log("Erreur recherche devis SAP : " . $e->getMessage());
echo json_encode(array("success" => false, "message" => "Erreur lors de la recherche : " . $e->getMessage()));
}
}
break;
}
exit();

View File

@@ -49,6 +49,64 @@ function formate_date($sdate)
return $ladate;
}
function syncContactClient($code, $contactNom, $contactPrenom, $contactFonction, $telephone, $mobile, $email, $fkUser)
{
try {
$db = Database::getInstance();
// 1. Compter les contacts actifs pour ce client
$sql = 'SELECT COUNT(*) as nb FROM clients_contacts WHERE fk_client = :code AND active = 1';
$countResult = $db->fetchAll($sql, [':code' => $code]);
$nbContacts = $countResult[0]['nb'];
if ($nbContacts == 0) {
// Aucun contact : créer directement avec principal=1
$principal = 1;
} else {
// Des contacts existent : vérifier si ce nom+prénom existe (en MAJUSCULES)
$sql = 'SELECT rowid FROM clients_contacts
WHERE fk_client = :code
AND UPPER(nom) = UPPER(:nom)
AND UPPER(prenom) = UPPER(:prenom)
AND active = 1';
$existingContact = $db->fetchAll($sql, [
':code' => $code,
':nom' => $contactNom,
':prenom' => $contactPrenom
]);
if (count($existingContact) > 0) {
// Contact déjà présent : ne rien faire
eLog("syncContactClient : Contact existe déjà pour client " . $code);
return;
}
// Contact pas trouvé : créer avec principal=0
$principal = 0;
}
// Créer le contact
$sql = 'INSERT INTO clients_contacts SET fk_client = :code, nom = :nom, prenom = :prenom, fonction = :fonction, telephone = :telephone, mobile = :mobile, email = :email, principal = :principal, active = 1, date_creat = NOW(), fk_user_creat = :fk_user';
$db->query($sql, [
':code' => $code,
':nom' => $contactNom,
':prenom' => $contactPrenom,
':fonction' => $contactFonction,
':telephone' => $telephone,
':mobile' => $mobile,
':email' => $email,
':principal' => $principal,
':fk_user' => $fkUser
]);
eLog("syncContactClient : Contact créé pour client " . $code . " (principal=" . $principal . ")");
} catch (Exception $e) {
error_log("Erreur syncContactClient : " . $e->getMessage());
eLog("Erreur syncContactClient pour client " . $code . " : " . $e->getMessage());
}
}
switch ($Route->_action) {
case "upload_clients":
@@ -171,6 +229,10 @@ switch ($Route->_action) {
]);
$fkClient = $db->lastInsertId();
fwrite($fhlog, $row . "--- Ajout client avec requête préparée\r\n");
// Synchroniser le contact dans clients_contacts
syncContactClient($code, $contactNom, $contactPrenom, $contactFonction, $telephone, $mobile, $email, $fkUser);
} catch (Exception $e) {
error_log("Erreur insertion client : " . $e->getMessage());
fwrite($fhlog, "Erreur insertion : " . $e->getMessage() . "\r\n");
@@ -212,6 +274,10 @@ switch ($Route->_action) {
':code' => $code
]);
fwrite($fhlog, $row . "--- MàJ client avec requête préparée\r\n");
// Synchroniser le contact dans clients_contacts
syncContactClient($code, $contactNom, $contactPrenom, $contactFonction, $telephone, $mobile, $email, $fkUser);
} catch (Exception $e) {
error_log("Erreur mise à jour client : " . $e->getMessage());
fwrite($fhlog, "Erreur MàJ : " . $e->getMessage() . "\r\n");