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

1
.gitignore vendored
View File

@@ -41,3 +41,4 @@ sessions/
# Fichiers système
Thumbs.db*.swp
.aider*

View File

@@ -10,7 +10,7 @@ class Conf {
public $_appname = "cleo";
public $_appscript = "login";
public $_appversion = "2.0.3";
public $_appversion = "2.0.4";
public $_appenv;
public $_apptitle = "CLEO - Gestion de devis";

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

View File

@@ -195,12 +195,90 @@ DB_PASSWORD=<PROD_PASSWORD> # À sécuriser
- [ ] Scripts de backup automatisés à mettre en place
- [ ] Réplication master-slave pour haute disponibilité (optionnel)
## ⚠️ CRITIQUE - Risque de collision de codes clients (EN ATTENTE CLIENT)
### Problématique identifiée
**Date**: 26 novembre 2025
**Statut**: 🔴 EN ATTENTE RÉPONSE CLIENT
#### Situation actuelle
Lorsqu'un commercial crée un nouveau client manuellement dans CLEO (client non présent dans SAP), le système génère automatiquement un code via :
```php
$newCode = MAX(code) + 1; // cjxdevis.php ligne 1326
```
#### Risque de collision
**Scénario catastrophe** :
1. Commercial crée un client manuel → code auto = `12345`
2. Commercial ajoute des contacts, fait des devis
3. **Import SAP suivant** : un nouveau client SAP arrive avec le code `12345`
4. L'import trouve le client existant (même code) et **écrase toutes les données** du client manuel
5. Les contacts du client manuel deviennent incohérents (pointent vers le mauvais client SAP)
6. Les devis du client manuel sont rattachés au mauvais client SAP
#### Question posée au client
**"Que se passe-t-il lorsqu'un devis avec un nouveau client (code = MAX+1) est intégré dans SAP ?"**
- Le client manuel reçoit-il un vrai code SAP ?
- Le code est-il synchronisé dans CLEO après intégration ?
- Existe-t-il un processus de réconciliation ?
### Solutions techniques envisagées
#### Option A : Plage réservée pour clients manuels
```php
// Codes 9000000+ réservés aux créations manuelles
$newCode = 9000000 + $compteur;
```
**Avantages** : Simple, pas de collision possible
**Inconvénients** : Nécessite coordination avec SAP
#### Option B : Codes négatifs pour clients manuels
```php
// Codes négatifs = clients manuels non SAP
$newCode = -1 * (MAX(ABS(code)) + 1);
```
**Avantages** : Distinction claire SAP/Manuel
**Inconvénients** : Peut poser problème avec certains systèmes
#### Option C : Flag `chk_manual` + protection
```sql
ALTER TABLE clients ADD COLUMN chk_manual TINYINT DEFAULT 0;
```
- `chk_manual = 1` → Client créé manuellement, jamais écrasé par import SAP
- Lors de l'import SAP, ignorer les clients avec `chk_manual = 1`
- Processus manuel de réconciliation si le client est créé dans SAP
**Avantages** : Protection garantie, traçabilité
**Inconvénients** : Nécessite gestion manuelle de la réconciliation
#### Option D : Code temporaire + synchronisation
- Client manuel créé avec code `TEMP_XXXXX`
- Lors de l'intégration SAP, récupération du vrai code SAP
- Mise à jour du code client + tous les contacts/devis associés
**Avantages** : Cohérence totale avec SAP
**Inconvénients** : Complexe, nécessite API ou process de sync
### Actions en attente
- [ ] **Réponse client** sur le processus actuel d'intégration SAP
- [ ] Choix de la solution technique selon la réponse
- [ ] Implémentation de la solution retenue
- [ ] Tests de non-régression sur imports SAP
- [ ] Documentation du processus de gestion des clients manuels
### Impact sur le code existant
**Fichiers concernés** :
- `controllers/cjxdevis.php` : fonction `save_new_client` (ligne 1308)
- `controllers/cjximport.php` : fonction `upload_clients` (ligne 112)
- Documentation utilisateur à mettre à jour
---
## Modification Contacts Clients - Migration vers clients.code
### Contexte
La relation entre `clients_contacts` et `clients` utilise actuellement `clients.rowid` comme clé étrangère.
Cela pose problème lors des imports SAP qui peuvent écraser ou modifier les `rowid`.
Il faut migrer vers `clients.code` (identifiant SAP immuable) pour garantir l'intégrité des relations.
La relation entre `clients_contacts` et `clients` utilise `clients.code` comme clé de référence.
Le système a été conçu pour utiliser le `code` SAP (clé métier immuable) plutôt que le `rowid` (clé technique auto-incrémentée).
### Plan de correction

View File

@@ -1,9 +1,9 @@
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.19 Distrib 10.11.9-MariaDB, for debian-linux-gnu (x86_64)
-- MariaDB dump 10.19-11.8.3-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: uof_linet
-- Host: localhost Database: cleo
-- ------------------------------------------------------
-- Server version 10.11.9-MariaDB-deb12
-- Server version 11.4.8-MariaDB-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -14,7 +14,7 @@
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
/*M!100616 SET @OLD_NOTE_VERBOSITY=@@NOTE_VERBOSITY, NOTE_VERBOSITY=0 */;
--
-- Table structure for table `clients`
@@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `clients`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `clients` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`code` int(11) NOT NULL,
@@ -51,9 +51,38 @@ CREATE TABLE `clients` (
UNIQUE KEY `code_UNIQUE` (`code`),
KEY `libelle` (`libelle`),
KEY `cp` (`cp`)
) ENGINE=InnoDB AUTO_INCREMENT=5307 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
) ENGINE=InnoDB AUTO_INCREMENT=5309 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `clients_contacts`
--
DROP TABLE IF EXISTS `clients_contacts`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `clients_contacts` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_client` int(11) NOT NULL,
`nom` varchar(50) DEFAULT NULL,
`prenom` varchar(50) DEFAULT NULL,
`fonction` varchar(50) DEFAULT NULL,
`telephone` varchar(20) DEFAULT NULL,
`mobile` varchar(20) DEFAULT NULL,
`email` varchar(75) DEFAULT NULL,
`principal` tinyint(1) DEFAULT 0 COMMENT 'Contact principal du client',
`active` tinyint(1) DEFAULT 1,
`date_creat` datetime DEFAULT NULL,
`fk_user_creat` int(11) DEFAULT NULL,
`date_modif` datetime DEFAULT NULL,
`fk_user_modif` int(11) DEFAULT NULL,
PRIMARY KEY (`rowid`),
UNIQUE KEY `rowid_UNIQUE` (`rowid`),
KEY `fk_client` (`fk_client`),
KEY `principal` (`fk_client`,`principal`),
KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=8199 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Contacts multiples par client' `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `clients_sites`
@@ -61,7 +90,7 @@ CREATE TABLE `clients` (
DROP TABLE IF EXISTS `clients_sites`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `clients_sites` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_client` int(11) NOT NULL,
@@ -77,22 +106,13 @@ CREATE TABLE `clients_sites` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `clients_sites`
--
LOCK TABLES `clients_sites` WRITE;
/*!40000 ALTER TABLE `clients_sites` DISABLE KEYS */;
/*!40000 ALTER TABLE `clients_sites` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `commerciaux`
--
DROP TABLE IF EXISTS `commerciaux`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `commerciaux` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_entite` int(11) DEFAULT 0,
@@ -133,14 +153,13 @@ CREATE TABLE `commerciaux` (
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `commerciaux_entites`
--
DROP TABLE IF EXISTS `commerciaux_entites`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `commerciaux_entites` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT NULL,
@@ -157,26 +176,13 @@ CREATE TABLE `commerciaux_entites` (
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `commerciaux_entites`
--
LOCK TABLES `commerciaux_entites` WRITE;
/*!40000 ALTER TABLE `commerciaux_entites` DISABLE KEYS */;
INSERT INTO `commerciaux_entites` VALUES
(1,'LINET',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1),
(2,'WISSNER-BOSSERHOFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1),
(3,'LINET & WI-BO',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1);
/*!40000 ALTER TABLE `commerciaux_entites` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `commerciaux_params`
--
DROP TABLE IF EXISTS `commerciaux_params`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `commerciaux_params` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_commercial` int(11) DEFAULT NULL,
@@ -269,14 +275,13 @@ CREATE TABLE `commerciaux_params` (
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `devis`
--
DROP TABLE IF EXISTS `devis`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `devis` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_user` int(11) NOT NULL DEFAULT 0,
@@ -285,6 +290,7 @@ CREATE TABLE `devis` (
`date_remise` date DEFAULT NULL,
`num_opportunite` varchar(8) NOT NULL DEFAULT '',
`fk_client` int(11) NOT NULL DEFAULT 0,
`fk_contact` int(11) DEFAULT NULL,
`fk_marche` int(11) NOT NULL DEFAULT 0,
`fk_statut_devis` int(11) NOT NULL DEFAULT 0,
`chk_clients_secteur` tinyint(1) NOT NULL DEFAULT 1,
@@ -327,18 +333,18 @@ CREATE TABLE `devis` (
KEY `fk_client` (`fk_client`),
KEY `fk_statut_devis` (`fk_statut_devis`),
KEY `date_demande` (`date_demande`),
KEY `dossier` (`fk_user`,`dossier`)
) ENGINE=InnoDB AUTO_INCREMENT=4611 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
KEY `dossier` (`fk_user`,`dossier`),
KEY `fk_contact` (`fk_contact`)
) ENGINE=InnoDB AUTO_INCREMENT=4624 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `devis_histo`
--
DROP TABLE IF EXISTS `devis_histo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `devis_histo` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_devis` int(11) DEFAULT NULL,
@@ -350,7 +356,7 @@ CREATE TABLE `devis_histo` (
`fk_statut_devis` int(11) DEFAULT NULL,
PRIMARY KEY (`rowid`),
KEY `devis_histo_fk_devis_index` (`fk_devis`)
) ENGINE=InnoDB AUTO_INCREMENT=22331 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
) ENGINE=InnoDB AUTO_INCREMENT=22388 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -359,7 +365,7 @@ CREATE TABLE `devis_histo` (
DROP TABLE IF EXISTS `devis_produits`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `devis_produits` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_devis` int(11) NOT NULL,
@@ -392,17 +398,16 @@ CREATE TABLE `devis_produits` (
PRIMARY KEY (`rowid`),
KEY `devis_produits__devis` (`fk_devis`),
KEY `devis_produits__produit` (`fk_produit`)
) ENGINE=InnoDB AUTO_INCREMENT=29277 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
) ENGINE=InnoDB AUTO_INCREMENT=29314 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `devis_speciaux`
--
DROP TABLE IF EXISTS `devis_speciaux`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `devis_speciaux` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_devis` int(11) NOT NULL DEFAULT 0,
@@ -461,14 +466,13 @@ CREATE TABLE `devis_speciaux` (
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `entites`
--
DROP TABLE IF EXISTS `entites`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `entites` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT '',
@@ -513,14 +517,13 @@ CREATE TABLE `entites` (
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `import_ventes`
--
DROP TABLE IF EXISTS `import_ventes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `import_ventes` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`source` varchar(15) DEFAULT '',
@@ -570,7 +573,7 @@ CREATE TABLE `import_ventes` (
DROP TABLE IF EXISTS `infos`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `infos` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`date_infos` date DEFAULT NULL,
@@ -586,14 +589,13 @@ CREATE TABLE `infos` (
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `marches`
--
DROP TABLE IF EXISTS `marches`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `marches` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`numero` varchar(20) NOT NULL DEFAULT '',
@@ -642,7 +644,7 @@ CREATE TABLE `marches` (
DROP TABLE IF EXISTS `marches_listes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `marches_listes` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_marche` int(11) DEFAULT NULL,
@@ -660,7 +662,7 @@ CREATE TABLE `marches_listes` (
DROP TABLE IF EXISTS `marches_produits`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `marches_produits` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_marche` int(11) DEFAULT 0,
@@ -702,7 +704,7 @@ CREATE TABLE `marches_produits` (
DROP TABLE IF EXISTS `marches_versions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `marches_versions` (
`rowid` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Id',
`libelle` varchar(75) DEFAULT NULL COMMENT 'Libellé',
@@ -713,24 +715,13 @@ CREATE TABLE `marches_versions` (
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Version des marchés' `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `marches_versions`
--
LOCK TABLES `marches_versions` WRITE;
/*!40000 ALTER TABLE `marches_versions` DISABLE KEYS */;
INSERT INTO `marches_versions` VALUES
(1,'Version Avril 2022','2022-04-01','0000-00-00',1);
/*!40000 ALTER TABLE `marches_versions` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `medias`
--
DROP TABLE IF EXISTS `medias`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `medias` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`dir0` varchar(150) DEFAULT NULL,
@@ -746,7 +737,7 @@ CREATE TABLE `medias` (
PRIMARY KEY (`rowid`),
UNIQUE KEY `rowid_UNIQUE` (`rowid`),
KEY `support` (`support`,`support_rowid`)
) ENGINE=InnoDB AUTO_INCREMENT=3866 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
) ENGINE=InnoDB AUTO_INCREMENT=3878 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -755,7 +746,7 @@ CREATE TABLE `medias` (
DROP TABLE IF EXISTS `notifications`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `notifications` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`dateheure` datetime DEFAULT NULL,
@@ -775,7 +766,7 @@ CREATE TABLE `notifications` (
DROP TABLE IF EXISTS `produits`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `produits` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_marche` int(11) NOT NULL DEFAULT 0,
@@ -821,7 +812,7 @@ CREATE TABLE `produits` (
DROP TABLE IF EXISTS `produits_familles`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `produits_familles` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`groupe` varchar(30) NOT NULL,
@@ -841,7 +832,7 @@ CREATE TABLE `produits_familles` (
DROP TABLE IF EXISTS `regions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `regions` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(75) DEFAULT NULL,
@@ -851,22 +842,13 @@ CREATE TABLE `regions` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `regions`
--
LOCK TABLES `regions` WRITE;
/*!40000 ALTER TABLE `regions` DISABLE KEYS */;
/*!40000 ALTER TABLE `regions` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `simul`
--
DROP TABLE IF EXISTS `simul`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `simul` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_import_vente` int(11) DEFAULT NULL,
@@ -885,14 +867,13 @@ CREATE TABLE `simul` (
) ENGINE=InnoDB AUTO_INCREMENT=1057 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
`rowid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fk_entite` int(11) DEFAULT NULL,
@@ -940,13 +921,64 @@ CREATE TABLE `users` (
) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `users_entites`
--
DROP TABLE IF EXISTS `users_entites`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `users_entites` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT '',
`http_host` varchar(150) DEFAULT '',
`adresse1` varchar(45) DEFAULT '',
`adresse2` varchar(45) DEFAULT '',
`cp` varchar(5) DEFAULT '',
`ville` varchar(45) DEFAULT '',
`type_entite` varchar(5) DEFAULT 'form',
`tva_intra` varchar(15) DEFAULT '',
`rcs` varchar(45) DEFAULT '',
`siret` varchar(17) DEFAULT NULL,
`ape` varchar(5) DEFAULT '',
`num_opca` varchar(15) DEFAULT '',
`logo` varchar(45) DEFAULT '',
`tel1` varchar(20) DEFAULT '',
`tel2` varchar(20) DEFAULT '',
`couleur` varchar(7) DEFAULT '#FFFAF0',
`prefecture` varchar(45) DEFAULT 'Bretagne',
`fk_titre_gerant` int(11) DEFAULT 1,
`gerant_prenom` varchar(45) DEFAULT '',
`gerant_nom` varchar(45) DEFAULT '',
`email` varchar(45) DEFAULT '',
`site_url` varchar(45) DEFAULT '',
`gerant_signature` varchar(45) DEFAULT '',
`tampon_signature` varchar(45) DEFAULT '',
`rib_banque` varchar(5) DEFAULT '',
`rib_guichet` varchar(5) DEFAULT '',
`rib_compte` varchar(11) DEFAULT '',
`rib_cle` varchar(2) DEFAULT '',
`rib_domiciliation` varchar(45) DEFAULT '',
`iban` varchar(33) DEFAULT '',
`bic` varchar(15) DEFAULT '',
`demo` tinyint(1) DEFAULT 0,
`genbase` varchar(45) DEFAULT '0',
`groupebase` varchar(45) DEFAULT '0',
`table_users_gen` varchar(50) DEFAULT '',
`appname` varchar(45) DEFAULT '',
`raz_num_devis` tinyint(1) DEFAULT 0,
`active` tinyint(1) DEFAULT 1,
PRIMARY KEY (`rowid`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `ventes`
--
DROP TABLE IF EXISTS `ventes`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `ventes` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`source` varchar(45) DEFAULT NULL,
@@ -977,22 +1009,13 @@ CREATE TABLE `ventes` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `ventes`
--
LOCK TABLES `ventes` WRITE;
/*!40000 ALTER TABLE `ventes` DISABLE KEYS */;
/*!40000 ALTER TABLE `ventes` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `x_clients_types`
--
DROP TABLE IF EXISTS `x_clients_types`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_clients_types` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`code` char(3) DEFAULT NULL,
@@ -1004,28 +1027,13 @@ CREATE TABLE `x_clients_types` (
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `x_clients_types`
--
LOCK TABLES `x_clients_types` WRITE;
/*!40000 ALTER TABLE `x_clients_types` DISABLE KEYS */;
INSERT INTO `x_clients_types` VALUES
(1,'PUB','Public',1),
(2,'PRA','Privé Associatif',1),
(3,'PRD','Privé Distributeur',1),
(4,'PRC','Privé Commercial',1),
(5,'ESP','ESPIC',1);
/*!40000 ALTER TABLE `x_clients_types` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `x_familles`
--
DROP TABLE IF EXISTS `x_familles`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_familles` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(20) NOT NULL DEFAULT '',
@@ -1037,34 +1045,13 @@ CREATE TABLE `x_familles` (
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `x_familles`
--
LOCK TABLES `x_familles` WRITE;
/*!40000 ALTER TABLE `x_familles` DISABLE KEYS */;
INSERT INTO `x_familles` VALUES
(3,'Lits SBU1',1,1),
(4,'Lits SBU2',2,1),
(5,'Accessoires SBU1',3,1),
(6,'Accessoires SBU2',4,1),
(7,'Services',5,1),
(8,'Matelas mousse',6,1),
(9,'Matelas à air',7,1),
(10,'Mobilier',8,1),
(11,'Assises',9,1),
(12,'Autres',11,1),
(13,'Domalys',10,1);
/*!40000 ALTER TABLE `x_familles` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `x_regions`
--
DROP TABLE IF EXISTS `x_regions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_regions` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_entite` int(11) DEFAULT 0,
@@ -1075,39 +1062,13 @@ CREATE TABLE `x_regions` (
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `x_regions`
--
LOCK TABLES `x_regions` WRITE;
/*!40000 ALTER TABLE `x_regions` DISABLE KEYS */;
INSERT INTO `x_regions` VALUES
(1,1,'SUD-OUEST',1),
(2,1,'RHONE-ALPES / AUVERGNE',1),
(3,1,'PACA',1),
(4,1,'EST',1),
(5,1,'NORD',1),
(6,1,'GRAND-OUEST',1),
(7,1,'IDF',1),
(8,1,'DOM-TOM',1),
(9,2,'WB-NORD',1),
(13,2,'WB-SUD OUEST',1),
(14,2,'WB-EST',1),
(15,2,'WB-ILE DE FRANCE',1),
(16,2,'WB-SUD-EST',1),
(17,2,'WB-CENTRE-EST ET DOM',1),
(18,1,'DIRECTION',1),
(19,2,'WB-NORD OUEST',1);
/*!40000 ALTER TABLE `x_regions` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `x_roles`
--
DROP TABLE IF EXISTS `x_roles`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_roles` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(45) DEFAULT '',
@@ -1118,30 +1079,13 @@ CREATE TABLE `x_roles` (
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Les différents rôles des utilisateurs' `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `x_roles`
--
LOCK TABLES `x_roles` WRITE;
/*!40000 ALTER TABLE `x_roles` DISABLE KEYS */;
INSERT INTO `x_roles` VALUES
(1,'Direction Commerciale','DC',1),
(2,'Direction des Ventes','DV',1),
(3,'Commercial(e)','RR',1),
(4,'Clinicien(ne)','CL',1),
(5,'Direction Grands Comptes','GC',1),
(20,'Administration des ventes','ADV',1),
(90,'Administrateur','ADM',1);
/*!40000 ALTER TABLE `x_roles` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `x_statuts_devis`
--
DROP TABLE IF EXISTS `x_statuts_devis`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `x_statuts_devis` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(30) DEFAULT NULL,
@@ -1152,22 +1096,47 @@ CREATE TABLE `x_statuts_devis` (
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `x_statuts_devis`
-- Table structure for table `y_pages`
--
LOCK TABLES `x_statuts_devis` WRITE;
/*!40000 ALTER TABLE `x_statuts_devis` DISABLE KEYS */;
INSERT INTO `x_statuts_devis` VALUES
(1,'En cours de création',1),
(2,'En cours de validation DIR-CO',1),
(3,'En cours de validation DV/DGC',1),
(4,'A traiter sur SAP',1),
(6,'A vérifier par le RR',1),
(7,'A envoyer au client',1),
(10,'Envoyé au client',0),
(20,'Archivé',1);
/*!40000 ALTER TABLE `x_statuts_devis` ENABLE KEYS */;
UNLOCK TABLES;
DROP TABLE IF EXISTS `y_pages`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `y_pages` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`fk_parent` int(11) DEFAULT 0,
`link` varchar(75) DEFAULT NULL,
`libelle` varchar(45) DEFAULT NULL,
`titre` varchar(75) DEFAULT NULL,
`tooltip` varchar(45) DEFAULT NULL,
`description` varchar(200) DEFAULT NULL,
`keywords` varchar(200) DEFAULT NULL,
`script` varchar(45) DEFAULT NULL,
`enmaintenance` tinyint(1) DEFAULT 0 COMMENT '0 libre d''accès, 1 en maintenance mais accès aux données, 2 en maintenance sans accès aux données',
`admin` tinyint(1) DEFAULT 0,
`mail` tinyint(1) DEFAULT 0,
`admtools` tinyint(1) DEFAULT 0,
`magazine` tinyint(1) DEFAULT 0,
`files` tinyint(1) DEFAULT 0,
`editor` tinyint(1) DEFAULT 0,
`autocomplete` tinyint(1) DEFAULT 0,
`print` tinyint(1) DEFAULT 0,
`form` tinyint(1) DEFAULT 0,
`sidebar` tinyint(1) DEFAULT 0,
`chart` tinyint(1) DEFAULT 0,
`agenda` tinyint(1) DEFAULT 0,
`scheduler` tinyint(1) DEFAULT 0,
`osm` tinyint(1) DEFAULT 0,
`layout` varchar(45) DEFAULT 'default.php',
`in_menu` tinyint(1) DEFAULT 1,
`ordre_menu` int(11) DEFAULT 0,
`active` tinyint(1) DEFAULT 1,
PRIMARY KEY (`rowid`),
UNIQUE KEY `rowid_UNIQUE` (`rowid`),
KEY `script` (`script`),
KEY `admin` (`admin`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `z_history`
@@ -1175,7 +1144,7 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `z_history`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `z_history` (
`fk_user` int(11) NOT NULL,
`libelle` varchar(20) NOT NULL DEFAULT 'tiers',
@@ -1185,22 +1154,13 @@ CREATE TABLE `z_history` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `z_history`
--
LOCK TABLES `z_history` WRITE;
/*!40000 ALTER TABLE `z_history` DISABLE KEYS */;
/*!40000 ALTER TABLE `z_history` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `z_logs`
--
DROP TABLE IF EXISTS `z_logs`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `z_logs` (
`date` datetime NOT NULL,
`ip` varchar(15) NOT NULL,
@@ -1220,7 +1180,7 @@ CREATE TABLE `z_logs` (
DROP TABLE IF EXISTS `z_sessions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `z_sessions` (
`sid` text NOT NULL,
`fk_user` int(11) NOT NULL,
@@ -1238,7 +1198,7 @@ CREATE TABLE `z_sessions` (
DROP TABLE IF EXISTS `z_stats`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `z_stats` (
`rowid` int(11) NOT NULL AUTO_INCREMENT,
`libelle` varchar(75) DEFAULT NULL,
@@ -1253,6 +1213,10 @@ CREATE TABLE `z_stats` (
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `PAGE_COMPRESSED`='ON';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping routines for database 'cleo'
--
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
@@ -1260,6 +1224,6 @@ CREATE TABLE `z_stats` (
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*M!100616 SET NOTE_VERBOSITY=@OLD_NOTE_VERBOSITY */;
-- Dump completed on 2025-09-11 14:44:41
-- Dump completed on 2025-12-02 11:57:09

View File

@@ -1,8 +1,7 @@
<?php
global $Route;
function cleanData(&$str)
{
function cleanData(&$str) {
// Fonction de nettoyage des données pour l'export Excel
if ($str == 't') $str = 'TRUE';
if ($str == 'f') $str = 'FALSE';
@@ -13,8 +12,7 @@ function cleanData(&$str)
$str = mb_convert_encoding($str, 'UTF-16LE', 'UTF-8');
}
function filterData(&$str)
{
function filterData(&$str) {
$str = preg_replace("/\t/", "\\t", $str);
$str = preg_replace("/\r?\n/", "\\n", $str);
if ($str == 't') $str = 'TRUE';
@@ -95,7 +93,6 @@ switch ($Route->_action) {
$excelData .= implode("\t", array_values($fields)) . "\n";
array_walk($contact, 'filterData');
$excelData .= implode("\t", array_values($contact)) . "\n";
} else {
// Client existant : données depuis la table clients
$sql = 'SELECT c.code, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.cp, c.ville FROM clients c WHERE c.rowid = :client_id';
@@ -112,7 +109,7 @@ switch ($Route->_action) {
$contact = $db->fetchOne($sql, [':contact_id' => $fkContactSafe]);
} else {
// Fallback : contact principal du client
$sql = 'SELECT cc.nom, cc.prenom, cc.fonction, cc.telephone, cc.mobile, cc.email FROM clients_contacts cc WHERE cc.fk_client = :client_id AND cc.chk_principal = 1 AND cc.active = 1 LIMIT 1';
$sql = 'SELECT cc.nom, cc.prenom, cc.fonction, cc.telephone, cc.mobile, cc.email FROM clients_contacts cc WHERE cc.fk_client = :client_id AND cc.principal = 1 AND cc.active = 1 LIMIT 1';
$contact = $db->fetchOne($sql, [':client_id' => $fkClientSafe]);
}
@@ -217,12 +214,10 @@ switch ($Route->_action) {
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Cache-Control: max-age=0');
echo $excelData;
} catch (Exception $e) {
error_log("Erreur export Excel : " . $e->getMessage());
http_response_code(500);
echo "Erreur lors de l'export du devis";
}
exit();
}

View File

@@ -5,9 +5,10 @@ $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 = 'SELECT d.*, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.code, c.cp, c.ville, cc.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 clients_contacts cc ON d.fk_contact = cc.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 ';
@@ -24,9 +25,10 @@ foreach ($aModel["devisEnCours"] as $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 = 'SELECT d.*, c.libelle, c.adresse1, c.adresse2, c.adresse3, c.code, c.cp, c.ville, cc.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 clients_contacts cc ON d.fk_contact = cc.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 ';

View File

@@ -37,14 +37,107 @@ let devisTotalRemHT = 0
let devisTotalMarge = 0
let chkRegleSeuilsMarge = false // indique si le marché sélectionné prend en compte les seuils de marge fixés dans les familles de produits
let seuilMargeRR = 30 // le seuil de marge du RR sur ce devis, par défaut à 30 %
let seuilMargeDV = 20 // le seuil de marge du DV sur ce devis, par défaut à 20 %
let seuilMargeRR = 40 // le seuil de marge du RR sur ce devis, par défaut à 40 % (MAJ 05/11/2025)
let seuilMargeDV = 30 // le seuil de marge du DV sur ce devis, par défaut à 30 % (MAJ 05/11/2025)
let intervalRefresh
let nbCommentChat = 0
let draggedElement = null // l'élément qui est en train d'être déplacé (la ligne du produit du devis lors d'un drag and drop)
const tableSortStates = new Map()
function initTableSort() {
const allTables = document.querySelectorAll('[id^="tblDos"], [id^="tblDosArch"]')
allTables.forEach(table => {
const tableId = table.id
const headers = table.querySelectorAll('th[data-sortable="true"]')
const tbody = table.querySelector('tbody')
if (!tbody) return
if (!tableSortStates.has(tableId)) {
tableSortStates.set(tableId, {
originalOrder: null,
currentSort: { column: null, direction: null }
})
}
headers.forEach(header => {
header.addEventListener('click', function() {
const columnIndex = parseInt(this.getAttribute('data-column-index'))
const sortType = this.getAttribute('data-sort-type')
sortTable(tableId, columnIndex, sortType, this)
})
})
})
}
function sortTable(tableId, columnIndex, sortType, headerElement) {
const table = document.getElementById(tableId)
const tbody = table.querySelector('tbody')
const rows = Array.from(tbody.querySelectorAll('tr'))
const state = tableSortStates.get(tableId)
if (!state.originalOrder) {
state.originalOrder = rows.slice()
}
const allHeaders = table.querySelectorAll('th[data-sortable="true"]')
allHeaders.forEach(h => h.style.fontWeight = 'normal')
let sortedRows
if (state.currentSort.column === columnIndex && state.currentSort.direction === 'desc') {
sortedRows = state.originalOrder.slice()
state.currentSort = { column: null, direction: null }
} else {
const direction = (state.currentSort.column === columnIndex && state.currentSort.direction === 'asc') ? 'desc' : 'asc'
sortedRows = rows.slice().sort((a, b) => {
const aCell = a.cells[columnIndex]
const bCell = b.cells[columnIndex]
if (!aCell || !bCell) return 0
let aValue = aCell.textContent.trim()
let bValue = bCell.textContent.trim()
if (sortType === 'number') {
aValue = aValue.replace(/[^\d,.-]/g, '').replace(',', '.')
bValue = bValue.replace(/[^\d,.-]/g, '').replace(',', '.')
aValue = parseFloat(aValue) || 0
bValue = parseFloat(bValue) || 0
return direction === 'asc' ? aValue - bValue : bValue - aValue
} else if (sortType === 'date') {
aValue = parseDateFromText(aValue)
bValue = parseDateFromText(bValue)
if (!aValue && !bValue) return 0
if (!aValue) return direction === 'asc' ? 1 : -1
if (!bValue) return direction === 'asc' ? -1 : 1
return direction === 'asc' ? aValue - bValue : bValue - aValue
} else {
const comparison = aValue.localeCompare(bValue, 'fr')
return direction === 'asc' ? comparison : -comparison
}
})
state.currentSort = { column: columnIndex, direction }
headerElement.style.fontWeight = 'bold'
}
tbody.innerHTML = ''
sortedRows.forEach(row => tbody.appendChild(row))
}
function parseDateFromText(dateText) {
const match = dateText.match(/(\d{2})\/(\d{2})[\/\s](\d{4})/)
if (!match) return null
const [, day, month, year] = match
return new Date(year, month - 1, day)
}
window.addEventListener('DOMContentLoaded', (event) => {
console.log('#')
@@ -3790,6 +3883,148 @@ window.addEventListener('DOMContentLoaded', (event) => {
chkVariante.addEventListener('change', calculDevis)
})
let elSearchDevis = document.getElementById('searchDevis')
let elBtnResetSearch = document.getElementById('btnResetSearch')
let searchTimeout = null
function restoreSearch() {
const savedTerm = sessionStorage.getItem('devisSearchTerm')
if (savedTerm && savedTerm.length >= 3) {
elSearchDevis.value = savedTerm
elBtnResetSearch.style.display = 'inline-block'
performSearch(savedTerm)
}
}
function performSearch(term) {
if (term.length < 3) {
return
}
const context = chkShowDevisArchives ? 'archives' : 'encours'
fetch('/jxdevis/search_devis', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
term: term,
context: context,
}),
})
.then((response) => response.json())
.then((data) => {
if (data.success) {
const devisIds = data.devis.map((d) => d.rowid)
filterDevisTables(devisIds, context)
updateBadges(data.nb_devis)
} else {
console.error('Erreur recherche:', data.message)
}
})
.catch((error) => {
console.error('Erreur AJAX:', error)
})
}
function filterDevisTables(devisIds, context) {
if (context === 'encours') {
const statuts = document.querySelectorAll('[id^="tblBodyDos"]')
statuts.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr')
rows.forEach((row) => {
if (row.id && row.id.startsWith('tr_')) {
const rowId = parseInt(row.id.replace('tr_', ''))
if (devisIds.includes(rowId)) {
row.style.display = ''
} else {
row.style.display = 'none'
}
}
})
})
} else {
const archives = document.querySelectorAll('[id^="tblBodyDosArch"]')
archives.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr')
rows.forEach((row) => {
if (row.id && row.id.startsWith('trArch_')) {
const rowId = parseInt(row.id.replace('trArch_', ''))
if (devisIds.includes(rowId)) {
row.style.display = ''
} else {
row.style.display = 'none'
}
}
})
})
}
}
function updateBadges(nbDevis) {
Object.keys(nbDevis).forEach((statutId) => {
const badge = document.querySelector('[id^="liStat"]')
if (badge) {
badge.setAttribute('data-after-text', nbDevis[statutId])
badge.setAttribute('data-after-type', 'orange badge top left')
}
})
}
function resetSearch() {
elSearchDevis.value = ''
elBtnResetSearch.style.display = 'none'
sessionStorage.removeItem('devisSearchTerm')
const context = chkShowDevisArchives ? 'archives' : 'encours'
if (context === 'encours') {
const statuts = document.querySelectorAll('[id^="tblBodyDos"]')
statuts.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr')
rows.forEach((row) => {
row.style.display = ''
})
})
} else {
const archives = document.querySelectorAll('[id^="tblBodyDosArch"]')
archives.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr')
rows.forEach((row) => {
row.style.display = ''
})
})
}
}
elSearchDevis.addEventListener('input', function () {
const term = this.value.trim()
if (searchTimeout) {
clearTimeout(searchTimeout)
}
if (term.length >= 3) {
elBtnResetSearch.style.display = 'inline-block'
sessionStorage.setItem('devisSearchTerm', term)
searchTimeout = setTimeout(() => {
performSearch(term)
}, 300)
} else if (term.length === 0) {
resetSearch()
} else {
elBtnResetSearch.style.display = 'none'
}
})
elBtnResetSearch.addEventListener('click', function () {
resetSearch()
})
restoreSearch()
initTableSort()
elBtnSideBarDevis.addEventListener('click', function () {
if (elVerticalBar.style.width == '10px') {
elVerticalBar.style.width = '1100px' // Largeur de la barre lorsqu'elle est ouverte

View File

@@ -11,6 +11,100 @@ let oldIdLnEnCours;
let oldIdLnArchives;
let nbCommentChat = 0;
let selectedXmlDevis = new Set();
let searchSapTimeout = null;
const tableSortStates = new Map();
function initTableSort() {
const allTables = document.querySelectorAll('[id^="tblDos"], [id^="tblDosArch"]');
allTables.forEach(table => {
const tableId = table.id;
const headers = table.querySelectorAll('th[data-sortable="true"]');
const tbody = table.querySelector('tbody');
if (!tbody) return;
if (!tableSortStates.has(tableId)) {
tableSortStates.set(tableId, {
originalOrder: null,
currentSort: { column: null, direction: null }
});
}
headers.forEach(header => {
header.addEventListener('click', function() {
const columnIndex = parseInt(this.getAttribute('data-column-index'));
const sortType = this.getAttribute('data-sort-type');
sortTable(tableId, columnIndex, sortType, this);
});
});
});
}
function sortTable(tableId, columnIndex, sortType, headerElement) {
const table = document.getElementById(tableId);
const tbody = table.querySelector('tbody');
const rows = Array.from(tbody.querySelectorAll('tr'));
const state = tableSortStates.get(tableId);
if (!state.originalOrder) {
state.originalOrder = rows.slice();
}
const allHeaders = table.querySelectorAll('th[data-sortable="true"]');
allHeaders.forEach(h => h.style.fontWeight = 'normal');
let sortedRows;
if (state.currentSort.column === columnIndex && state.currentSort.direction === 'desc') {
sortedRows = state.originalOrder.slice();
state.currentSort = { column: null, direction: null };
} else {
const direction = (state.currentSort.column === columnIndex && state.currentSort.direction === 'asc') ? 'desc' : 'asc';
sortedRows = rows.slice().sort((a, b) => {
const aCell = a.cells[columnIndex];
const bCell = b.cells[columnIndex];
if (!aCell || !bCell) return 0;
let aValue = aCell.textContent.trim();
let bValue = bCell.textContent.trim();
if (sortType === 'number') {
aValue = aValue.replace(/[^\d,.-]/g, '').replace(',', '.');
bValue = bValue.replace(/[^\d,.-]/g, '').replace(',', '.');
aValue = parseFloat(aValue) || 0;
bValue = parseFloat(bValue) || 0;
return direction === 'asc' ? aValue - bValue : bValue - aValue;
} else if (sortType === 'date') {
aValue = parseDateFromText(aValue);
bValue = parseDateFromText(bValue);
if (!aValue && !bValue) return 0;
if (!aValue) return direction === 'asc' ? 1 : -1;
if (!bValue) return direction === 'asc' ? -1 : 1;
return direction === 'asc' ? aValue - bValue : bValue - aValue;
} else {
const comparison = aValue.localeCompare(bValue, 'fr');
return direction === 'asc' ? comparison : -comparison;
}
});
state.currentSort = { column: columnIndex, direction };
headerElement.style.fontWeight = 'bold';
}
tbody.innerHTML = '';
sortedRows.forEach(row => tbody.appendChild(row));
}
function parseDateFromText(dateText) {
const match = dateText.match(/(\d{2})\/(\d{2})[\/\s](\d{4})/);
if (!match) return null;
const [, day, month, year] = match;
return new Date(year, month - 1, day);
}
window.addEventListener('DOMContentLoaded', (event) => {
console.log('#');
@@ -786,6 +880,201 @@ window.addEventListener('DOMContentLoaded', (event) => {
return false;
};
// Fonctions de recherche SAP
let elSearchSAP = document.getElementById('searchSAP');
let elBtnResetSearchSAP = document.getElementById('btnResetSearchSAP');
function restoreSearchSAP() {
const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
const savedTerm = sessionStorage.getItem(storageKey);
if (savedTerm && savedTerm.length >= 3) {
elSearchSAP.value = savedTerm;
elBtnResetSearchSAP.style.display = 'inline-block';
performSearchSAP(savedTerm);
} else {
elSearchSAP.value = '';
elBtnResetSearchSAP.style.display = 'none';
}
}
function performSearchSAP(term) {
if (term.length < 3) {
return;
}
const context = panel === 'archives' ? 'archives' : 'encours';
fetch('/jxdevis/search_devis_sap', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
term: term,
context: context,
}),
})
.then((response) => response.json())
.then((data) => {
if (data.success) {
const devisIds = data.devis.map((d) => d.rowid);
filterDevisTablesSAP(devisIds, context);
updateBadgesSAP(data.nb_devis);
} else {
console.error('Erreur recherche:', data.message);
}
})
.catch((error) => {
console.error('Erreur AJAX:', error);
});
}
function filterDevisTablesSAP(devisIds, context) {
if (context === 'encours') {
const statuts = document.querySelectorAll('[id^="tblBodyDos"]');
statuts.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr.ligEnCours');
rows.forEach((row) => {
const cells = row.querySelectorAll('.celEnCours');
if (cells.length > 0) {
const rowId = parseInt(cells[0].getAttribute('data-rid'));
if (devisIds.includes(rowId)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
}
});
});
} else {
const archives = document.querySelectorAll('[id^="tblBodyDosArch"]');
archives.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr');
rows.forEach((row) => {
if (row.id && (row.id.startsWith('trArch_') || row.id.startsWith('trArchTous_'))) {
const rowId = parseInt(row.id.replace('trArch_', '').replace('trArchTous_', ''));
if (devisIds.includes(rowId)) {
row.style.display = '';
} else {
row.style.display = 'none';
}
}
});
});
}
}
function updateBadgesSAP(nbDevis) {
Object.keys(nbDevis).forEach((statutId) => {
const liElements = document.querySelectorAll('[id^="liStat"]');
liElements.forEach((li) => {
li.setAttribute('data-after-text', nbDevis[statutId] || '0');
li.setAttribute('data-after-type', 'orange badge top left');
});
});
}
function resetSearchSAP() {
elSearchSAP.value = '';
elBtnResetSearchSAP.style.display = 'none';
const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
sessionStorage.removeItem(storageKey);
const context = panel === 'archives' ? 'archives' : 'encours';
if (context === 'encours') {
const statuts = document.querySelectorAll('[id^="tblBodyDos"]');
statuts.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr');
rows.forEach((row) => {
row.style.display = '';
});
});
} else {
const archives = document.querySelectorAll('[id^="tblBodyDosArch"]');
archives.forEach((tbody) => {
const rows = tbody.querySelectorAll('tr');
rows.forEach((row) => {
row.style.display = '';
});
});
const tbodyTous = document.getElementById('tblBodyDosArchTous');
if (tbodyTous) {
const rowsTous = tbodyTous.querySelectorAll('tr');
rowsTous.forEach((row) => {
row.style.display = '';
});
}
}
}
elSearchSAP.addEventListener('input', function () {
const term = this.value.trim();
if (searchSapTimeout) {
clearTimeout(searchSapTimeout);
}
if (term.length >= 3) {
elBtnResetSearchSAP.style.display = 'inline-block';
const storageKey = panel === 'enCours' ? 'sapSearchTermEnCours' : 'sapSearchTermArchives';
sessionStorage.setItem(storageKey, term);
searchSapTimeout = setTimeout(() => {
performSearchSAP(term);
}, 300);
} else if (term.length === 0) {
resetSearchSAP();
} else {
elBtnResetSearchSAP.style.display = 'none';
}
});
elBtnResetSearchSAP.addEventListener('click', function () {
resetSearchSAP();
});
// Hook sur changement d'onglet pour restaurer la recherche appropriée
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
if ($(this).attr('href') == '#tabEnCours') {
panel = 'enCours';
restoreSearchSAP();
} else if ($(this).attr('href') == '#tabArchives') {
panel = 'archives';
restoreSearchSAP();
}
});
restoreSearchSAP();
initTableSort();
// Gestion des états actifs des onglets départements (multiples <ul>)
// Utiliser l'événement Bootstrap 'shown.bs.tab' au lieu de 'click'
const allDeptTabs = document.querySelectorAll('.dept-tab a');
allDeptTabs.forEach((tab) => {
$(tab).on('shown.bs.tab', function(e) {
// Retirer 'active' de tous les onglets départements sauf celui-ci
document.querySelectorAll('.dept-tab').forEach((li) => {
if (li !== this.parentElement) {
li.classList.remove('active');
}
});
// Retirer 'active' de l'onglet "Tous"
const tousLi = document.querySelector('a[href="#dosArchTous"]').parentElement;
tousLi.classList.remove('active');
});
});
// Gestion du clic sur "Tous"
const tousTab = document.querySelector('a[href="#dosArchTous"]');
if (tousTab) {
$(tousTab).on('shown.bs.tab', function(e) {
// Retirer 'active' de tous les onglets départements
document.querySelectorAll('.dept-tab').forEach((li) => {
li.classList.remove('active');
});
});
}
// Add new functions
function updateExportButton() {
if (selectedXmlDevis.size > 0) {

View File

@@ -16,6 +16,16 @@ ob_start();
<div id="vb-buttons" class="mb-1">
<button class="btn btn-default" id="btnDevisArchives" title="Voir les devis archivés"><i class="fa fa-stack-overflow fa-lg"></i> Devis archivés</button>
<button class="btn btn-success" id="btnCreateDevis" title="Créer un nouveau devis"><i class="fa fa-plus fa-lg"></i> Créer un devis</button>
<div class="row">
<div class="col-md-9">
<div class="input-group mt-1">
<input type="text" class="form-control" id="searchDevis" placeholder="Rechercher un devis par le nom du client, du contact, ville, opportunité..." maxlength="30">
<span class="input-group-addon">
<i class="fa fa-times clickable" id="btnResetSearch" style="display:none;"></i>
</span>
</div>
</div>
</div>
</div>
<?php
if ($aModel["last_devis"] > 0) {
@@ -87,21 +97,23 @@ ob_start();
echo '<div class="border cm-scrollbar cm-table-w-scroll table-responsive table-800">';
echo '<table class="table table-responsive table-bordered table-fixed" id="tblDos' . $iDos . '">';
echo '<thead><tr>';
echo '<th class="header" scope="col" width="5%">#</th>';
echo '<th class="header" scope="col" width="10%">Demande</th>';
echo '<th class="header clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="0">#</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="1">Demande</th>';
$colIndex = 2;
if (($fkRole == 2 && $iDos == 2) || ($fkRole == 1 && $iDos == 1)) {
// C'est un DV et sur le dossier Encours de validation DV
// Ou le Dir-CO sur le dossier de validation DIR-CO
// on affiche la colonne du nom du RR pour qu'il puisse savoir qui a fait la demande
echo '<th class="header" scope="col" width="15%">RR</th>';
echo '<th class="header clickable" scope="col" width="15%" data-sortable="true" data-sort-type="text" data-column-index="' . $colIndex . '">RR</th>';
$colIndex++;
}
echo '<th class="header" scope="col" width="10%">Opport.</th>';
echo '<th class="header" scope="col" width="5%">CP</th>';
echo '<th class="header" scope="col" width="10%">Ville</th>';
echo '<th class="header" scope="col" width="15%">Client</th>';
echo '<th class="header" scope="col" width="10%">Marché</th>';
echo '<th class="header" scope="col" width="10%">Total HT</th>';
echo '<th class="header" scope="col" width="10%">Marge Totale</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="' . $colIndex . '">Opport.</th>';
echo '<th class="header clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="' . ($colIndex + 1) . '">CP</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="' . ($colIndex + 2) . '">Ville</th>';
echo '<th class="header clickable" scope="col" width="15%" data-sortable="true" data-sort-type="text" data-column-index="' . ($colIndex + 3) . '">Client</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="' . ($colIndex + 4) . '">Marché</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="' . ($colIndex + 5) . '">Total HT</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="' . ($colIndex + 6) . '">Marge Totale</th>';
echo '<th class="header" scope="col" width="12%"></th>';
echo '</tr></thead>';
echo '<tbody id="tblBodyDos' . $iDos . '">';
@@ -203,14 +215,14 @@ ob_start();
echo '<div class="border cm-scrollbar cm-table-w-scroll table-responsive table-800">';
echo '<table class="table table-responsive table-bordered table-fixed" id="tblDosArch' . $iDos . '">';
echo '<thead><tr>';
echo '<th class="header" scope="col" width="5%">#</th>';
echo '<th class="header" scope="col" width="10%">Demande</th>';
echo '<th class="header" scope="col" width="10%">Opport.</th>';
echo '<th class="header" scope="col" width="10%">Ville</th>';
echo '<th class="header" scope="col" width="20%">Client</th>';
echo '<th class="header" scope="col" width="10%">Marché</th>';
echo '<th class="header" scope="col" width="10%">Total HT</th>';
echo '<th class="header" scope="col" width="10%">Marge Totale</th>';
echo '<th class="header clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="0">#</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="1">Demande</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="2">Opport.</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="3">Ville</th>';
echo '<th class="header clickable" scope="col" width="20%" data-sortable="true" data-sort-type="text" data-column-index="4">Client</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="5">Marché</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="6">Total HT</th>';
echo '<th class="header clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="7">Marge Totale</th>';
echo '<th class="header" scope="col" width="10%"></th>';
echo '</tr></thead>';
echo '<tbody id="tblBodyDosArch' . $iDos . '">';

View File

@@ -5,7 +5,37 @@ $metacss = '<link href="/pub/res/css/schat.css" rel="stylesheet" type="text/css"
$barre = "";
ob_start();
?>
<div id="divSAP">
<style>
.dept-tab a {
min-width: 50px !important;
padding: 8px 10px !important;
font-size: 13px;
}
.table-800 {
overflow-y: auto !important;
}
#tabArchives .table-800 {
max-height: 680px !important;
}
.table-800 thead th {
position: sticky;
top: 0;
z-index: 10;
}
</style>
<div class="row" style="margin-bottom: 20px;">
<div class="col-md-2"></div>
<div class="col-md-8">
<div class="input-group">
<input type="text" class="form-control" id="searchSAP" placeholder="Rechercher un devis par le nom du client, du contact, ville, opportunité..." maxlength="30">
<span class="input-group-addon">
<i class="fa fa-times clickable" id="btnResetSearchSAP" style="display:none;"></i>
</span>
</div>
</div>
<div class="col-md-2"></div>
</div>
<div id="divSAP" style="margin-top: 20px;">
<ul class="nav nav-tabs nav-justified" role="tablist">
<li role="presentation" class="active"><a href="#tabEnCours" aria-controls="tabEnCours" role="tab" data-toggle="tab">Les devis en cours</a></li>
<li role="presentation"><a href="#tabArchives" aria-controls="tabArchives" role="tab" data-toggle="tab">Les devis archivés</a></li>
@@ -40,20 +70,22 @@ ob_start();
echo '<div class="border cm-scrollbar cm-table-w-scroll table-responsive table-800">';
echo '<table class="table table-responsive table-bordered table-fixed" id="tblDos' . $iDos . '">';
echo '<thead><tr>';
echo '<th class="header text-center" scope="col" width="5%">#</th>';
echo '<th class="header text-center" scope="col" width="10%">Date Demande</th>';
echo '<th class="header text-center" scope="col" width="10%">Date Remise</th>';
echo '<th class="header text-center" scope="col" width="10%">Responsable Régional</th>';
echo '<th class="header text-center" scope="col" width="10%">Code Etabliss.</th>';
echo '<th class="header text-center" scope="col" width="15%">Etablissement</th>';
echo '<th class="header text-center" scope="col" width="7%">CP</th>';
echo '<th class="header text-center" scope="col" width="10%">Ville</th>';
echo '<th class="header text-center" scope="col" width="10%">Marché</th>';
echo '<th class="header text-center" scope="col" width="10%">Montant Total HT</th>';
echo '<th class="header text-center" scope="col" width="10%">Marge totale</th>';
echo '<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="0">#</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="1">Date Demande</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="2">Date Remise</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="3">Responsable Régional</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="4">Code Etabliss.</th>';
echo '<th class="header text-center clickable" scope="col" width="15%" data-sortable="true" data-sort-type="text" data-column-index="5">Etablissement</th>';
echo '<th class="header text-center clickable" scope="col" width="7%" data-sortable="true" data-sort-type="number" data-column-index="6">CP</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="7">Ville</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="8">Marché</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="9">Montant Total HT</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="10">Marge totale</th>';
$colIndexActions = 11;
if ($dossier["rowid"] == 7) {
// Si le dossier est "A envoyer au client", on affiche la colonne "Email"
echo '<th class="header text-center" scope="col" width="10%">Email</th>';
$colIndexActions = 12;
}
echo '<th class="header text-center" scope="col" width="20%">Actions <button class="btn btn-info btn-xs btnExportSelectedXML hidden" title="Export XML SAP des devis sélectionnés"><i class="fa fa-scribd fa-lg"></i></button></th>';
echo '</tr></thead>';
@@ -167,39 +199,118 @@ ob_start();
<div role="tabpanel" class="tab-pane" id="tabArchives">
<div class="row">
<div class="col-md-9">
<ul class="nav nav-tabs nav-justified" role="tablist">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#dosArchTous" aria-controls="dosArchTous" role="tab" data-toggle="tab">Tous</a></li>
</ul>
<?php
$i = 0;
foreach ($aModel["dossiers"] as $dossier) {
if ($i % 15 == 0 && $i > 0) {
echo '<div class="spacer"></div>';
}
$active = ($i == 0) ? "active" : "";
$nbPerLine = 25;
$totalDepts = count($aModel["dossiers"]);
for ($line = 0; $line < 4; $line++) {
echo '<ul class="nav nav-tabs" role="tablist">';
$start = $line * $nbPerLine;
$end = min($start + $nbPerLine, $totalDepts);
for ($j = $start; $j < $end; $j++) {
$dossier = $aModel["dossiers"][$j];
$ceDossier = ($dossier["dossier"] == "") ? "?" : $dossier["dossier"];
echo '<li role="presentation" class="' . $active . '"><a href="#dosArch' . $i . '" aria-controls="dosArch' . $i . '" role="tab" data-toggle="tab">' . $ceDossier . '</a></li>';
$i++;
echo '<li role="presentation" class="dept-tab"><a href="#dosArch' . $j . '" aria-controls="dosArch' . $j . '" role="tab" data-toggle="tab">' . $ceDossier . '</a></li>';
}
echo '</ul>';
}
?>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane p-0 active" id="dosArchTous">
<div class="border cm-scrollbar cm-table-w-scroll table-responsive table-800">
<table class="table table-responsive table-bordered table-fixed" id="tblDosArchTous">
<thead><tr>
<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="0">#</th>
<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="1">Date Demande</th>
<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="2">Resp. Régional</th>
<th class="header text-center clickable" scope="col" width="7%" data-sortable="true" data-sort-type="text" data-column-index="3">Code Etabliss.</th>
<th class="header text-center clickable" scope="col" width="15%" data-sortable="true" data-sort-type="text" data-column-index="4">Etablissement</th>
<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="5">CP</th>
<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="6">Ville</th>
<th class="header text-center clickable" scope="col" width="8%" data-sortable="true" data-sort-type="text" data-column-index="7">Marché</th>
<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="text" data-column-index="8">Dép.</th>
<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="9">Montant Total HT</th>
<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="10">Marge totale</th>
<th class="header text-center" scope="col" width="10%">Actions</th>
</tr></thead>
<tbody id="tblBodyDosArchTous">
<?php
$i = 0;
foreach ($aModel["devisArchives"] as $devis) {
echo '<tr id="trArchTous_' . $devis["rowid"] . '">';
echo '<td class="text-center">' . $devis["rowid"] . '</td>';
$dateDem = substr($devis["date_demande"], 8, 2) . '/' . substr($devis["date_demande"], 5, 2) . ' ' . substr($devis["date_demande"], 0, 4);
if ($devis["chk_speciaux"] == 1) {
$cellDateDem = '<span data-after-text="S" data-after-type="blue circle">' . $dateDem . '</span>';
} else {
$cellDateDem = $dateDem;
}
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $cellDateDem . '</td>';
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $devis["prenom"] . " " . $devis["nom"] . '</td>';
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $devis["code"] . '</td>';
if ($devis["fk_client"] == 0) {
$ville = $devis["ville_new_client"];
$libelle = '<span data-after-text="N" data-after-type="red circle">' . $devis["lib_new_client"] . '</span>';
} else {
$ville = $devis["ville"];
$libelle = $devis["libelle"];
}
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $libelle . '</td>';
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $devis["cp"] . '</td>';
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $ville . '</td>';
echo '<td class="clickable celArchives" data-rid="' . $devis["rowid"] . '">' . $devis["lib_marche"] . '</td>';
$dossierLabel = ($devis["dossier"] == "") ? "?" : $devis["dossier"];
echo '<td class="clickable celArchives text-center" data-rid="' . $devis["rowid"] . '">' . $dossierLabel . '</td>';
$montant = floatval($devis["montant_total_ht_remise"]);
echo '<td class="clickable celArchives right" data-rid="' . $devis["rowid"] . '">' . number_format($montant, 2, ',', ' ') . ' &euro;</td>';
$margeTotale = floatval($devis["marge_totale"]);
echo '<td class="clickable celArchives right" data-rid="' . $devis["rowid"] . '">' . number_format($margeTotale, 2, ',', ' ') . ' &percnt;</td>';
echo '<td class="text-center">';
echo '<div class="btn-group">';
echo '<button class="btn btn-primary btn-xs btnViewDevisArchives" title="Consulter le devis" data-rid="' . $devis["rowid"] . '"><i class="fa fa-eye fa-lg"></i></button>';
echo '<button class="btn btn-info btn-xs btnExportDevisEnCours" title="Export Excel du devis" data-rid="' . $devis["rowid"] . '" data-libelle="' . $devis["libelle"] . '"><i class="fa fa-file-excel-o fa-lg"></i></button>';
$typBtn = "btn-success";
foreach ($aModel["medias"] as $media) {
if ($media["support_rowid"] == $devis["rowid"]) {
$typBtn = "btn-warning";
break;
}
}
echo '<button class="btn ' . $typBtn . ' btn-xs btnImportPDFEnCours" title="Consulter le PDF SAP du devis" data-rid="' . $devis["rowid"] . '" data-libelle="' . $devis["libelle"] . '"><i class="fa fa-file-pdf-o fa-lg"></i></button>';
echo '</div>';
echo '</td></tr>';
$i++;
}
if ($i == 0) echo '<tr><td colspan="12" class="center">Aucun devis archivé trouvé</td></tr>';
?>
</tbody>
</table>
</div>
</div>
<?php
$iDos = 0;
foreach ($aModel["dossiers"] as $dossier) {
$active = ($iDos == 0) ? "active" : "";
$active = "";
echo '<div role="tabpanel" class="tab-pane p-0 ' . $active . '" id="dosArch' . $iDos . '">';
echo '<div class="border cm-scrollbar cm-table-w-scroll table-responsive table-800">';
echo '<table class="table table-responsive table-bordered table-fixed" id="tblDosArch' . $iDos . '">';
echo '<thead><tr>';
echo '<th class="header text-center" scope="col" width="5%">#</th>';
echo '<th class="header text-center" scope="col" width="10%">Date Demande</th>';
echo '<th class="header text-center" scope="col" width="10%">Resp. Régional</th>';
echo '<th class="header text-center" scope="col" width="7%">Code Etabliss.</th>';
echo '<th class="header text-center" scope="col" width="20%">Etablissement</th>';
echo '<th class="header text-center" scope="col" width="5%">CP</th>';
echo '<th class="header text-center" scope="col" width="13%">Ville</th>';
echo '<th class="header text-center" scope="col" width="10%">Marché</th>';
echo '<th class="header text-center" scope="col" width="10%">Montant Total HT</th>';
echo '<th class="header text-center" scope="col" width="10%">Marge totale</th>';
echo '<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="0">#</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="date" data-column-index="1">Date Demande</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="2">Resp. Régional</th>';
echo '<th class="header text-center clickable" scope="col" width="7%" data-sortable="true" data-sort-type="text" data-column-index="3">Code Etabliss.</th>';
echo '<th class="header text-center clickable" scope="col" width="20%" data-sortable="true" data-sort-type="text" data-column-index="4">Etablissement</th>';
echo '<th class="header text-center clickable" scope="col" width="5%" data-sortable="true" data-sort-type="number" data-column-index="5">CP</th>';
echo '<th class="header text-center clickable" scope="col" width="13%" data-sortable="true" data-sort-type="text" data-column-index="6">Ville</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="text" data-column-index="7">Marché</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="8">Montant Total HT</th>';
echo '<th class="header text-center clickable" scope="col" width="10%" data-sortable="true" data-sort-type="number" data-column-index="9">Marge totale</th>';
echo '<th class="header text-center" scope="col" width="10%">Actions</th>';
echo '</tr></thead>';
echo '<tbody id="tblBodyDosArch' . $iDos . '">';