Fonctionnalités principales : 1. Marchés hybrides - Onglet Mercurial - Ajout onglet Mercurial avec style distinct (vert, gras, blanc) - Affichage des produits mercuriaux pour marchés hybrides - Filtrage automatique des produits "Hors Marché 999" - Documentation Phase 2 avec CAS 1 et CAS 2 de marchés hybrides - Règles métier pour validation différenciée (devis 100% mercurial vs mixte) 2. Corrections bugs - Fix flag chkChange sur onglet "Sélection Produits" (callback asynchrone) - Plus d'alerte intempestive après sauvegarde des produits 3. Outils de déploiement - Nouveau script deploy-file.sh pour déploiement unitaire (DEV/PROD) - Amélioration deploy-cleo.sh 4. Gestion multi-contacts (v2.0.3) - Contrôleur AJAX cjxcontacts.php - Script migration clients_contacts - Documentation complète 5. Documentation - Mise à jour TODO.md avec Phase 2 marchés hybrides - Mise à jour README.md v2.0.3 - Ajout RULES.md - Ajout migration_clients_contacts.sql 6. Nettoyage - Suppression fichiers obsolètes (conf_new.php, conf_old.php, uof_linet_20250911.sql) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
894 lines
35 KiB
PHP
894 lines
35 KiB
PHP
<?php
|
|
global $Session;
|
|
global $Conf;
|
|
global $Route;
|
|
|
|
//! on va chercher la data de la Session au format tableau
|
|
$session_data = $Session->get_data();
|
|
//! où on récupère le fk_tiers sur lequel l'utilisateur travaille
|
|
if (isset($session_data["tiers"])) {
|
|
$fk_tiers = $session_data["tiers"];
|
|
} else {
|
|
$fk_tiers = 0;
|
|
}
|
|
|
|
$fk_user = $Session->_user["rowid"];
|
|
|
|
eLog("jxpost action : " . $Route->_action);
|
|
|
|
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 (strstr($str, '"')) $str = '"' . str_replace('"', '""', $str) . '"';
|
|
}
|
|
|
|
switch ($Route->_action) {
|
|
case "filter":
|
|
$idfilter = $_POST["idfilter"];
|
|
switch ($idfilter) {
|
|
case "filtertiers":
|
|
$Session->set_data($idfilter . "_search", $_POST["filter_search"]);
|
|
$Session->set_data($idfilter . "_contact", $_POST["filter_contact"]);
|
|
$Session->set_data($idfilter . "_ape", $_POST["filter_ape"]);
|
|
if (isset($_POST["filter_recent"])) {
|
|
$recent = 1;
|
|
} else {
|
|
$recent = 0;
|
|
}
|
|
$Session->set_data($idfilter . "_recent", $recent);
|
|
if (isset($_POST["filter_agenda"])) {
|
|
$agenda = 1;
|
|
} else {
|
|
$agenda = 0;
|
|
}
|
|
$Session->set_data($idfilter . "_agenda", $agenda);
|
|
if (isset($_POST["filter_archive"])) {
|
|
$archive = 1;
|
|
} else {
|
|
$archive = 0;
|
|
}
|
|
$Session->set_data($idfilter . "_archive", $archive);
|
|
$Session->set_data($idfilter . "_type_tiers", $_POST["filter_type_tiers"]);
|
|
$Session->set_data($idfilter . "_ville", $_POST["filter_villeA"]); //! filter_villeA parce que c'est un autocomplete : retourne le rowid qui est en fait la ville !
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case "upfind":
|
|
$tab = $_POST["win"];
|
|
$lid = $Route->_param1;
|
|
|
|
if ($Conf::erp) {
|
|
$sql = 'SELECT * FROM medias WHERE dir2="' . $tab . '" AND support_rowid=' . $lid . ';';
|
|
} else {
|
|
$sql = 'SELECT * FROM medias WHERE support="' . $tab . '" AND support_rowid=' . $lid . ';';
|
|
}
|
|
$upls = array();
|
|
$upls = getinfos($sql, "groupe");
|
|
echo json_encode($upls);
|
|
break;
|
|
|
|
case "updelete":
|
|
updelete($_POST);
|
|
break;
|
|
|
|
case "upload":
|
|
if ($Conf::erp) {
|
|
upload($_POST);
|
|
} else {
|
|
upload_old($_POST);
|
|
}
|
|
break;
|
|
|
|
case "medias":
|
|
$user = $Session->_user["rowid"];
|
|
$type = $Route->_param1; //! facture par exemple
|
|
if (isset($_POST["rowid"])) {
|
|
$rowid = $_POST["rowid"]; //! c'est le rowid de la facture par exemple
|
|
if ($type == "facture" || $type == "devis") {
|
|
//! on doit aller chercher le num_facture pour avoir le nom du fichier
|
|
if ($type == "facture") {
|
|
$num_facture = getdata("devis", $rowid, "num_facture");
|
|
} else {
|
|
$num_facture = getdata("devis", $rowid, "num_devis");
|
|
}
|
|
$fk_tiers = getdata("devis", $rowid, "fk_soc");
|
|
$nom_tiers = str_normalize(getdata("clients", $fk_tiers, "libelle", "groupe"));
|
|
if ($Conf->_entite["raz_num_devis"]) {
|
|
$num_facture = substr('000' . $num_facture, -3);
|
|
} else {
|
|
$num_facture = substr('0000' . $num_facture, -4);
|
|
}
|
|
$support = $fk_tiers;
|
|
$filename = $fk_tiers . "_" . $type . "_" . $num_facture . ".pdf";
|
|
if (isset($_POST["relance"])) {
|
|
$filename = $fk_tiers . "_" . $type . "_" . $num_facture . "_relance_" . date("Ymd") . ".pdf";
|
|
}
|
|
$typ = "pdf";
|
|
$dir0 = "tiers";
|
|
$dir1 = $nom_tiers;
|
|
} else {
|
|
$support = $type;
|
|
$filename = $rowid . ".pdf";
|
|
$typ = "pdf";
|
|
$rep = $type . DS . $rowid . DS . "pdf";
|
|
$dir0 = "tiers";
|
|
$dir1 = "dir1";
|
|
}
|
|
$dir2 = $type;
|
|
$des = "";
|
|
$pos = "L";
|
|
$hau = 0;
|
|
$lar = 0;
|
|
//! On vérifie d'abord qu'il n'y ait pas un média existant pour le même support, le même support_rowid et le même nom de fichier : doublon !
|
|
$sql = 'SELECT * FROM medias WHERE dir0="' . $dir0 . '" AND dir1="' . $dir1 . '" AND dir2="' . $dir2 . '" AND fichier="' . $filename . '";';
|
|
$doublon = getinfos($sql, "groupe");
|
|
if (count($doublon) == 0) {
|
|
//! il n'y a pas de doublon, on peut créer l'enregistrement
|
|
$sql = 'INSERT INTO medias SET dir0="' . $dir0 . '", dir1="' . $dir1 . '", dir2="' . $dir2 . '", support_rowid=' . $rowid . ', fichier="' . $filename . '", fk_user_creat=' . $user . ', ';
|
|
$sql .= 'type_fichier="' . $typ . '", date_creat="' . date("Y-m-d H:i:s") . '", description="' . $des . '", position="' . $pos . '", hauteur=' . $hau . ', largeur=' . $lar . ';';
|
|
} else {
|
|
//! l'enregistrement existe déjà : on met à jour date_modif et fk_user_modif
|
|
$sql = 'UPDATE medias SET date_modif="' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $user . ' WHERE dir0="' . $dir0 . '" AND dir1="' . $dir1 . '" AND dir2="' . $dir2 . '" AND fichier="' . $filename . '";';
|
|
}
|
|
eLog("jxpost medias : " . $sql);
|
|
qSQL($sql, "groupe");
|
|
}
|
|
break;
|
|
|
|
case "refresh":
|
|
$win = $Route->_param1;
|
|
if ($win != "") {
|
|
if (isset($_POST["input"])) {
|
|
$input = $_POST["input"];
|
|
switch ($win) {
|
|
case "winaction":
|
|
//! un refresh dans la fenêtre modale winaction
|
|
if ($input == "fk_contact") {
|
|
$sql = "SELECT rowid, CONCAT(firstname, ' ', name) AS libelle FROM contacts WHERE fk_soc=" . $fk_tiers . " ORDER BY libelle;";
|
|
$res = qSQL($sql, "groupe");
|
|
$arr = array();
|
|
if ($res instanceof PDOStatement) {
|
|
while ($rec = $res->fetch(PDO::FETCH_ASSOC)) {
|
|
$arr[] = $rec;
|
|
}
|
|
}
|
|
$jsonresult = json_encode($arr);
|
|
$lignes = $jsonresult;
|
|
echo $lignes;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "mediafind":
|
|
$tab = $_POST["win"];
|
|
$lid = $Route->_param1;
|
|
|
|
if ($Conf::erp) {
|
|
$sql = 'SELECT * FROM medias WHERE dir2="' . $tab . '" AND support_rowid=' . $lid . ';';
|
|
} else {
|
|
$sql = 'SELECT * FROM medias WHERE support="' . $tab . '" AND support_rowid=' . $lid . ';';
|
|
}
|
|
$upls = array();
|
|
$upls = getinfos($sql, "groupe");
|
|
$upls = $upls[0];
|
|
echo json_encode($upls);
|
|
break;
|
|
|
|
case "getdata":
|
|
$chp = $_POST["chp"];
|
|
$typ = $Route->_param1;
|
|
$upls = array();
|
|
|
|
switch ($typ) {
|
|
case "tiers":
|
|
// SÉCURITÉ : Liste blanche des colonnes autorisées
|
|
$allowedColumns = ['code', 'libelle', 'adresse1', 'adresse2', 'adresse3', 'cp', 'ville',
|
|
'contact_nom', 'contact_prenom', 'contact_fonction', 'telephone', 'mobile', 'email'];
|
|
|
|
if (!in_array($chp, $allowedColumns)) {
|
|
echo json_encode(array('error' => 'Colonne non autorisée'));
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
// SÉCURITÉ : Utilisation de requête préparée pour l'ID
|
|
$sql = "SELECT `$chp` AS data FROM clients WHERE rowid = :id";
|
|
$result = $db->fetchOne($sql, [':id' => intval($fk_tiers)]);
|
|
if ($result) {
|
|
$upls = $result;
|
|
}
|
|
} catch (Exception $e) {
|
|
error_log("Erreur getdata : " . $e->getMessage());
|
|
}
|
|
break;
|
|
}
|
|
|
|
echo json_encode($upls);
|
|
break;
|
|
|
|
case "setsession":
|
|
if (isset($_POST["key"]) && isset($_POST["val"])) {
|
|
$Session->set_data($_POST["key"], $_POST["val"]);
|
|
}
|
|
break;
|
|
|
|
// case "autocomplete" supprimé car non utilisé dans l'application
|
|
// L'autocomplétion est gérée côté client JavaScript
|
|
|
|
case "get_context":
|
|
//! Renvoie le contexte de l'utilisateur
|
|
$ajson = array();
|
|
$ajson["user"] = $Session->_user;
|
|
$ajson["session"] = $Session->get_data();
|
|
$ajson["devip"] = $Conf->_devIp ? "1" : "0";
|
|
echo json_encode($ajson);
|
|
break;
|
|
|
|
case "load_client":
|
|
//! Charge les infos d'un client
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
// SÉCURITÉ : Validation de l'ID et requête préparée
|
|
$cid = intval($data->cid);
|
|
if ($cid <= 0) {
|
|
echo json_encode(array('error' => 'ID client invalide'));
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
$result = $db->getById('clients', $cid);
|
|
echo json_encode($result ?: array());
|
|
} catch (Exception $e) {
|
|
error_log("Erreur load_client : " . $e->getMessage());
|
|
echo json_encode(array('error' => 'Erreur lors du chargement du client'));
|
|
}
|
|
} else {
|
|
echo json_encode(array('error' => 'Pas de client spécifié'));
|
|
}
|
|
break;
|
|
|
|
case "search_clients":
|
|
//! Cherche les clients correspondant à un libellé, une adresse, un code postal, une ville, un nom, un prénom, une fonction ou un email
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->search)) {
|
|
// SÉCURITÉ : Utilisation de requêtes préparées pour la recherche
|
|
$search = trim($data->search);
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
$sql = 'SELECT c.rowid, c.libelle, c.type_client, c.adresse1, c.cp, c.ville FROM clients c
|
|
WHERE c.libelle LIKE :search
|
|
OR c.adresse1 LIKE :search
|
|
OR c.cp LIKE :search
|
|
OR c.ville LIKE :search
|
|
OR c.contact_nom LIKE :search
|
|
OR c.contact_prenom LIKE :search
|
|
OR c.contact_fonction LIKE :search
|
|
OR c.email LIKE :search
|
|
ORDER BY c.libelle';
|
|
|
|
$searchParam = '%' . $search . '%';
|
|
$results = $db->fetchAll($sql, [':search' => $searchParam]);
|
|
echo json_encode($results);
|
|
} catch (Exception $e) {
|
|
error_log("Erreur search_clients : " . $e->getMessage());
|
|
echo json_encode(array('error' => 'Erreur lors de la recherche'));
|
|
}
|
|
} else {
|
|
echo json_encode(array('ret' => "ko"));
|
|
}
|
|
break;
|
|
|
|
case "load_marches":
|
|
//! charge des infos de tous les marchés
|
|
$sql = 'SELECT m.rowid, m.libelle FROM marches m ORDER BY m.libelle DESC;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "load_marche":
|
|
//! Charge les infos d'un marché
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
$sql = 'SELECT m.* FROM marches m WHERE m.rowid=' . $cid . ';';
|
|
echo getinfos($sql, "gen", "json");
|
|
} else {
|
|
$ret = array('ret' => "ko");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "search_produits":
|
|
//! Cherche les produits correspondant à un code ou à un libellé
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->search)) {
|
|
$search = nettoie_input($data->search);
|
|
$sql = 'SELECT p.*, pf.famille FROM produits p LEFT JOIN produits_familles pf ON p.fk_famille_produit=pf.rowid ';
|
|
$sql .= 'WHERE (p.code LIKE "%' . $search . '%" OR p.libelle LIKE "%' . $search . '%" OR p.groupe LIKE "%' . $search . '%" OR pf.famille LIKE "%' . $search . '%") AND p.prix_vente>0 AND p.active=1 ';
|
|
$sql .= 'ORDER BY p.libelle;';
|
|
echo getinfos($sql, "gen", "json");
|
|
} else {
|
|
$ret = array('ret' => "ko");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "load_familles":
|
|
//! Charge les familles de produits existantes
|
|
$sql = 'SELECT xf.* FROM x_familles xf ORDER BY xf.ordre;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "load_familles_groupes":
|
|
//! Charge les familles par groupes de produits existantes
|
|
$sql = 'SELECT pf.* FROM produits_familles pf ORDER BY pf.ordre, pf.groupe;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "save_familles":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
|
|
//! on récupère les familles existantes
|
|
$sql = 'SELECT pf.rowid FROM produits_familles pf ORDER BY pf.rowid;';
|
|
$pf = getinfos($sql, "gen");
|
|
//! on les désactive toutes
|
|
$sql = 'UPDATE produits_familles SET active=0;';
|
|
qSQL($sql);
|
|
|
|
//! on boucle sur les familles reçues
|
|
foreach ($data as $row) {
|
|
$rowid = nettoie_input($row->id);
|
|
$set = 'groupe="' . nettoie_input(trim($row->groupe)) . '", ';
|
|
$set .= 'ordre="' . nettoie_input(trim($row->ordre)) . '", ';
|
|
$set .= 'fk_famille="' . nettoie_input(trim($row->famille)) . '", ';
|
|
$set .= 'code_maintenance="' . nettoie_input(trim($row->maintenance)) . '", ';
|
|
$set .= 'marge_rr="' . nettoie_input(trim($row->margerr)) . '", ';
|
|
$set .= 'marge_dv="' . nettoie_input(trim($row->margedv)) . '", ';
|
|
$set .= 'active=1 ';
|
|
//! on recherche si la famille existe déjà
|
|
$found = false;
|
|
foreach ($pf as $p) {
|
|
if ($p["rowid"] == $rowid) {
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$found) {
|
|
//! Si la famille n'existe pas, on la crée
|
|
$sql = 'INSERT INTO produits_familles SET ' . $set . ';';
|
|
} else {
|
|
//! Sinon on la met à jour
|
|
$sql = 'UPDATE produits_familles SET ' . $set . ' ';
|
|
$sql .= 'WHERE rowid=' . $rowid . ';';
|
|
}
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
}
|
|
//! enfin, on supprime toutes les familles qui n'ont pas été reçues, active=0
|
|
$sql = 'DELETE FROM produits_familles WHERE active=0;';
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
|
|
$ret = array('ret' => "ok", 'msg' => "Enregistrement des familles effectué");
|
|
echo json_encode($ret);
|
|
break;
|
|
|
|
case "save_marche":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->rowid)) {
|
|
$cid = nettoie_input($data->rowid);
|
|
$act = nettoie_input($data->act);
|
|
|
|
$set = 'SET libelle="' . nettoie_input(trim($data->libelle)) . '"';
|
|
$set .= ', numero="' . nettoie_input($data->numero) . '"';
|
|
$set .= ', nom="' . nettoie_input($data->nom) . '"';
|
|
$set .= isset($data->chk_remise_sur_tg) ? ', chk_remise_sur_tg=1' : ', chk_remise_sur_tg=0';
|
|
$set .= isset($data->chk_prix_nets) ? ', chk_prix_nets=1' : ', chk_prix_nets=0';
|
|
$set .= isset($data->chk_marche_public) ? ', chk_marche_public=1' : ', chk_marche_public=0';
|
|
|
|
if ($data->taux_remise_trimestrielle == "") {
|
|
$set .= ', taux_remise_trimestrielle=0';
|
|
} else {
|
|
$set .= ', taux_remise_trimestrielle=' . $data->taux_remise_trimestrielle;
|
|
}
|
|
if ($data->taux_remise_semestrielle == "") {
|
|
$set .= ', taux_remise_semestrielle=0';
|
|
} else {
|
|
$set .= ', taux_remise_semestrielle=' . $data->taux_remise_semestrielle;
|
|
}
|
|
if ($data->taux_remise_annuelle == "") {
|
|
$set .= ', taux_remise_annuelle=0';
|
|
} else {
|
|
$set .= ', taux_remise_annuelle=' . $data->taux_remise_annuelle;
|
|
}
|
|
$set .= ', date_debut="' . d6GetDate($data->date_debut, "FM") . '"';
|
|
$set .= ', date_fin="' . d6GetDate($data->date_fin, "FM") . '"';
|
|
$set .= ', date_validite_prix="' . d6GetDate($data->date_validite_prix, "FM") . '"';
|
|
$set .= ', franco_de_port="' . nettoie_input(trim($data->franco_de_port)) . '"';
|
|
$set .= ', garantie="' . nettoie_input(trim($data->garantie)) . '"';
|
|
$set .= ', delai_de_livraison="' . nettoie_input(trim($data->delai_de_livraison)) . '"';
|
|
$set .= ', remises_commerciales="' . nettoie_input(trim($data->remises_commerciales)) . '"';
|
|
if ($data->remise_palier_1 == "") {
|
|
$set .= ', remise_palier_1=0';
|
|
} else {
|
|
$set .= ', remise_palier_1=' . $data->remise_palier_1;
|
|
}
|
|
if ($data->remise_taux_1 == "") {
|
|
$set .= ', remise_taux_1=0';
|
|
} else {
|
|
$set .= ', remise_taux_1=' . $data->remise_taux_1;
|
|
}
|
|
if ($data->remise_palier_2 == "") {
|
|
$set .= ', remise_palier_2=0';
|
|
} else {
|
|
$set .= ', remise_palier_2=' . $data->remise_palier_2;
|
|
}
|
|
if ($data->remise_taux_2 == "") {
|
|
$set .= ', remise_taux_2=0';
|
|
} else {
|
|
$set .= ', remise_taux_2=' . $data->remise_taux_2;
|
|
}
|
|
if ($data->remise_palier_3 == "") {
|
|
$set .= ', remise_palier_3=0';
|
|
} else {
|
|
$set .= ', remise_palier_3=' . $data->remise_palier_3;
|
|
}
|
|
if ($data->remise_taux_3 == "") {
|
|
$set .= ', remise_taux_3=0';
|
|
} else {
|
|
$set .= ', remise_taux_3=' . $data->remise_taux_3;
|
|
}
|
|
if ($data->remise_palier_4 == "") {
|
|
$set .= ', remise_palier_4=0';
|
|
} else {
|
|
$set .= ', remise_palier_4=' . $data->remise_palier_4;
|
|
}
|
|
if ($data->remise_taux_4 == "") {
|
|
$set .= ', remise_taux_4=0';
|
|
} else {
|
|
$set .= ', remise_taux_4=' . $data->remise_taux_4;
|
|
}
|
|
|
|
$set .= ', commentaire="' . nettoie_input(trim($data->commentaire)) . '"';
|
|
$set .= isset($data->chk_cache_commerciaux) ? ', chk_cache_commerciaux=1' : ', chk_cache_commerciaux=0';
|
|
$set .= isset($data->chk_marche_hybride) ? ', chk_marche_hybride=1' : ', chk_marche_hybride=0';
|
|
$set .= isset($data->chk_regle_seuils_marge) ? ', chk_regle_seuils_marge=1' : ', chk_regle_seuils_marge=0';
|
|
$set .= isset($data->active) ? ', active=1' : ', active=0';
|
|
|
|
if ($cid == 0) {
|
|
$set .= ', date_creat = "' . date("Y-m-d H:i:s") . '", fk_user_creat=' . $fk_user;
|
|
$sql = 'INSERT INTO marches ' . $set . ';';
|
|
} else {
|
|
$set .= ', date_modif = "' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user;
|
|
$sql = 'UPDATE marches ' . $set . ' WHERE rowid=' . $cid . ';';
|
|
}
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
|
|
$ret = array('ret' => "ok");
|
|
echo json_encode($ret);
|
|
} else {
|
|
$ret = array('ret' => "ko");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "delete_marche":
|
|
//! Supprime un marché
|
|
//! Réception de l'id du marché à supprimer
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
// SÉCURITÉ : Validation de l'ID comme entier
|
|
$cid = intval($data->cid);
|
|
if ($cid <= 0) {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
|
|
// Utilisation de requêtes préparées pour la suppression
|
|
$sql1 = 'DELETE FROM marches WHERE rowid = :id';
|
|
$db->query($sql1, ['id' => $cid]);
|
|
|
|
$sql2 = 'DELETE FROM marches_listes WHERE fk_marche = :id';
|
|
$db->query($sql2, ['id' => $cid]);
|
|
|
|
$sql3 = 'DELETE FROM produits WHERE fk_marche = :id';
|
|
$db->query($sql3, ['id' => $cid]);
|
|
|
|
eLog("Marché supprimé : ID=$cid");
|
|
$ret = array('ret' => "ok", 'msg' => 'Marché supprimé');
|
|
echo json_encode($ret);
|
|
} catch (Exception $e) {
|
|
eLog("Erreur suppression marché : " . $e->getMessage());
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
|
|
}
|
|
} else {
|
|
$ret = array('ret' => "ko", 'msg' => 'Marché non supprimé');
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "save_marches_listes":
|
|
//! Enregistre les mises à jour du tableau des listes tarifaires par marché
|
|
//! Réception du tableau des mots clés par marché en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->idListe)) {
|
|
if ($data->idListe == "1") {
|
|
foreach ($data as $key => $val) {
|
|
if (substr($key, 0, 7) == "motcle_") {
|
|
$fk_marche = trim(substr($key, 7));
|
|
$motCle = trim($val);
|
|
$motCleAchat = "";
|
|
$motCleVente = "";
|
|
foreach ($data as $keyAV => $valAV) {
|
|
if ($keyAV == "motcleachat_" . $fk_marche) {
|
|
$motCleAchat = trim($valAV);
|
|
} else {
|
|
if ($keyAV == "motclevente_" . $fk_marche) {
|
|
$motCleVente = trim($valAV);
|
|
}
|
|
}
|
|
}
|
|
|
|
$sql = 'SELECT l.rowid FROM marches_listes l WHERE l.fk_marche=' . $fk_marche . ';';
|
|
$retour = getinfos($sql, "gen");
|
|
if (count($retour) > 0) {
|
|
$sql = 'UPDATE marches_listes SET mot_cle="' . $motCle . '", terme_achat="' . $motCleAchat . '", terme_vente="' . $motCleVente . '" WHERE fk_marche=' . $fk_marche . ';';
|
|
qSQL($sql, "gen");
|
|
} else {
|
|
$sql = 'INSERT INTO marches_listes SET fk_marche=' . $fk_marche . ', mot_cle="' . $motCle . '", terme_achat="' . $motCleAchat . '", terme_vente="' . $motCleVente . '";';
|
|
qSQL($sql, "gen");
|
|
}
|
|
}
|
|
}
|
|
$ret = array('ret' => "ok", "msg" => "Enregistrement des données effectué");
|
|
echo json_encode($ret);
|
|
} else {
|
|
$ret = array('ret' => "ko", "msg" => "Erreur lors de la réception des données à enregistrer");
|
|
echo json_encode($ret);
|
|
}
|
|
} else {
|
|
$ret = array('ret' => "ko", "msg" => "Erreur lors de la réception des données à enregistrer");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "load_produits_marche":
|
|
//! Charge les produits d'un marché
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
|
|
// On récupère certaines infos du marché pour savoir si on doit appliquer des filtres
|
|
$sql = 'SELECT m.chk_remise_sur_tg FROM marches m WHERE m.rowid=' . $cid . ';';
|
|
$retour = getinfos($sql, "gen");
|
|
$chk_remise_sur_tg = $retour[0]["chk_remise_sur_tg"];
|
|
|
|
if ($cid == 999 || $chk_remise_sur_tg == 1) {
|
|
// c'est directement le TG, on ne fait rien de spécial
|
|
$sql = 'SELECT p.rowid, p.code, p.libelle, concat(p.code, " # ", p.libelle) as rech, p.groupe, p.prix_achat_net, p.prix_vente, p.prc_discount_1 ';
|
|
$sql .= 'FROM produits p WHERE p.fk_marche=' . $cid . ' AND p.active=1 ORDER BY p.code DESC;';
|
|
echo getinfos($sql, "gen", "json");
|
|
} else {
|
|
// On regarde le terme_achat du marché
|
|
$sql = 'SELECT l.terme_achat FROM marches_listes l WHERE l.fk_marche=' . $cid . ';';
|
|
$retour = getinfos($sql, "gen");
|
|
$terme_achat = $retour[0]["terme_achat"];
|
|
|
|
if ($terme_achat == "Purchasing") {
|
|
// On doit alors récupérer leur prix d'achat dans le marché TG
|
|
$sql = 'SELECT p.rowid, p.code, p.libelle, concat(p.code, " # ", p.libelle) as rech, p.groupe, p.prix_achat_net, p.prix_vente, p.prc_discount_1 ';
|
|
$sql .= 'FROM produits p WHERE p.fk_marche=' . $cid . ' AND p.active=1 ORDER BY p.code DESC;';
|
|
$retour = getinfos($sql, "gen");
|
|
if (count($retour) > 0) {
|
|
foreach ($retour as &$prod) {
|
|
$sql = 'SELECT p.prix_achat_net, p.prc_discount_1 FROM produits p WHERE p.fk_marche=999 AND p.code="' . $prod["code"] . '";';
|
|
$retour2 = getinfos($sql, "gen");
|
|
if (count($retour2) == 1) {
|
|
$prod["prix_achat_net"] = $retour2[0]["prix_achat_net"];
|
|
$prod["prc_discount_1"] = $retour2[0]["prc_discount_1"];
|
|
}
|
|
}
|
|
}
|
|
echo json_encode($retour);
|
|
} else {
|
|
$sql = 'SELECT p.rowid, p.code, p.libelle, concat(p.code, " # ", p.libelle) as rech, p.groupe, p.prix_achat_net, p.prix_vente, p.prc_discount_1 ';
|
|
$sql .= 'FROM produits p WHERE p.fk_marche=' . $cid . ' AND p.active=1 ORDER BY p.code DESC;';
|
|
echo getinfos($sql, "gen", "json");
|
|
}
|
|
|
|
}
|
|
} else {
|
|
$ret = array("ret" => "ko", "msg" => "Erreur lors de l'envoi du marché à charger");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "load_marches_listes":
|
|
//! Charge la liste des mots clés des marchés à retrouver dans les fichiers d'importation
|
|
$sql = 'SELECT l.* FROM marches_listes l;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "load_user":
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
$sql = 'SELECT u.* FROM users u WHERE u.rowid=' . $cid . ';';
|
|
echo getinfos($sql, "gen", "json");
|
|
} else {
|
|
$ret = array("ret" => "ko", "msg" => "Erreur lors de la récupération des infos de l'utilisateur");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "save_user":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->rowid)) {
|
|
$cid = nettoie_input($data->rowid);
|
|
$act = nettoie_input($data->act);
|
|
|
|
$set = 'SET libelle="' . nettoie_input(trim($data->libelle)) . '"';
|
|
$set .= ', prenom="' . nettoie_input(trim($data->prenom)) . '"';
|
|
$set .= ', mobile="' . nettoie_input(trim($data->mobile)) . '"';
|
|
$set .= ', email="' . nettoie_input(trim($data->email)) . '"';
|
|
$set .= ', username="' . nettoie_input(trim($data->username)) . '"';
|
|
$set .= ', fk_role=' . nettoie_input(trim($data->fk_role));
|
|
$set .= ', fk_region=' . nettoie_input(trim($data->fk_region));
|
|
if (isset($data->fk_parent)) {
|
|
$set .= ', fk_parent=' . nettoie_input(trim($data->fk_parent));
|
|
} else {
|
|
$set .= ', fk_parent=0';
|
|
}
|
|
$set .= ', lst_depts="' . nettoie_input(trim($data->lst_depts)) . '"';
|
|
$set .= isset($data->chk_grands_comptes) ? ', chk_grands_comptes=1' : ', chk_grands_comptes=0';
|
|
$set .= isset($data->active) ? ', active=1' : ', active=0';
|
|
|
|
if ($cid == 0) {
|
|
// on lui crée un mot de passe par défaut : initiale prénom en majuscule + initiale nom Maj + 3 caractères suivants du nom en minuscules + . + mois + année
|
|
// On supprime les espaces dans le nom de l'utilisateur et on ne garde que les 3 premiers caractères
|
|
$libUser = str_replace(" ", "", nettoie_input(trim($data->libelle)));
|
|
$pwd = strtoupper(substr(nettoie_input(trim($data->prenom)), 0, 1)) . strtoupper(substr($libUser, 0, 1)) . strtolower(substr($libUser, 1, 3)) . "." . date("mY");
|
|
eLog($pwd);
|
|
$set .= ', userpswd="' . hashPsswd($pwd) . '"';
|
|
|
|
$set .= ', date_creat = "' . date("Y-m-d H:i:s") . '", fk_user_creat=' . $fk_user;
|
|
$sql = 'INSERT INTO users ' . $set . ';';
|
|
} else {
|
|
$set .= ', date_modif = "' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user;
|
|
$sql = 'UPDATE users ' . $set . ' WHERE rowid=' . $cid . ';';
|
|
}
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
|
|
$ret = array('ret' => "ok");
|
|
echo json_encode($ret);
|
|
} else {
|
|
$ret = array('ret' => "ko");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "delete_user":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
// SÉCURITÉ : Validation de l'ID comme entier
|
|
$cid = intval($data->cid);
|
|
if ($cid <= 0) {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
// TODO : Supprimer les devis créés par cet utilisateur
|
|
|
|
// Utilisation de la fonction sécurisée deleteById
|
|
$result = $db->deleteById('users', $cid);
|
|
|
|
if ($result) {
|
|
eLog("Utilisateur supprimé : ID=$cid");
|
|
echo json_encode(array('ret' => "ok"));
|
|
} else {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'Utilisateur non trouvé'));
|
|
}
|
|
} catch (Exception $e) {
|
|
eLog("Erreur suppression utilisateur : " . $e->getMessage());
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
|
|
}
|
|
} else {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'ID manquant'));
|
|
}
|
|
break;
|
|
|
|
case "maintenance":
|
|
if ($Conf->_devIp) {
|
|
// Mise à jour des mots de passe Utilisateurs
|
|
$sql = 'SELECT u.rowid, u.prenom, u.libelle FROM users u WHERE u.active=1 AND u.rowid=39;';
|
|
$users = getinfos($sql, "gen");
|
|
foreach ($users as $user) {
|
|
$uId = $user["rowid"];
|
|
$libUser = str_replace(" ", "", nettoie_input(trim($user["libelle"])));
|
|
$pwd = strtoupper(substr(nettoie_input(trim($user["prenom"])), 0, 1)) . strtoupper(substr($libUser, 0, 1)) . strtolower(substr($libUser, 1, 3)) . "." . date("mY");
|
|
eLog($pwd);
|
|
$sql = 'UPDATE users SET userpswd="' . hashPsswd($pwd) . '" WHERE rowid=' . $uId . ';';
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "load_roles":
|
|
$sql = 'SELECT xro.rowid, xro.libelle FROM x_roles xro WHERE xro.active=1 ORDER BY xro.rowid;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "load_regions":
|
|
$sql = 'SELECT xre.rowid, xre.libelle FROM x_regions xre WHERE xre.active=1 ORDER BY xre.rowid;';
|
|
echo getinfos($sql, "gen", "json");
|
|
break;
|
|
|
|
case "export_sap_devis":
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
eLog("export_sap_devis: ");
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
$sql = 'SELECT d.* FROM devis d WHERE d.rowid=' . $cid . ';';
|
|
$dev = getinfos($sql, "gen");
|
|
$devis = $dev[0];
|
|
eLog("export_sap_devis: " . $cid . " & " . $devis["fk_client"]);
|
|
|
|
$filename = "devis_" . $cid . "_" . date('Y_m_d_hi') . ".csv";
|
|
$fields = array("Code", "Etablissement", "Adresse 1", "Adresse 2");
|
|
|
|
// SÉCURITÉ : Utilisation de requête préparée pour l'ID client
|
|
try {
|
|
$db = Database::getInstance();
|
|
$sql = 'SELECT c.code, c.libelle, c.adresse1, c.adresse2 FROM clients c WHERE c.rowid = :id';
|
|
$client = $db->fetchOne($sql, [':id' => intval($devis["fk_client"])]);
|
|
if (!$client) {
|
|
$client = ['code' => '', 'libelle' => '', 'adresse1' => '', 'adresse2' => ''];
|
|
}
|
|
} catch (Exception $e) {
|
|
error_log("Erreur export_sap_devis : " . $e->getMessage());
|
|
$client = ['code' => '', 'libelle' => '', 'adresse1' => '', 'adresse2' => ''];
|
|
}
|
|
|
|
$excelData = implode("\t", array_values($fields)) . "\n";
|
|
|
|
eLog($excelData);
|
|
|
|
array_walk($client, 'filterData');
|
|
$excelData .= implode("\t", array_values($client)) . "\n";
|
|
|
|
$sql = 'SELECT p.code, p.libelle, p.prix_achat_net, p.prix_vente, dp.qte, dp.remise, dp.totalht FROM devis_produits dp LEFT JOIN produits p ON dp.fk_produit=p.rowid WHERE dp.fk_devis=' . $cid . ';';
|
|
eLog($sql);
|
|
$data = getinfos($sql, "gen");
|
|
|
|
// une ligne vierge de séparation
|
|
$excelData .= "\n";
|
|
$fields = array("Code", "Désignation", "Prix Achat", "Prix Vente", "Quantité", "Remise", "Total HT");
|
|
$excelData .= implode("\t", array_values($fields)) . "\n";
|
|
|
|
foreach ($data as $row) {
|
|
array_walk($row, 'filterData');
|
|
$excelData .= implode("\t", $row) . "\n";
|
|
}
|
|
eLog($excelData);
|
|
header("Content-Type: application/vnd.ms-excel; charset=UTF-16LE");
|
|
header("Content-Disposition: attachment; filename=$filename");
|
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
|
echo $excelData;
|
|
exit;
|
|
}
|
|
break;
|
|
|
|
case "load_info":
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
$sql = 'SELECT i.* FROM infos i WHERE i.rowid=' . $cid . ';';
|
|
echo getinfos($sql, "gen", "json");
|
|
}
|
|
break;
|
|
|
|
case "save_info":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
$cid = nettoie_input($data->cid);
|
|
|
|
$set = 'SET date_infos="' . nettoie_input($data->cdate) . '" ';
|
|
$set .= ', titre_infos="' . nettoie_input(trim($data->ctitre)) . '" ';
|
|
$set .= ', text_infos="' . nettoie_input(trim($data->ctexte)) . '" ';
|
|
if (isset($data->cpublie)) {
|
|
if ($data->cpublie == false || $data->cpublie == 0) {
|
|
$set .= ', chk_publie=0';
|
|
} else {
|
|
$set .= ', chk_publie=1';
|
|
}
|
|
} else {
|
|
$set .= ', chk_publie=0';
|
|
}
|
|
|
|
if ($cid == 0) {
|
|
$set .= ', date_creat = "' . date("Y-m-d H:i:s") . '", fk_user_creat=' . $fk_user;
|
|
$sql = 'INSERT INTO infos ' . $set . ';';
|
|
} else {
|
|
$set .= ', date_modif = "' . date("Y-m-d H:i:s") . '", fk_user_modif=' . $fk_user;
|
|
$sql = 'UPDATE infos ' . $set . ' WHERE rowid=' . $cid . ';';
|
|
}
|
|
eLog($sql);
|
|
qSQL($sql, "gen");
|
|
$ret = array('ret' => "ok");
|
|
echo json_encode($ret);
|
|
} else {
|
|
$ret = array('ret' => "ko");
|
|
echo json_encode($ret);
|
|
}
|
|
break;
|
|
|
|
case "supp_info":
|
|
//! Réception et lecture de la demande en json
|
|
$data = json_decode(file_get_contents("php://input"));
|
|
if (isset($data->cid)) {
|
|
// SÉCURITÉ : Validation de l'ID comme entier
|
|
$cid = intval($data->cid);
|
|
if ($cid <= 0) {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'ID invalide'));
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$db = Database::getInstance();
|
|
$sql = 'DELETE FROM infos WHERE rowid = :id';
|
|
$stmt = $db->query($sql, ['id' => $cid]);
|
|
$result = $stmt->rowCount() > 0;
|
|
|
|
if ($result) {
|
|
eLog("Info supprimée : ID=$cid");
|
|
echo json_encode(array('ret' => "ok"));
|
|
} else {
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'Info non trouvée'));
|
|
}
|
|
} catch (Exception $e) {
|
|
eLog("Erreur suppression info : " . $e->getMessage());
|
|
echo json_encode(array('ret' => "ko", 'msg' => 'Erreur lors de la suppression'));
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
exit();
|