Created
May 30, 2026 15:54
-
-
Save b23prodtm/63b3efe43fa695c2c5a1304173cdee26 to your computer and use it in GitHub Desktop.
Transfert commandes GDO vers Webtel Station Chargeur Online
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>GDO ➜ Webtel Converter Ultimate</title> | |
| <style> | |
| :root { --webtel-blue: #0056b3; --webtel-gray: #f0f2f5; --webtel-border: #dcdfe3; --success: #28a745; } | |
| body { font-family: 'Segoe UI', Arial, sans-serif; background-color: var(--webtel-gray); padding: 20px; margin: 0; } | |
| .container { max-width: 1200px; margin: 20px auto; background: #fff; padding: 25px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); position: relative; } | |
| .header { display: flex; justify-content: space-between; align-items: center; border-bottom: 2px solid var(--webtel-blue); margin-bottom: 20px; padding-bottom: 10px; } | |
| h1 { color: var(--webtel-blue); font-size: 1.3rem; margin: 0; text-transform: uppercase; } | |
| /* Onglet de Configuration */ | |
| .settings-panel { position: absolute; top: 70px; right: 25px; background: white; border: 1px solid var(--webtel-border); border-radius: 4px; padding: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 100; display: none; width: 350px; } | |
| .settings-btn { background: none; border: none; cursor: pointer; font-size: 1.5rem; color: var(--webtel-text); } | |
| .settings-btn:hover { color: var(--webtel-blue); } | |
| .filter-section { background: #f9f9f9; padding: 15px; border: 1px solid var(--webtel-border); border-radius: 4px; margin-bottom: 15px; } | |
| .filter-section label { font-weight: bold; font-size: 0.85rem; display: block; margin-bottom: 8px; } | |
| textarea { width: 100%; border: 1px solid var(--webtel-border); padding: 8px; font-family: monospace; font-size: 0.8rem; box-sizing: border-box; border-radius: 4px; } | |
| .upload-area { border: 1px dashed var(--webtel-blue); padding: 30px; text-align: center; background: #fafafa; cursor: pointer; margin-bottom: 20px; border-radius: 4px; } | |
| table { width: 100%; border-collapse: collapse; font-size: 0.8rem; } | |
| th { background: #f8f9fa; padding: 10px; border-bottom: 2px solid var(--webtel-blue); text-align: left; } | |
| td { padding: 8px 10px; border-bottom: 1px solid #eee; } | |
| .pagination { display: flex; justify-content: center; align-items: center; gap: 20px; padding: 10px; background: #f8f9fa; border-top: 1px solid var(--webtel-border); } | |
| .pagination button { padding: 4px 12px; cursor: pointer; border: 1px solid var(--webtel-blue); background: white; color: var(--webtel-blue); border-radius: 4px; font-weight: bold; } | |
| .btn-action { width: 100%; padding: 12px; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; margin-top: 10px; display: none; } | |
| #logArea { background: #fdfdfd; border: 1px solid var(--webtel-border); padding: 10px; height: 100px; overflow-y: auto; font-family: monospace; font-size: 0.75rem; margin-top: 15px; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>GDO ➜ Webtel Converter</h1> | |
| <button class="settings-btn" onclick="toggleSettings()">⚙</button> | |
| </div> | |
| <!-- Panneau de Configuration JSON Masqué --> | |
| <div id="settingsPanel" class="settings-panel"> | |
| <label style="font-weight: bold; display: block; margin-bottom: 10px;">Mappage JSON :</label> | |
| <textarea id="mappingConfig" style="height: 200px;"> | |
| { | |
| "ORDER": "NUM. ORD.", | |
| "CLIENT_CODE": "COD. DEST", | |
| "DEST": "DESTINATARIO", | |
| "CITY": "LOCALITA", | |
| "ZIP": "PR", | |
| "WEIGHT": "LORDO", | |
| "PARCELS": "COLLI", | |
| "PALLETS": "PLT", | |
| "DATE_SHIP": "DATA CARICO", | |
| "DATE_DELIV": "DATA CONS.", | |
| "TIME_DELIV": "ORA CONSEGNA", | |
| "NOTE1": "NOTE DESTINATARI", | |
| "NOTE2": "NOTE" | |
| } | |
| </textarea> | |
| <button onclick="saveConfig()" style="margin-top:10px; width:100%; padding:8px; background:var(--webtel-blue); color:white; border:none; border-radius:4px; cursor:pointer;">Sauvegarder</button> | |
| </div> | |
| <div class="filter-section"> | |
| <label>Préchargement des commandes (Numéros séparés par espace ou ligne) :</label> | |
| <textarea id="prechargeFilter" style="height: 60px;" placeholder="Ex: 2131290840 2131290841"></textarea> | |
| </div> | |
| <div id="validationResult"></div> | |
| <div class="upload-area" id="dropZone"> | |
| Glissez le fichier <strong>BOLLE_ATTI_TESTATA.csv</strong> ici pour l'importer | |
| </div> | |
| <div id="tableWrapper" style="display:none;"> | |
| <input type="text" id="tableSearch" style="width:100%; padding:10px; margin-bottom:15px; border:1px solid var(--webtel-border); border-radius:4px;" placeholder="Rechercher un destinataire ou une ville..."> | |
| <div style="border: 1px solid var(--webtel-border);"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th><input type="checkbox" id="selectAll"></th> | |
| <th>Ordre</th> | |
| <th>Destinataire</th> | |
| <th>Ville</th> | |
| <th>Poids</th> | |
| </tr> | |
| </thead> | |
| <tbody id="tableBody"></tbody> | |
| </table> | |
| <div class="pagination"> | |
| <button id="prevBtn"> << </button> | |
| <span id="pageInfo">Page 1 / 1</span> | |
| <button id="nextBtn"> >> </button> | |
| </div> | |
| </div> | |
| <button id="convertBtn" class="btn-action" style="background:var(--webtel-blue); color:white; display:block;">CONVERTIR POUR WEBTEL</button> | |
| <button id="downloadBtn" class="btn-action" style="background:var(--success); color:white;">TÉLÉCHARGER LE CSV</button> | |
| </div> | |
| <div id="logArea"></div> | |
| </div> | |
| <script> | |
| let allData = []; | |
| let filteredData = []; | |
| let selectedOrders = new Set(); | |
| let currentPage = 1; | |
| const rowsPerPage = 15; | |
| let fileHeaders = []; | |
| let finalCSV = ""; | |
| function toggleSettings() { | |
| const panel = document.getElementById('settingsPanel'); | |
| panel.style.display = panel.style.display === 'block' ? 'none' : 'block'; | |
| } | |
| function saveConfig() { | |
| localStorage.setItem('gdoMappingConfig', document.getElementById('mappingConfig').value); | |
| toggleSettings(); | |
| addLog("Configuration JSON sauvegardée."); | |
| } | |
| window.onload = () => { | |
| const saved = localStorage.getItem('gdoMappingConfig'); | |
| if (saved) document.getElementById('mappingConfig').value = saved; | |
| }; | |
| const dropZone = document.getElementById('dropZone'); | |
| dropZone.onclick = () => { let i = document.createElement('input'); i.type='file'; i.onchange=e=>handleFile(e.target.files[0]); i.click(); }; | |
| dropZone.ondragover = e => { e.preventDefault(); dropZone.style.background="#f0f7ff"; }; | |
| dropZone.ondrop = e => { e.preventDefault(); handleFile(e.dataTransfer.files[0]); }; | |
| function addLog(msg) { | |
| const div = document.createElement('div'); | |
| div.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`; | |
| document.getElementById('logArea').prepend(div); | |
| } | |
| function handleFile(file) { | |
| const precharge = document.getElementById('prechargeFilter').value.split(/[\s,\n]+/).filter(x => x.trim() !== ""); | |
| const reader = new FileReader(); | |
| reader.onload = e => { | |
| const lines = e.target.result.split(/\r?\n/); | |
| fileHeaders = lines[0].split(';'); | |
| const map = JSON.parse(document.getElementById('mappingConfig').value); | |
| const idxOrder = fileHeaders.indexOf(map.ORDER); | |
| allData = lines.slice(1).filter(l => l.trim()).map(l => l.split(';')) | |
| .filter(row => precharge.length === 0 || precharge.includes(row[idxOrder])); | |
| filteredData = [...allData]; | |
| selectedOrders.clear(); | |
| currentPage = 1; | |
| renderTable(); | |
| document.getElementById('tableWrapper').style.display = "block"; | |
| addLog(`${allData.length} lignes filtrées par préchargement.`); | |
| }; | |
| reader.readAsText(file); | |
| } | |
| function renderTable() { | |
| const map = JSON.parse(document.getElementById('mappingConfig').value); | |
| const tbody = document.getElementById('tableBody'); | |
| tbody.innerHTML = ""; | |
| const start = (currentPage - 1) * rowsPerPage; | |
| const pageData = filteredData.slice(start, start + rowsPerPage); | |
| const idx = { order: fileHeaders.indexOf(map.ORDER), dest: fileHeaders.indexOf(map.DEST), city: fileHeaders.indexOf(map.CITY), weight: fileHeaders.indexOf(map.WEIGHT) }; | |
| pageData.forEach(row => { | |
| const id = row[idx.order]; | |
| const tr = document.createElement('tr'); | |
| const isChecked = selectedOrders.has(id) ? "checked" : ""; | |
| tr.innerHTML = `<td><input type="checkbox" ${isChecked} onchange="toggleOrderSelection('${id}', this.checked)"></td> | |
| <td>${id}</td><td>${row[idx.dest]}</td><td>${row[idx.city]}</td><td>${row[idx.weight]}</td>`; | |
| tbody.appendChild(tr); | |
| }); | |
| const totalPages = Math.ceil(filteredData.length / rowsPerPage); | |
| document.getElementById('pageInfo').textContent = `Page ${currentPage} / ${totalPages || 1}`; | |
| } | |
| window.toggleOrderSelection = (id, checked) => { | |
| if(checked) selectedOrders.add(id); else selectedOrders.delete(id); | |
| }; | |
| document.getElementById('selectAll').onchange = (e) => { | |
| const map = JSON.parse(document.getElementById('mappingConfig').value); | |
| const idxOrder = fileHeaders.indexOf(map.ORDER); | |
| filteredData.forEach(row => { | |
| if(e.target.checked) selectedOrders.add(row[idxOrder]); | |
| else selectedOrders.delete(row[idxOrder]); | |
| }); | |
| renderTable(); | |
| }; | |
| document.getElementById('tableSearch').oninput = (e) => { | |
| const term = e.target.value.toLowerCase(); | |
| filteredData = allData.filter(row => row.some(col => col.toLowerCase().includes(term))); | |
| currentPage = 1; | |
| renderTable(); | |
| }; | |
| document.getElementById('convertBtn').onclick = () => { | |
| if (selectedOrders.size === 0) return alert("Sélectionnez au moins une commande."); | |
| const map = JSON.parse(document.getElementById('mappingConfig').value); | |
| const header = "M_Separator;Date of shippment;M_Carrier code;M_Product code;M_Sender code;Sender label;Consignee code;M_Consignee name 1;Consignee name 2;Consignee name 3;M_Consignee address 1;Consignee address 2;Consignee address 3;Consignee country;M_Consignee postal code;M_Consignee city;Contact;Phone;Consignment number;Reference;M_Terms of delivery-Incoterm;M_Number of handlings units;NumberOfParcels;Number of Euro-pallet;Type of Euro-pallet;M_Gross weight;Taxable unit;Taxable unit type;Gross volume;Cash on Delivery;Currency1;Declared value;Currency2;not use1;not use2;Goods description;Delivery information1;Delivery information2;Mandatory delivery date;Printer code;Particular delivery;Announcement by email;Mobile phone;E-mail;meter floor;Start date desired delivery;Start hour desired delivery;End date desired delivery;End hour desired delivery;Prior delivery notice;Appointment taking before delivery;Availability date"; | |
| const rows = [header]; | |
| const idx = {}; | |
| for(let key in map) { idx[key] = fileHeaders.indexOf(map[key]); } | |
| allData.filter(row => selectedOrders.has(row[idx.ORDER])).forEach(row => { | |
| let r = new Array(52).fill(""); | |
| r[0] = "S"; r[2] = "01"; r[3] = "01"; r[4] = "01"; | |
| r[1] = row[idx.DATE_SHIP]; | |
| r[6] = row[idx.CLIENT_CODE]; | |
| r[7] = row[idx.DEST]; r[13] = "FR"; r[14] = row[idx.ZIP]; r[15] = row[idx.CITY]; | |
| r[19] = row[idx.ORDER]; r[20] = "P"; | |
| r[21] = row[idx.PARCELS]; r[22] = row[idx.PARCELS]; | |
| r[23] = row[idx.PALLETS]; | |
| r[24] = "PAL"; r[25] = row[idx.WEIGHT]; | |
| const notes = ((row[idx.NOTE1] || "") + " " + (row[idx.NOTE2] || "")).trim(); | |
| r[36] = notes.substring(0, 128); r[37] = notes.substring(128, 256); | |
| r[38] = row[idx.DATE_DELIV]; | |
| r[46] = row[idx.TIME_DELIV]; | |
| r[50] = "O"; | |
| rows.push(r.join(';')); | |
| }); | |
| finalCSV = rows.join('\n'); | |
| document.getElementById('downloadBtn').style.display = "block"; | |
| addLog(`Conversion terminée : ${selectedOrders.size} commandes sélectionnées.`); | |
| }; | |
| document.getElementById('downloadBtn').onclick = () => { | |
| const blob = new Blob([finalCSV], { type: 'text/csv' }); | |
| const a = document.createElement('a'); | |
| a.href = URL.createObjectURL(blob); | |
| a.download = `WEBTEL_EXPORT_${Date.now()}.csv`; | |
| a.click(); | |
| }; | |
| document.getElementById('prevBtn').onclick = () => { if(currentPage > 1) { currentPage--; renderTable(); } }; | |
| document.getElementById('nextBtn').onclick = () => { if(currentPage * rowsPerPage < filteredData.length) { currentPage++; renderTable(); } }; | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment