<html>
<head>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link href="https://cdn.datatables.net/v/bm/jszip-3.10.1/dt-2.1.4/b-3.1.1/b-colvis-3.1.1/b-html5-3.1.1/b-print-3.1.1/date-1.5.3/fc-5.0.1/fh-4.0.1/r-3.0.2/rg-1.5.0/sp-2.3.2/sl-2.0.5/sr-1.4.1/datatables.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/v/bm/jszip-3.10.1/dt-2.1.4/b-3.1.1/b-colvis-3.1.1/b-html5-3.1.1/b-print-3.1.1/date-1.5.3/fc-5.0.1/fh-4.0.1/r-3.0.2/rg-1.5.0/sp-2.3.2/sl-2.0.5/sr-1.4.1/datatables.min.js"></script>
<script src="https://moment.github.io/luxon/global/luxon.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css" rel="stylesheet">
<meta charset=utf-8 />
<title>DataTables - JS Bin</title>
</head>
<body>
<div class="container">
<table id="liste_factures" class="table is-hoverable font95rem">
<thead>
<!-- récap des calculs sur les factures en cours (voir si on le met ici ou si on le garde dans le layout)-->
<tr class="is-hidden">
<th colspan="13" class="font95rem has-text-right smallcaps has-text-weight-medium">
total en-cours : <span id="head_total_en_cours"></span> <span id="head_count_total" class="parentheses has-text-weight-light"></span>
<span class="indianred ml-3">échues : </span> <span id="head_total_echues" class="indianred"></span> <span id="head_count_echues" class="parentheses has-text-weight-light indianred"></span>
<span class="olivedrab ml-3">non échues : </span> <span id="head_total_non_echues" class="olivedrab"></span> <span id="head_count_non_echues" class="parentheses has-text-weight-light olivedrab"></span>
</th>
</tr>
<tr class="thead-light">
<th><!-- details --></th>
<th><!-- ajouter reglements --></th>
<th><!-- acquitter facture --></th>
<th>mouvement</th>
<th>stade</th>
<th>type d'intervention</th>
<th>numéro</th>
<th>date</th>
<th>client</th>
<th>commettant</th>
<th>échéance</th>
<th>montant ttc</th>
<th>restant dû</th>
<th class="filtre never">facturation</th>
<th class="filtre never">mois</th>
<th class="traitement never">late</th>
<th class="traitement never">late (count)</th>
<th class="traitement never">not late</th>
<th class="traitement never">not late (count)</th>
</tr>
</thead>
<tfoot>
<tr class="soustotal has-text-FT">
<td colspan="12" class="rupture bg-royalblue has-text-right has-text-weight-semibold has-text-white"></td>
<td class="rupture bg-royalblue has-text-right has-text-weight-semibold has-text-white white-space-nowrap"></td>
<td class="filtre never"></td>
<td class="filtre never"></td>
<td class="traitement never"></td>
<td class="traitement never"></td>
<td class="traitement never"></td>
<td class="traitement never"></td>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
body {
font: 90%/1.45em "Helvetica Neue", HelveticaNeue, Verdana, Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
color: #333;
background-color: #fff;
}
var today = DateTime.fromISO(DateTime.now()); // pour les calculs (retard)
var nameLevel0 = ''; // pour rowgroup
var dataSet = [
{
"__KEY": 103508,
"Num_interne": 103508,
"Num_chrono": "FIB11664",
"Nature": "Fact Inter BHS",
"Date1": "2023-12-05",
"Date2": "2024-01-04",
"Montant2": 4292.65,
"Montant3": 4292.65,
"Libelle": "Einsatz unseres Technikers F. Richard",
"Saisi_par": "slobstein",
"Stade_courant": "Envoyée",
"personne1": {
"Societe": "Test Case Company"
},
"mouvementsRubriques": [
{
"Code_rubrique": "NK",
"Valeur_alpha": "2404994"
},
{
"Code_rubrique": "TE",
"Valeur_alpha": "MO",
"Nature": 0,
"code": "MO",
"libelle": "Montage"
},
{
"Code_rubrique": "MY",
"Valeur_alpha": "2459"
},
{
"Code_rubrique": "CL",
"Valeur_alpha": "-"
},
{
"Code_rubrique": "MT",
"Valeur_alpha": "WPA"
},
{
"Code_rubrique": "TN",
"Valeur_alpha": "FR"
},
{
"Code_rubrique": "DT",
"Valeur_alpha": ""
},
{
"Code_rubrique": "PB",
"Valeur_alpha": "BHS C"
},
{
"Code_rubrique": "FG",
"Valeur_alpha": "-"
},
{
"Code_rubrique": "RC",
"Valeur_alpha": "4501063501"
},
{
"Code_rubrique": "CB",
"Valeur_alpha": "SERV"
},
{
"Code_rubrique": "AR",
"Valeur_alpha": ""
}
],
"__recordNum": 97665,
"dateFacture": {
"display": "05/12/2023",
"sort": "2023-12-05",
"annee": 2023,
"mois": 12
},
"dateEcheance": {
"display": "04/01/2024",
"sort": "2024-01-04",
"iso": "2024-01-04T00:00:00"
},
"stade": {
"display": "Envoyée",
"minusc": "envoyee"
},
"typeIntervention": {
"Code_rubrique": "TE",
"Valeur_alpha": "MO",
"Nature": 0,
"code": "MO",
"libelle": "Montage"
},
"commettant": {
"libelle": "",
"Valeur_num": 0,
"Valeur_alpha": "",
"Valeur_date": "0000-00-00",
"mois": 0,
"annee": 0,
"jour": 0,
"semaine": 0,
"numIso": "",
"montantEntier": "0",
"montant": "0,00",
"num_ordre": 0
}
},
{
"__KEY": 103510,
"Num_interne": 103510,
"Num_chrono": "FIB11665",
"Nature": "Fact Inter BHS",
"Date1": "2023-12-05",
"Date2": "2024-01-04",
"Montant2": 870,
"Montant3": 870,
"Libelle": "Intervention à distance de notre technicien F. Richard",
"Saisi_par": "slobstein",
"Stade_courant": "Envoyée",
"personne1": {
"Societe": "Test Case Cinéma Français"
},
"mouvementsRubriques": [
{
"Code_rubrique": "RC",
"Valeur_alpha": "17343168"
},
{
"Code_rubrique": "NK",
"Valeur_alpha": "2402594"
},
{
"Code_rubrique": "CB",
"Valeur_alpha": "SERV"
},
{
"Code_rubrique": "FG",
"Valeur_alpha": "-"
},
{
"Code_rubrique": "DT",
"Valeur_alpha": ""
},
{
"Code_rubrique": "CL",
"Valeur_alpha": "-"
},
{
"Code_rubrique": "AR",
"Valeur_alpha": ""
},
{
"Code_rubrique": "TN",
"Valeur_alpha": "FR"
},
{
"Code_rubrique": "TE",
"Valeur_alpha": "AST",
"Nature": 0,
"code": "AST",
"libelle": "Assistance téléphonique"
},
{
"Code_rubrique": "PB",
"Valeur_alpha": "CL"
},
{
"Code_rubrique": "MT",
"Valeur_alpha": "WPA"
}
],
"__recordNum": 97667,
"dateFacture": {
"display": "05/12/2023",
"sort": "2023-12-05",
"annee": 2023,
"mois": 12
},
"dateEcheance": {
"display": "04/01/2024",
"sort": "2024-01-04",
"iso": "2024-01-04T00:00:00"
},
"stade": {
"display": "Envoyée",
"minusc": "envoyee"
},
"typeIntervention": {
"Code_rubrique": "TE",
"Valeur_alpha": "AST",
"Nature": 0,
"code": "AST",
"libelle": "Assistance téléphonique"
},
"commettant": {
"libelle": "",
"Valeur_num": 0,
"Valeur_alpha": "",
"Valeur_date": "0000-00-00",
"mois": 0,
"annee": 0,
"jour": 0,
"semaine": 0,
"numIso": "",
"montantEntier": "0",
"montant": "0,00",
"num_ordre": 0
}
}
];
var contenuColonnes = [
// { data: null, defaultContent: '' }, // colonne 0, class dtr-control pour responsive
{ data: 'Num_interne',
render: function ( data, type, row ) {
return '<a rel="modal:open" href="AJAX/get/mouvement/' + data + '?tcom1=$4DTEXT(WEB_vt_interface)&onglet=details&template=mouvement/details/modal/facture"><i class="fa-solid fa-eye" title="Consulter la facture"></i></a>';
}
},
{ data: 'Num_interne',
render: function ( data, type, row ) {
return '<a rel="modal:open" href="AJAX/get/mouvement/' + data + '?tcom1=$4DTEXT(WEB_vt_interface)&onglet=details&template=mouvement/details/modal/facture"><i class="fa-solid fa-plus" title="Ajouter un règlement"></i></a>';
}
},
{ data: 'Num_interne',
render: function ( data, type, row ) {
return '<a rel="modal:open" href="AJAX/get/mouvement/' + data + '?tcom1=$4DTEXT(WEB_vt_interface)&onglet=details&template=mouvement/details/modal/facture"><i class="fa-solid fa-check" title="Acquitter la facture"></i></a>';
}
},
{ data: 'Nature'},
{ data: 'Stade_courant'},
{ data: 'typeIntervention.libelle' },
{ data: 'Num_chrono' },
{ data: {
_: 'dateFacture',
display: 'dateFacture.display',
sort: 'dateFacture.sort'
}
},
{ data: 'personne1.Societe' },
{ data: 'commettant.libelle' },
{ data: 'dateEcheance',
render: function ( data, type, row ) {
var dateEcheance = DateTime.fromISO(data.sort);
if ( dateEcheance < today ) {
var style = 'indianred';
} else {
var style= '-';
}
return '<span class="' + style + '">' + data.display + '</span>';
}
},
{ data: 'Montant2' },
{ data: 'Montant3' },
// colonnes masquées utilisées pour les filtres
{ data: 'dateFacture.annee' },
{ data: 'dateFacture.mois' },
// colonnes masquées utilisées pour calcul totaux + compteurs factures échues / non échues
{ data: null,
render: function ( data, type, row ) {
var dateEcheance = DateTime.fromISO(row['dateEcheance'].sort);
if ( dateEcheance < today ) {
return row['Montant3'];
} else {
return 0;
}
}
},
{ data: null,
render: function ( data, type, row ) {
var dateEcheance = DateTime.fromISO(row['dateEcheance'].sort);
if ( dateEcheance < today ) {
return 1 ;
} else {
return 0;
}
}
},
{ data: null,
render: function ( data, type, row ) {
var dateEcheance = DateTime.fromISO(row['dateEcheance'].sort);
if ( dateEcheance >= today ) {
return row['Montant3'];
} else {
return 0;
}
}
},
{ data: null,
render: function ( data, type, row ) {
var dateEcheance = DateTime.fromISO(row['dateEcheance'].sort);
if ( dateEcheance >= today ) {
return 1 ;
} else {
return 0;
}
}
}
];
var table = new DataTable('#liste_factures', {
data: dataSet,
columns: contenuColonnes,
fixedHeader: true,
processing: true,
pageLength: -1,
layout: {
// top2: 'searchPanes',
top: function () {
let toolbar = document.createElement('div');
toolbar.innerHTML = '<p class="font12rem has-text-centered smallcaps has-text-weight-medium">total en-cours : <span id="head_total_en_cours"></span> <span id="head_count_total" class="parentheses has-text-weight-light"></span><span class="indianred ml-5">échues : </span> <span id="head_total_echues" class="indianred"></span> <span id="head_count_echues" class="parentheses has-text-weight-light indianred"></span><span class="olivedrab ml-5">non échues : </span> <span id="head_total_non_echues" class="olivedrab"></span> <span id="head_count_non_echues" class="parentheses has-text-weight-light olivedrab"></span></p>';
return toolbar;
},
topStart: {
buttons: ['copy', 'csv', 'excel', 'pdf', 'print']
}
},
/* searchPanes: {
columns: [13, 3, 5, 4],
cascadePanes: true
},*/
drawCallback: function () {
var api = this.api();
var pageInfo = api.page.info();
var en_cours = 0;
var count_total = 0;
var echues = 0;
var non_echues = 0;
var count_echues = 0;
var count_non_echues = 0;
var en_cours_txt = '';
var echues_txt = '';
var count_echues_txt = '';
var non_echues_txt = '';
var count_non_echues_txt = '';
api.rows({search: 'applied'}).every( function ( rowIdx, tableLoop, rowLoop ) {
var data = this.data();
var restant_du = data['Montant3'];
var echeance = DateTime.fromISO(data['dateEcheance'].sort);
en_cours += restant_du;
count_total = pageInfo.recordsDisplay;
if (count_total > 1) {
count_total_txt = count_total + ' factures';
} else {
count_total = count_total + ' facture';
}
if ( echeance < today ) {
echues += restant_du;
count_echues += 1;
} else if ( echeance >= today ) {
non_echues += restant_du;
count_non_echues += 1;
}
en_cours_txt = DataTable.render.number(' ', null, 2, null, ' €').display(en_cours);
echues_txt = DataTable.render.number(' ', null, 2, null, ' €').display(echues);
non_echues_txt = DataTable.render.number(' ', null, 2, null, ' €').display(non_echues);
if (count_echues > 1) {
count_echues_txt = count_echues + ' factures';
} else {
count_echues_txt = count_echues + ' facture';
}
if (count_non_echues > 1) {
count_non_echues_txt = count_non_echues + ' factures';
} else {
count_non_echues_txt = count_non_echues + ' facture';
}
$('#head_total_en_cours').html(en_cours_txt);
$('#head_count_total').html(count_total_txt);
$('#head_total_echues').html(echues_txt);
$('#head_total_non_echues').html(non_echues_txt);
$('#head_count_echues').html(count_echues_txt);
$('#head_count_non_echues').html(count_non_echues_txt);
} );
},
columnDefs: [
// { className: 'dtr-control', targets: [0] },
{ orderable: false, targets: [0, 1, 2] },
{ className: 'icone', targets: [0, 1, 2] },
{ render: DataTable.render.number(' ', ',', 2, '' , ''), targets : [11, 12] }, // decimal
{ className: 'has-text-right', targets: [11, 12] },
{ className: 'white-space-nowrap', targets: [3, 4, 5, 11, 12] }
],
orderFixed: [[13, 'desc'], [14, 'desc']], // tri fixe pour la rupture (dateFacture.annee + mois)
order: [[7, 'desc']], // tri par défaut dans chaque groupe (dateFacture)
responsive: {
details: false
},
rowGroup: {
dataSrc: ['dateFacture.annee', 'dateFacture.mois'],
startClassName: 'rupture has-text-FT',
endClassName: 'soustotal has-text-FT',
startRender: function ( rows, group, level ) {
if (level === 0) {
nameLevel0 = group;
return '<span class="has-text-FT">FACTURES ' + group + '<span class="is-pulled-right">(' + rows.count() + ')</span></span>';
} else {
var monthName = DateTime.local(2000, group, 1).monthLong.toUpperCase();
return '<span class="font95rem has-text-dark">' + monthName + ' ' + nameLevel0 + '<span class="is-pulled-right">(' + rows.count() + ')</span></span>';
}
},
endRender: function ( rows, group, level ) {
// Get instance of Datatables API
var api = $('#liste_factures').DataTable();
if (level === 0) {
nameLevel0 = group;
// TOTAUX PAR ANNÉE (GROUP, LEVEL 0)
var totalRestantDu =
rows
.data()
.pluck('Montant3')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
// Use cells.render() with the row selector of a function
var totalEchues =
api.cells(function ( idx, data, node ) {
return data.dateFacture.annee === group ?
true : false;
}, 15, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var totalCountEchues =
api.cells(function ( idx, data, node ) {
return data.dateFacture.annee === group ?
true : false;
}, 16, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var totalNonEchues =
api.cells(function ( idx, data, node ) {
return data.dateFacture.annee === group ?
true : false;
}, 17, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var totalCountNonEchues =
api.cells(function ( idx, data, node ) {
return data.dateFacture.annee === group ?
true : false;
}, 18, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
totalRestantDu = DataTable.render.number(' ', null, 2, null, '').display(totalRestantDu);
totalEchues = DataTable.render.number(' ', null, 2, null, '').display(totalEchues);
totalCountEchues = DataTable.render.number(' ', null, 0, null, '').display(totalCountEchues);
totalNonEchues = DataTable.render.number(' ', null, 2, null, '').display(totalNonEchues);
totalCountNonEchues = DataTable.render.number(' ', null, 0, null, '').display(totalCountNonEchues);
// affichage total annuel
return $('<tr />')
.append('<td colspan="12" class="has-text-FT has-text-right has-text-weight-semibold white-space-nowrap">TOTAL ' + group +'<br></td>')
.append('<td class="has-text-FT has-text-right white-space-nowrap has-text-weight-semibold">' + totalRestantDu + '<br></td>') ;
} else {
// TOTAUX PAR MOIS (GROUP, LEVEL 1)
var soustotalRestantDu =
rows
.data()
.pluck('Montant3')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
// Use cells.render() with the row selector of a function
var sousTotalEchues =
api.cells(function ( idx, data, node ) {
return (data.dateFacture.mois === group) & (data.dateFacture.annee === nameLevel0) ?
true : false;
}, 15, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var sousTotalCountEchues =
api.cells(function ( idx, data, node ) {
return (data.dateFacture.mois === group) & (data.dateFacture.annee === nameLevel0) ?
true : false;
}, 16, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var sousTotalNonEchues =
api.cells(function ( idx, data, node ) {
return (data.dateFacture.mois === group) & (data.dateFacture.annee === nameLevel0) ?
true : false;
}, 17, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
var sousTotalCountNonEchues =
api.cells(function ( idx, data, node ) {
return (data.dateFacture.mois === group) & (data.dateFacture.annee === nameLevel0) ?
true : false;
}, 18, {search: 'applied'})
.render('display')
.reduce(function (a, b) {
return a + b * 1;
}, 0) ;
soustotalRestantDu = DataTable.render.number(' ', null, 2, null, '').display(soustotalRestantDu);
sousTotalEchues = DataTable.render.number(' ', null, 2, null, '').display(sousTotalEchues);
sousTotalCountEchues = DataTable.render.number(' ', null, 0, null, '').display(sousTotalCountEchues);
sousTotalNonEchues = DataTable.render.number(' ', null, 2, null, '').display(sousTotalNonEchues);
sousTotalCountNonEchues = DataTable.render.number(' ', null, 0, null, '').display(sousTotalCountNonEchues);
var monthName = DateTime.local(2000, group, 1).monthLong.toUpperCase();
// affichage total mensuel
return $('<tr/>')
.append('<td colspan="12" class="has-text-dark has-text-right has-text-weight-semibold white-space-nowrap">TOTAL ' + monthName + ' ' + nameLevel0 + '</td>')
.append('<td class="has-text-dark has-text-right has-text-weight-semibold white-space-nowrap">' + soustotalRestantDu + '</td>');
}
}
},
footerCallback: function (row, data, start, end, display) {
var api = this.api();
var pageInfo = api.page.info();
// TOTAUX (ENSEMBLE DU TABLEAU, APRÈS FILTRES ÉVENTUELS)
var globalRestant = api
.column(12, { page: 'current' })
.data()
.reduce(function (a, b) {
return a + b * 1;
}, 0);
var globalEchues = api
.rows({page: 'current'})
.data()
.filter(row => DateTime.fromISO(row['dateEcheance'].sort) < today)
.reduce((accum, row) => accum + row.Montant3, 0);
var globalCountEchues = api
.rows({page: 'current'})
.data()
.filter(row => DateTime.fromISO(row['dateEcheance'].sort) < today)
.count(row);
var globalNonEchues = api
.rows({page: 'current'})
.data()
.filter(row => DateTime.fromISO(row['dateEcheance'].sort) >= today)
.reduce((accum, row) => accum + row.Montant3, 0);
var globalCountNonEchues = api
.rows({page: 'current'})
.data()
.filter(row => DateTime.fromISO(row['dateEcheance'].sort) >= today)
.count(row);
globalRestant = DataTable.render.number(' ', null, 2, null, '').display(globalRestant);
globalEchues = DataTable.render.number(' ', null, 2, null, '').display(globalEchues);
globalNonEchues = DataTable.render.number(' ', null, 2, null, '').display(globalNonEchues);
globalCountEchues = DataTable.render.number(' ', null, 0, null, '').display(globalCountEchues);
globalCountNonEchues = DataTable.render.number(' ', null, 0, null, '').display(globalCountNonEchues);
var labelTotal = 'TOTAL ' + pageInfo.recordsDisplay + ' FACTURES ';
// update footer
$(api.column(1).footer()).html(labelTotal);
$(api.column(12).footer()).html(globalRestant);
$(api.column(15).footer()).html(globalEchues);
$(api.column(16).footer()).html(globalCountEchues);
$(api.column(17).footer()).html(globalNonEchues);
$(api.column(18).footer()).html(globalCountNonEchues);
}
});
You can jump to the latest bin by adding /latest
to your URL
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + [ | Indents selected lines |
ctrl + ] | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Clone Bin |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |