Initial commit: CLEO ERP avec améliorations debug

- Configuration du debug conditionnel pour dev/recette
- Fonction debug() globale avec niveaux
- Logging des requêtes SQL
- Handlers d'exceptions et d'erreurs globaux

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-04 10:24:52 +02:00
commit 99021b4f42
7348 changed files with 11423897 additions and 0 deletions

5
models/maccueil.php Normal file
View File

@@ -0,0 +1,5 @@
<?php
$aModel = array(
"infos" => getinfos('SELECT i.* FROM infos i WHERE i.chk_publie=1 ORDER BY i.date_infos DESC;', "gen"),
);

16
models/mclients.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
$sch = "";
if ($_POST) {
if (isset($_POST["schClients"])) {
$search = nettoie_input(trim($_POST["schClients"]));
$sch = '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 . '%" ';
}
}
//! On récupère la liste des clients
$sql = 'SELECT c.* FROM clients c ';
if ($sch != "") {
$sql .= 'WHERE ' . $sch;
}
$sql .= 'ORDER BY c.libelle';
$aModel["clients"] = getinfos($sql, "gen");

75
models/mdevis.php Normal file
View File

@@ -0,0 +1,75 @@
<?php
global $Session;
$fkUser = $Session->_user["rowid"];
$fkRole = $Session->_user["fk_role"];
switch ($fkRole) {
case 1:
// DIR-CO
$where = 'd.fk_user=' . $fkUser . ' OR d.fk_statut_devis>=2';
break;
case 2:
// DV : on récupère tous les RR de son périmètre
$sql = 'SELECT rowid FROM users WHERE fk_parent =' . $fkUser . ';';
$aRR = getinfos($sql, "gen");
$lstRR = '';
foreach ($aRR as $rr) {
$lstRR .= $rr["rowid"] . ',';
}
$lstRR = substr($lstRR, 0, -1);
$where = 'd.fk_user=' . $fkUser . ' OR (d.fk_statut_devis>=3 AND d.fk_user IN (' . $lstRR . '))';
break;
default:
// RR
$where = 'd.fk_user=' . $fkUser;
break;
}
$sql = 'SELECT 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 LEFT JOIN clients c ON c.rowid=d.fk_client LEFT JOIN x_statuts_devis xs ON xs.rowid=d.fk_statut_devis LEFT JOIN marches m ON m.rowid=d.fk_marche LEFT JOIN users u ON u.rowid=d.fk_user ';
$sql .= 'WHERE ' . $where . ' ORDER BY d.dossier, d.date_remise DESC;';
$aModel["devis"] = getinfos($sql, "gen");
//! on compte le nombre de devis par statut
$aModel["nb_devis"] = array();
foreach ($aModel["devis"] as $devis) {
if (!isset($aModel["nb_devis"][$devis["fk_statut_devis"]])) {
$aModel["nb_devis"][$devis["fk_statut_devis"]] = 1;
} else {
$aModel["nb_devis"][$devis["fk_statut_devis"]]++;
}
}
//! On récupère la liste des dossiers des devis
$sql = 'SELECT DISTINCT d.dossier FROM devis d WHERE ' . $where . ' ORDER BY d.dossier;';
$aModel["dossiers"] = getinfos($sql, "gen");
//! Tous les produits du catalogue
$sql = 'SELECT rowid, code, libelle, prix_vente, prix_achat_net FROM produits WHERE active=1;';
$aModel["produits"] = getinfos($sql, "gen");
//! toutes les familles de produits
$sql = 'SELECT rowid, libelle, ordre FROM x_familles WHERE active=1 ORDER BY ordre;';
$aModel["familles"] = getinfos($sql, "gen");
$sql = 'SELECT m.* FROM marches m WHERE m.active=1 AND m.chk_cache_commerciaux=0 ORDER BY m.libelle;';
$aModel["marches"] = getinfos($sql, "gen");
//! les types de clients
$sql = 'SELECT rowid, code, libelle FROM x_clients_types WHERE active=1 ORDER BY code;';
$aModel["types_clients"] = getinfos($sql, "gen");
//! les statuts de devis sans le 20 - Archivés
$sql = 'SELECT rowid, libelle FROM x_statuts_devis WHERE active=1 AND rowid<20 ORDER BY rowid;';
$aModel["statuts_devis"] = getinfos($sql, "gen");
// On récupère le dernier numéro de devis mis à jour de la session
if (isset($_SESSION["lastDevis"])) {
$aModel["last_devis"] = $_SESSION["lastDevis"];
} else {
$aModel["last_devis"] = 0;
}

217
models/mexpxls.php Normal file
View File

@@ -0,0 +1,217 @@
<?php
global $Route;
function cleanData(&$str)
{
// Fonction de nettoyage des données pour l'export Excel
if ($str == 't') $str = 'TRUE';
if ($str == 'f') $str = 'FALSE';
if (preg_match("/^0/", $str) || preg_match("/^\+?\d{8,}$/", $str) || preg_match("/^\d{4}.\d{1,2}.\d{1,2}/", $str)) {
$str = "'$str";
}
if (strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
$str = mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');
}
function filterData(&$str)
{
$str = preg_replace("/\t/", "\\t", $str);
$str = preg_replace("/\r?\n/", "\\n", $str);
if ($str == 't') $str = 'TRUE';
if ($str == 'f') $str = 'FALSE';
if (preg_match("/^0/", $str) || preg_match("/^\+?\d{8,}$/", $str) || preg_match("/^\d{4}.\d{1,2}.\d{1,2}/", $str)) {
$str = "'$str";
}
if (strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
$str = mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');
// $str = iconv('UTF-8', 'UTF-8', $str);
}
switch ($Route->_action) {
case "export_tpg":
$sql = 'SELECT p.code, p.libelle, p.groupe, IF(p.prix_vente=0, "", FORMAT(p.prix_vente, 2, "fr_FR")) AS vente FROM produits p WHERE p.fk_marche=999 AND p.active=1 ORDER BY p.code;';
$prods = getinfos($sql, "gen");
$fileName = "TPG_" . date('Y_m_d_hi') . ".xls";
$excelData = "TPG AU " . date('d/m/Y') . "\n";
$cols = array("code", "Libelle", "Groupe", "Prix Vente");
$excelData .= implode("\t", array_values($cols)) . "\n";
foreach ($prods as $prod) {
array_walk($prod, 'filterData');
$excelData .= implode("\t", $prod) . "\n";
}
// une ligne vierge de séparation
$excelData .= "\n";
header('Content-Type: application/vnd.ms-excel; charset=utf-16le');
header("Content-type: application/x-msexcel; charset=utf-16le");
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Cache-Control: max-age=0');
echo $excelData;
exit();
break;
case "export_sap_devis":
$cid = nettoie_input($Route->_param1);
$sql = 'SELECT d.* FROM devis d WHERE d.rowid=' . $cid . ';';
eLog("Export Excel SAP Devis : " . $sql);
$dev = getinfos($sql, "gen");
$devis = $dev[0];
$fileName = "devis_" . $cid . "_" . date('Y_m_d_hi') . ".xls";
// On affiche les données client
$fields = array("Code", "Etablissement", "Adresse 1", "Adresse 2", "Adresse 3", "Code Postal", "Ville");
$excelData = implode("\t", array_values($fields)) . "\n";
$sql = 'SELECT c.code, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.cp, c.ville FROM clients c WHERE c.rowid=' . $devis["fk_client"] . ';';
$cli = getinfos($sql, "gen");
if (count($cli) == 0) {
// c'est un nouveau client, on affiche les données client enregistrées dans le devis
$sql = 'SELECT "0" AS code, d.lib_new_client, d.adresse1_new_client, d.adresse2_new_client, d.adresse3_new_client, d.cp_new_client, d.ville_new_client FROM devis d WHERE d.rowid=' . $cid . ';';
$cli = getinfos($sql, "gen");
$client = $cli[0];
array_walk($client, 'filterData');
$excelData .= implode("\t", array_values($client)) . "\n";
// une ligne vierge de séparation
$excelData .= "\n";
// Les données du contact à prendre aussi dans le devis
$sql = 'SELECT d.contact_new_nom, d.contact_new_prenom, d.contact_new_fonction, d.new_telephone, d.new_mobile, d.new_email FROM devis d WHERE d.rowid=' . $cid . ';';
$cont = getinfos($sql, "gen");
$contact = $cont[0];
$fields = array("Contact Nom", "Prenom", "Fonction", "Fixe", "Mobile", "Email");
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($contact, 'filterData');
$excelData .= implode("\t", array_values($contact)) . "\n";
} else {
$client = $cli[0];
array_walk($client, 'filterData');
$excelData .= implode("\t", array_values($client)) . "\n";
// une ligne vierge de séparation
$excelData .= "\n";
// Les données du contact
$sql = 'SELECT c.contact_nom, c.contact_prenom, c.contact_fonction, c.telephone, c.mobile, c.email FROM clients c WHERE c.rowid=' . $devis["fk_client"] . ';';
$cont = getinfos($sql, "gen");
$contact = $cont[0];
$fields = array("Contact Nom", "Prenom", "Fonction", "Fixe", "Mobile", "Email");
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($contact, 'filterData');
$excelData .= implode("\t", array_values($contact)) . "\n";
}
// une ligne vierge de séparation
$excelData .= "\n";
// On affiche les données devis
$sql = 'SELECT d.rowid, d.num_opportunite, IF(d.date_demande IS NULL OR d.date_demande="0000-00-00", "", DATE_FORMAT(d.date_demande, "%d/%m/%Y")) AS datedem, ';
$sql .= 'IF(d.date_remise IS NULL OR d.date_remise="0000-00-00", "", DATE_FORMAT(d.date_remise, "%d/%m/%Y")) AS daterem, m.libelle AS lib_marche, m.numero AS num_marche, m.nom AS nom_marche, ';
$sql .= 'IF(d.chk_devis_photos=1, "Oui", "Non") AS photos, d.commentaire, IF(d.chk_speciaux=1, "Oui", "Non") AS speciaux ';
$sql .= 'FROM devis d LEFT JOIN marches m ON d.fk_marche=m.rowid WHERE d.rowid=' . $cid . ';';
$dev = getinfos($sql, "gen");
$devis = $dev[0];
$chkSpeciaux = $devis["speciaux"];
$fields = array("Devis", "Opportunite", "Date Demande", "Date remise client", "Marche", "Num Marche", "Nom Marche", "Avec photos", "Commentaire RR", "Speciaux");
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($devis, 'filterData');
$excelData .= implode("\t", array_values($devis)) . "\n";
// une ligne vierge de séparation
$excelData .= "\n";
// on affiche les totaux du devis
$sql = 'SELECT d.montant_total_ht, d.montant_total_ht_remise, d.marge_totale FROM devis d WHERE d.rowid=' . $cid . ';';
$dev = getinfos($sql, "gen");
$totaux = $dev[0];
$fields = array("Total HT", "Total HT Remise", "Marge Totale");
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($totaux, 'filterData');
$excelData .= implode("\t", array_values($totaux)) . "\n";
// une ligne vierge de séparation
$excelData .= "\n";
// on affiche les produits
$sql = 'SELECT p.code, p.libelle, IF(p.prix_vente=0, "", FORMAT(p.prix_vente, 2, "fr_FR")) AS vente, ';
$sql .= 'IF(dp.qte=0, "", dp.qte) AS qute, IF(dp.remise=0, "", FORMAT(dp.remise, 2, "fr_FR")) as remise, IF(dp.pu_vente_remise=0, "", FORMAT(dp.pu_vente_remise, 2, "fr_FR")) as puventeremise, ';
$sql .= 'IF(dp.totalht=0, "", FORMAT(dp.totalht, 2, "fr_FR")) AS totht, IF(dp.marge=0, "", FORMAT(dp.marge, 2, "fr_FR")) AS marge, dp.commentaire ';
$sql .= 'FROM devis_produits dp ';
$sql .= 'LEFT JOIN produits p ON dp.fk_produit=p.rowid ';
$sql .= 'LEFT JOIN produits_familles pf ON p.groupe=pf.groupe ';
$sql .= 'LEFT JOIN x_familles xf ON pf.fk_famille=xf.rowid ';
$sql .= 'WHERE dp.fk_devis=' . $cid . ' ORDER BY dp.ordre, xf.ordre, p.libelle;';
$data = getinfos($sql, "gen");
$fields = array("Code", "Designation", "Prix Vente", "Quantite", "Remise", "PU vente avec remise", "Total HT", "Marge", "Commentaire");
$excelData .= implode("\t", array_values($fields)) . "\n";
foreach ($data as $row) {
array_walk($row, 'filterData');
$excelData .= implode("\t", $row) . "\n";
}
if ($chkSpeciaux == "Oui") {
// une ligne vierge de séparation
$excelData .= "\n";
$excelData .= "----" . "\n";
$excelData .= "PRODUITS SPECIAUX" . "\n";
$excelData .= "----" . "\n";
$sql = 'SELECT IF(ds.chk_livr_multi=1, "Oui", "Non") AS livr_multi, ds.nb_livr, DATE_FORMAT(ds.date_livr_1, "%d/%m/%Y") AS datelivr ';
$sql .= 'FROM devis_speciaux ds WHERE ds.fk_devis=' . $cid . ';';
$spec = getinfos($sql, "gen");
$speciaux = $spec[0];
$fields = array("Livraisons multiples", "Nbre livraisons", "Date 1ere livraison");
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($speciaux, 'filterData');
$excelData .= implode("\t", array_values($speciaux)) . "\n";
$excelData .= "\n";
$fields = array("#", "Code", "Designation", "Quantite", "Surcout", "Echantillon", "Date echantillon", "Concurrent", "Description");
$excelData .= implode("\t", array_values($fields)) . "\n";
for ($i = 1; $i <= 5; $i++) {
$sql = 'SELECT ds.fk_produit_' . $i . ', ds.code_produit_' . $i . ', ds.lib_produit_' . $i . ', ds.qte_' . $i . ', IF(ds.surcout_' . $i . '=0, "", FORMAT(ds.surcout_' . $i . ', 2, "fr_FR")), IF(ds.chk_echantillon_' . $i . '=1, "Oui", "Non") AS echantillon, ';
$sql .= 'DATE_FORMAT(ds.date_echantillon_' . $i . ', "%d/%m/%Y") AS date_ech, ds.lib_concurrent_' . $i . ', ds.description_' . $i . ' ';
$sql .= 'FROM devis_speciaux ds WHERE ds.fk_devis=' . $cid . ';';
eLog($sql, "sql");
$spec = getinfos($sql, "gen");
$speciaux = $spec[0];
if ($speciaux["fk_produit_" . $i] > 0) {
array_walk($speciaux, 'filterData');
$excelData .= implode("\t", array_values($speciaux)) . "\n";
}
}
}
// une ligne vierge de séparation
$excelData .= "\n";
$excelData .= "----" . "\n";
$excelData .= "FIN DU DEVIS" . "\n";
$excelData .= "----" . "\n";
$excelData .= "\n";
header('Content-Type: application/vnd.ms-excel; charset=utf-16le');
header("Content-type: application/x-msexcel; charset=utf-16le");
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Cache-Control: max-age=0');
echo $excelData;
exit();
}

3
models/minterface.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
$aModel["infos"] = getinfos('SELECT i.* FROM infos i ORDER BY i.date_infos DESC;');

44
models/mlogin.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
$aModel = array();
function openSession($userdata)
{
$uid = $userdata['rowid'];
$urole = $userdata['role'];
$sql = "DELETE FROM z_sessions WHERE fk_user=" . $uid . ";";
qSQL($sql, "gen");
session_regenerate_id();
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
$uip = $_SERVER["HTTP_CLIENT_IP"];
} elseif (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$uip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else {
$uip = $_SERVER["REMOTE_ADDR"];
}
$utime = time();
//! en session on récupère son prénom et nom, son id, son ip et son rôle
$_SESSION['uname'] = ucfirst($userdata["prenom"]) . " " . strtoupper($userdata["libelle"]);
$_SESSION['uid'] = $uid;
$_SESSION['urole'] = $urole;
$_SESSION['umodified'] = $utime;
$_SESSION['uip'] = $uip;
session_write_close();
$sql = "INSERT INTO z_sessions (sid, fk_user, role, date_modified, ip, browser) VALUES ('" . session_id() . "', " . $uid . ", '" . $urole . "', '" . date("Y-m-d H:i:s") . "', '" . $uip . "', '" . $_SERVER['HTTP_USER_AGENT'] . "');";
qSQL($sql, "gen");
// et on en profite pour purger les logs
$sql = "DELETE FROM z_logs WHERE DATEDIFF(CURDATE(), z_logs.date)>5;";
qSQL($sql);
// ainsi que les sessions qui ont une date antérieure à 1 jour
$sql = "DELETE FROM z_sessions WHERE DATEDIFF(CURDATE(), z_sessions.date_modified)>1;";
qSQL($sql, "gen");
envoieMail("support@unikoffice.com", "Ouverture de session", "Ouverture de session pour " . $uid);
return TRUE;
}

11
models/mmarches.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
$sch = "";
if ($_POST) {
if (isset($_POST["chproduits"])) {
$search = trim($_POST["chproduits"]);
$sch = 'libelle LIKE "%' . $search . '%" OR libelle_court LIKE "%' . $search . '%"';
}
}
$sql = 'SELECT m.rowid, m.libelle, m.date_debut, m.date_fin, m.date_validite_prix, m.date_import, m.chk_remise_sur_tg, m.chk_marche_hybride, m.active FROM marches m ORDER BY m.libelle;';
$aModel["lesmarches"] = getinfos($sql, "gen");

42
models/msap.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
$aModel = array();
$sql = 'SELECT m.* FROM medias m WHERE m.support="devis_pdf_sap" ORDER BY m.support_rowid;';
$aModel["medias"] = getinfos($sql, "gen");
$sql = 'SELECT d.*, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.code, c.cp, c.ville, c.email, u.libelle as nom, u.prenom, s.libelle as lib_statut, m.libelle as lib_marche ';
$sql .= 'FROM devis d ';
$sql .= 'LEFT JOIN clients c on d.fk_client = c.rowid ';
$sql .= 'LEFT JOIN users u ON d.fk_user = u.rowid ';
$sql .= 'LEFT JOIN marches m ON d.fk_marche = m.rowid ';
$sql .= 'LEFT JOIN x_statuts_devis s ON d.fk_statut_devis = s.rowid ';
$sql .= 'WHERE (d.fk_statut_devis > 3 AND d.fk_statut_devis < 20) ORDER BY d.date_demande;';
$aModel["devisEnCours"] = getinfos($sql, "gen");
//! on compte le nombre de devis par statut
$aModel["nb_devis"] = array();
foreach ($aModel["devisEnCours"] as $devis) {
if (!isset($aModel["nb_devis"][$devis["fk_statut_devis"]])) {
$aModel["nb_devis"][$devis["fk_statut_devis"]] = 1;
} else {
$aModel["nb_devis"][$devis["fk_statut_devis"]]++;
}
}
$sql = 'SELECT d.*, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.code, c.cp, c.ville, u.libelle as nom, u.prenom, s.libelle as lib_statut, m.libelle as lib_marche ';
$sql .= 'FROM devis d ';
$sql .= 'LEFT JOIN clients c on d.fk_client = c.rowid ';
$sql .= 'LEFT JOIN users u ON d.fk_user = u.rowid ';
$sql .= 'LEFT JOIN marches m ON d.fk_marche = m.rowid ';
$sql .= 'LEFT JOIN x_statuts_devis s ON d.fk_statut_devis = s.rowid ';
$sql .= 'WHERE d.fk_statut_devis = 20 ORDER BY d.date_remise;';
$aModel["devisArchives"] = getinfos($sql, "gen");
//! les statuts de devis sans le 20 - Archivés pour afficher les devis en cours à traiter au niveau de l'ADV
$sql = 'SELECT rowid, libelle FROM x_statuts_devis WHERE active=1 AND rowid>3 AND rowid<20 ORDER BY rowid;';
$aModel["statuts_devis"] = getinfos($sql, "gen");
//! On récupère la liste des dossiers des devis pour afficher les devis archivés par département
$sql = 'SELECT DISTINCT d.dossier FROM devis d WHERE d.fk_statut_devis = 20 ORDER BY dossier;';
$aModel["dossiers"] = getinfos($sql, "gen");

12
models/musers.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
$sql = 'SELECT u.*, xrol.libelle AS lib_role, xreg.libelle AS lib_region FROM users u LEFT JOIN x_roles xrol on u.fk_role = xrol.rowid LEFT JOIN x_regions xreg on u.fk_region = xreg.rowid ORDER BY u.libelle, u.prenom;';
$aModel["users"] = getinfos($sql, "gen");
$sql = 'SELECT rowid, libelle, abreviation FROM x_roles WHERE active=1 ORDER BY libelle;';
$aModel["roles"] = getinfos($sql, "gen");
$sql = 'SELECT rowid, libelle FROM x_regions WHERE active=1 ORDER BY libelle;';
$aModel["regions"] = getinfos($sql, "gen");
$sql = 'SELECT u.rowid, CONCAT(u.prenom, " ", u.libelle, " (", xrol.abreviation, ")") AS lib_parent FROM users u LEFT JOIN x_roles xrol on u.fk_role = xrol.rowid WHERE u.fk_role IN (1,2) ORDER BY lib_parent;';
$aModel["parents"] = getinfos($sql, "gen");