diff --git a/src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedSoftDeleteEntity.java b/src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedEntity.java similarity index 97% rename from src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedSoftDeleteEntity.java rename to src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedEntity.java index 8d6a117..d2227d3 100644 --- a/src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedSoftDeleteEntity.java +++ b/src/main/java/com/imprimelibros/erp/common/jpa/AbstractAuditedEntity.java @@ -13,7 +13,7 @@ import com.imprimelibros.erp.users.User; @MappedSuperclass @EntityListeners(AuditingEntityListener.class) -public abstract class AbstractAuditedSoftDeleteEntity { +public abstract class AbstractAuditedEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/imprimelibros/erp/configuracion/margenes_presupuestos/MargenPresupuestoController.java b/src/main/java/com/imprimelibros/erp/configuracion/margenes_presupuestos/MargenPresupuestoController.java index d232b92..9b55d34 100644 --- a/src/main/java/com/imprimelibros/erp/configuracion/margenes_presupuestos/MargenPresupuestoController.java +++ b/src/main/java/com/imprimelibros/erp/configuracion/margenes_presupuestos/MargenPresupuestoController.java @@ -16,7 +16,6 @@ import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; diff --git a/src/main/java/com/imprimelibros/erp/home/HomeController.java b/src/main/java/com/imprimelibros/erp/home/HomeController.java index a42041c..572b17a 100644 --- a/src/main/java/com/imprimelibros/erp/home/HomeController.java +++ b/src/main/java/com/imprimelibros/erp/home/HomeController.java @@ -48,6 +48,6 @@ public class HomeController { Map translations = Map.of(); model.addAttribute("languageBundle", translations); } - return "imprimelibros/home"; + return "imprimelibros/home/home"; } } diff --git a/src/main/java/com/imprimelibros/erp/presupuesto/Presupuesto.java b/src/main/java/com/imprimelibros/erp/presupuesto/Presupuesto.java index 00dbb63..972ca44 100644 --- a/src/main/java/com/imprimelibros/erp/presupuesto/Presupuesto.java +++ b/src/main/java/com/imprimelibros/erp/presupuesto/Presupuesto.java @@ -9,19 +9,15 @@ import com.imprimelibros.erp.presupuesto.validation.PresupuestoValidationGroups; import com.imprimelibros.erp.presupuesto.validation.Tamanio; import com.imprimelibros.erp.common.HtmlStripConverter; -import com.imprimelibros.erp.common.jpa.AbstractAuditedSoftDeleteEntity; +import com.imprimelibros.erp.common.jpa.AbstractAuditedEntity; import jakarta.persistence.*; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.SQLRestriction; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import java.math.BigDecimal; -import java.time.Instant; import com.imprimelibros.erp.users.User; @@ -38,7 +34,7 @@ import com.imprimelibros.erp.users.User; }) @SQLDelete(sql = "UPDATE presupuesto SET deleted = 1, deleted_at = NOW(3) WHERE id = ?") @SQLRestriction("deleted = 0") -public class Presupuesto extends AbstractAuditedSoftDeleteEntity implements Cloneable { +public class Presupuesto extends AbstractAuditedEntity implements Cloneable { public enum TipoEncuadernacion { fresado("presupuesto.fresado"), diff --git a/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoController.java b/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoController.java index 045c7ee..944dd3f 100644 --- a/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoController.java +++ b/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoController.java @@ -3,18 +3,23 @@ package com.imprimelibros.erp.presupuesto; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import java.util.Arrays; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; +import org.springframework.data.jpa.domain.Specification; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; @@ -23,7 +28,15 @@ import org.springframework.http.MediaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.type.TypeReference; +import com.imprimelibros.erp.configuracion.margenes_presupuestos.MargenPresupuesto; +import com.imprimelibros.erp.datatables.DataTable; +import com.imprimelibros.erp.datatables.DataTablesParser; +import com.imprimelibros.erp.datatables.DataTablesRequest; +import com.imprimelibros.erp.datatables.DataTablesResponse; import com.imprimelibros.erp.externalApi.skApiClient; +import com.imprimelibros.erp.i18n.TranslationService; +import com.imprimelibros.erp.presupuesto.Presupuesto.TipoCubierta; +import com.imprimelibros.erp.presupuesto.Presupuesto.TipoEncuadernacion; import com.imprimelibros.erp.presupuesto.classes.ImagenPresupuesto; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMaquetacion; import com.imprimelibros.erp.presupuesto.classes.PresupuestoMarcapaginas; @@ -46,9 +59,14 @@ public class PresupuestoController { protected MessageSource messageSource; private final ObjectMapper objectMapper; + private final TranslationService translationService; + private final PresupuestoRepository repo; - public PresupuestoController(ObjectMapper objectMapper) { + public PresupuestoController(ObjectMapper objectMapper, TranslationService translationService, + PresupuestoRepository repo) { this.objectMapper = objectMapper; + this.translationService = translationService; + this.repo = repo; } @PostMapping("/public/validar/datos-generales") @@ -407,4 +425,68 @@ public class PresupuestoController { return ResponseEntity.ok(resumen); } + // ============================================= + // MÉTODOS PARA USUARIOS AUTENTICADOS + // ============================================= + @GetMapping + public String getPresupuestoView(Model model, Authentication authentication, Locale locale) { + + List keys = List.of(); + + Map translations = translationService.getTranslations(locale, keys); + model.addAttribute("languageBundle", translations); + + return "imprimelibros/presupuestos/presupuesto-list"; + } + + @GetMapping(value = "/datatable/{tipo}", produces = "application/json") + @ResponseBody + public DataTablesResponse> datatable(@RequestParam("tipo") String tipo, + HttpServletRequest request, Authentication authentication, + Locale locale) { + + DataTablesRequest dt = DataTablesParser.from(request); + + List searchable = List.of( + "id", + "titulo", + "cliente", + "tipoEncuadernacion", + "tipoCubierta", + "tipoImpresion", + "tirada", + "paginas", + "estado", "total", "pais", "region", "ciudad", "updatedAt"); + + List orderable = List.of(/* + * "id", + * "tipoEncuadernacion", + * "tipoCubierta", + * "tiradaMin", + * "tiradaMax", + * "margenMin", + * "margenMax" + */); + + Specification base = (root, query, cb) -> cb.conjunction(); + long total = repo.count(); + + return DataTable + .of(repo, MargenPresupuesto.class, dt, searchable) // 'searchable' en DataTable.java + // edita columnas "reales": + .orderable(orderable) + .add("actions", (presupuesto) -> { + return "
\n" + + " \n" + + " \n" + + "
"; + }) + .where(base) + .toJson(total); + } + } diff --git a/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoRepository.java b/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoRepository.java index 7a4ec33..a9d42f4 100644 --- a/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoRepository.java +++ b/src/main/java/com/imprimelibros/erp/presupuesto/PresupuestoRepository.java @@ -1,14 +1,17 @@ package com.imprimelibros.erp.presupuesto; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import com.imprimelibros.erp.configuracion.margenes_presupuestos.MargenPresupuesto; + import java.util.*; @Repository -public interface PresupuestoRepository extends JpaRepository { +public interface PresupuestoRepository extends JpaRepository, JpaSpecificationExecutor { Optional findFirstBySessionIdAndOrigenAndEstadoInOrderByUpdatedAtDesc( String sessionId, diff --git a/src/main/resources/i18n/app_es.properties b/src/main/resources/i18n/app_es.properties index 1043a15..0fff1f0 100644 --- a/src/main/resources/i18n/app_es.properties +++ b/src/main/resources/i18n/app_es.properties @@ -14,5 +14,6 @@ app.mensajes=Mensajes app.logout=Cerrar sesión app.sidebar.inicio=Inicio -app.sidebar.usuarios=Usuarios -app.sidebar.configuracion=Configuración \ No newline at end of file +app.sidebar.presupuestos=Presupuestos +app.sidebar.configuracion=Configuración +app.sidebar.usuarios=Usuarios \ No newline at end of file diff --git a/src/main/resources/i18n/presupuesto_es.properties b/src/main/resources/i18n/presupuesto_es.properties index 38984bf..fd3ab82 100644 --- a/src/main/resources/i18n/presupuesto_es.properties +++ b/src/main/resources/i18n/presupuesto_es.properties @@ -1,3 +1,4 @@ +presupuesto.title=Presupuestos presupuesto.datos-generales=Datos Generales presupuesto.interior=Interior presupuesto.cubierta=Cubierta @@ -6,6 +7,26 @@ presupuesto.extras=Extras presupuesto.resumen=Resumen presupuesto.add-to-presupuesto=Añadir al presupuesto presupuesto.calcular=Calcular +presupuesto.add=Añadir presupuesto + +presupuesto.nav.presupuestos-cliente=Presupuestos cliente +presupuesto.nav.presupuestos-anonimos=Presupuestos anónimos + +presupuesto.tabla.id=ID +presupuesto.tabla.titulo=Título +presupuesto.tabla.cliente=Cliente +presupuesto.tabla.encuadernacion=Encuadernación +presupuesto.tabla.cubierta=Cubierta +presupuesto.tabla.tipo-impresion=Tipo de impresión +presupuesto.tabla.tirada=Tirada +presupuesto.tabla.paginas=Páginas +presupuesto.tabla.estado=Estado +presupuesto.tabla.total-iva=Total (con IVA) +presupuesto.tabla.updated-at=Actualizado el +presupuesto.tabla.pais=País +presupuesto.tabla.region=Región +presupuesto.tabla.ciudad=Ciudad +presupuesto.tabla.acciones=Acciones # Pestaña datos generales de presupuesto presupuesto.informacion-libro=Información del libro diff --git a/src/main/resources/static/assets/css/app.css b/src/main/resources/static/assets/css/app.css index ef5ddfd..8475747 100644 --- a/src/main/resources/static/assets/css/app.css +++ b/src/main/resources/static/assets/css/app.css @@ -928,7 +928,7 @@ File: Main Css File font-family: "Public Sans", sans-serif; } .navbar-menu .navbar-nav .nav-sm .nav-link:before { - content: ""; + content: none; width: 6px; height: 1.5px; background-color: var(--vz-vertical-menu-sub-item-color); @@ -6714,6 +6714,38 @@ a { border-left-color: #ff7f5d; } +/* ---- NAV SECUNDARIO CON PESTAÑITA OUTLINE ---- */ +/* Solo la pestaña activa: estilo outline + pestañita */ +.nav-secondary-outline.arrow-navtabs .nav-link.active { + color: #ff7f5d; + background: transparent; + border: 1px solid #ff7f5d; /* como el botón Iniciar sesión */ + border-radius: .5rem; + position: relative; +} + +/* Si el tema ya dibuja una flecha sólida, la anulamos */ +.nav-secondary-outline.arrow-navtabs .nav-link.active::before { + display: none !important; +} + +/* Pestañita tipo outline */ +.nav-secondary-outline.arrow-navtabs .nav-link.active::after { + content: ""; + position: absolute; + left: 50%; + bottom: -7px; /* ajusta si lo necesitas */ + width: 12px; + height: 12px; + transform: translateX(-50%) rotate(225deg); + background: var(--vz-body-bg, var(--bs-body-bg, #fff)); /* color del fondo de la página */ + border-left: 1px solid #ff7f5d; + border-top: 1px solid #ff7f5d; + z-index: 2; +} + + + .nav-success .nav-link.active { color: #fff; background-color: #3cd188; @@ -16329,4 +16361,5 @@ span.flatpickr-weekday { position: absolute; bottom: -18px; left: -35px; -} \ No newline at end of file +} + diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js b/src/main/resources/static/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js index 2e71a67..d64e264 100644 --- a/src/main/resources/static/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js +++ b/src/main/resources/static/assets/js/pages/imprimelibros/configuracion/margenes-presupuesto/list.js @@ -26,6 +26,22 @@ pageLength: 50, language: { url: '/assets/libs/datatables/i18n/' + language + '.json' }, responsive: true, + dom: 'Bfrtip', + buttons: { + dom: { + button: { + className: 'btn btn-sm btn-outline-primary me-1' + }, + buttons: [ + { extend: 'copy' }, + { extend: 'csv' }, + { extend: 'excel' }, + { extend: 'pdf' }, + { extend: 'print' }, + { extend: 'colvis' } + ], + } + }, ajax: { url: '/configuracion/margenes-presupuesto/datatable', method: 'GET', diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js index a02cdca..3f72566 100644 --- a/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js +++ b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestador/presupuestador.js @@ -216,6 +216,7 @@ class PresupuestoCliente { if (tabButton) { bootstrap.Tab.getOrCreateInstance(tabButton).show(); } + window.scrollTo({ top: 0, behavior: 'smooth' }); } #getPresupuestoData() { diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/presupuestos/list.js b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestos/list.js new file mode 100644 index 0000000..5ebe0c7 --- /dev/null +++ b/src/main/resources/static/assets/js/pages/imprimelibros/presupuestos/list.js @@ -0,0 +1,75 @@ +(() => { + // si jQuery está cargado, añade CSRF a AJAX + const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content'); + const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content'); + if (window.$ && csrfToken && csrfHeader) { + $.ajaxSetup({ + beforeSend: function (xhr) { + xhr.setRequestHeader(csrfHeader, csrfToken); + } + }); + } + + const language = document.documentElement.lang || 'es-ES'; + + // Comprueba dependencias antes de iniciar + if (!window.DataTable) { + console.error('DataTables no está cargado aún'); + return; + } + + const table_anonimos = new DataTable('#presupuestos-anonimos-datatable', { + processing: true, + serverSide: true, + orderCellsTop: true, + stateSave: true, + pageLength: 50, + language: { url: '/assets/libs/datatables/i18n/' + language + '.json' }, + responsive: true, + dom: 'Bfrtip', + buttons: { + dom: { + button: { + className: 'btn btn-sm btn-outline-primary me-1' + }, + buttons: [ + { extend: 'copy' }, + { extend: 'csv' }, + { extend: 'excel' }, + { extend: 'pdf' }, + { extend: 'print' }, + { extend: 'colvis' } + ], + } + }, + ajax: { + url: '/presupuesto/datatable/anonimos', + method: 'GET', + data: function (d) { + d.f_encuadernacion = $('#search-encuadernacion').val() || ''; // 'USER' | 'ADMIN' | 'SUPERADMIN' | '' + d.f_cubierta = $('#search-cubierta').val() || ''; // 'true' | 'false' | '' + } + }, + order: [[0, 'asc']], + columns: [ + { data: 'id', name: 'id', orderable: true }, + { data: 'cliente', name: 'cliente', orderable: true }, + { data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', orderable: true }, + { data: 'tipoCubierta', name: 'tipoCubierta', orderable: true }, + { data: 'tipoImpresion', name: 'tipoImpresion', orderable: true }, + { data: 'tirada', name: 'tirada', orderable: true }, + { data: 'paginas', name: 'paginas', orderable: true }, + { data: 'estado', name: 'estado', orderable: true }, + { data: 'total', name: 'total', orderable: true }, + { data: 'pais', name: 'pais', orderable: true }, + { data: 'region', name: 'region', orderable: true }, + { data: 'ciudad', name: 'ciudad', orderable: true }, + { data: 'updatedAt', name: 'updatedAt', orderable: true }, + { data: 'actions', name: 'actions' } + ], + columnDefs: [{ targets: -1, orderable: false, searchable: false }] + }); + + + +})(); diff --git a/src/main/resources/static/assets/js/pages/imprimelibros/users/list.js b/src/main/resources/static/assets/js/pages/imprimelibros/users/list.js index 8d5abb5..1e3bdfb 100644 --- a/src/main/resources/static/assets/js/pages/imprimelibros/users/list.js +++ b/src/main/resources/static/assets/js/pages/imprimelibros/users/list.js @@ -19,6 +19,22 @@ $(() => { pageLength: 50, language: { url: '/assets/libs/datatables/i18n/' + language + '.json' }, responsive: true, + dom: 'Bfrtip', + buttons: { + dom: { + button: { + className: 'btn btn-sm btn-outline-primary me-1' + }, + buttons: [ + { extend: 'copy' }, + { extend: 'csv' }, + { extend: 'excel' }, + { extend: 'pdf' }, + { extend: 'print' }, + { extend: 'colvis' } + ], + } + }, ajax: { url: '/users/datatable', method: 'GET', diff --git a/src/main/resources/static/assets/libs/datatables/buttons.colVis.min.js b/src/main/resources/static/assets/libs/datatables/buttons.colVis.min.js new file mode 100644 index 0000000..ca50658 --- /dev/null +++ b/src/main/resources/static/assets/libs/datatables/buttons.colVis.min.js @@ -0,0 +1,5 @@ +/*! + * Column visibility buttons for Buttons and DataTables. + * © SpryMedia Ltd - datatables.net/license + */ +!function(i){var o,e;"function"==typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(n){return i(n,window,document)}):"object"==typeof exports?(o=require("jquery"),e=function(n,t){t.fn.dataTable||require("datatables.net")(n,t),t.fn.dataTable.Buttons||require("datatables.net-buttons")(n,t)},"undefined"==typeof window?module.exports=function(n,t){return n=n||window,t=t||o(n),e(n,t),i(t,0,n.document)}:(e(window,o),module.exports=i(o,window,window.document))):i(jQuery,window,document)}(function(n,t,i){"use strict";var e=n.fn.dataTable;return n.extend(e.ext.buttons,{colvis:function(n,t){var i=null,o={extend:"collection",init:function(n,t){i=t},text:function(n){return n.i18n("buttons.colvis","Column visibility")},className:"buttons-colvis",closeButton:!1,buttons:[{extend:"columnsToggle",columns:t.columns,columnText:t.columnText}]};return n.on("column-reorder.dt"+t.namespace,function(){n.button(null,n.button(null,i).node()).collectionRebuild([{extend:"columnsToggle",columns:t.columns,columnText:t.columnText}])}),o},columnsToggle:function(n,t){return n.columns(t.columns).indexes().map(function(n){return{extend:"columnToggle",columns:n,columnText:t.columnText}}).toArray()},columnToggle:function(n,t){return{extend:"columnVisibility",columns:t.columns,columnText:t.columnText}},columnsVisibility:function(n,t){return n.columns(t.columns).indexes().map(function(n){return{extend:"columnVisibility",columns:n,visibility:t.visibility,columnText:t.columnText}}).toArray()},columnVisibility:{columns:void 0,text:function(n,t,i){return i._columnText(n,i)},className:"buttons-columnVisibility",action:function(n,t,i,o){var t=t.columns(o.columns),e=t.visible();t.visible(void 0!==o.visibility?o.visibility:!(e.length&&e[0]))},init:function(e,n,t){var u=this,l=e.column(t.columns);n.attr("data-cv-idx",t.columns),e.on("column-visibility.dt"+t.namespace,function(n,t,i,o){l.index()!==i||t.bDestroying||t.nTable!=e.settings()[0].nTable||u.active(o)}).on("column-reorder.dt"+t.namespace,function(){t.destroying||1===e.columns(t.columns).count()&&(l=e.column(t.columns),u.text(t._columnText(e,t)),u.active(l.visible()))}),this.active(l.visible())},destroy:function(n,t,i){n.off("column-visibility.dt"+i.namespace).off("column-reorder.dt"+i.namespace)},_columnText:function(n,t){var i,o;return"string"==typeof t.text?t.text:(o=n.column(t.columns).title(),i=n.column(t.columns).index(),o=o.replace(/\n/g," ").replace(//gi," ").replace(//gi,""),o=e.Buttons.stripHtmlComments(o),o=e.util.stripHtml(o).trim(),t.columnText?t.columnText(n,i,o):o)}},colvisRestore:{className:"buttons-colvisRestore",text:function(n){return n.i18n("buttons.colvisRestore","Restore visibility")},init:function(n,t,i){n.columns().every(function(){var n=this.init();void 0===n.__visOriginal&&(n.__visOriginal=this.visible())})},action:function(n,t,i,o){t.columns().every(function(n){var t=this.init();this.visible(t.__visOriginal)})}},colvisGroup:{className:"buttons-colvisGroup",action:function(n,t,i,o){t.columns(o.show).visible(!0,!1),t.columns(o.hide).visible(!1,!1),t.columns.adjust()},show:[],hide:[]}}),e}); \ No newline at end of file diff --git a/src/main/resources/static/assets/libs/datatables/buttons.html5.min.js b/src/main/resources/static/assets/libs/datatables/buttons.html5.min.js new file mode 100644 index 0000000..0fb8ffc --- /dev/null +++ b/src/main/resources/static/assets/libs/datatables/buttons.html5.min.js @@ -0,0 +1,8 @@ +/*! + * HTML5 export buttons for Buttons and DataTables. + * © SpryMedia Ltd - datatables.net/license + * + * FileSaver.js (1.3.3) - MIT license + * Copyright © 2016 Eli Grey - http://eligrey.com + */ +!function(o){var l,n;"function"==typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(t){return o(t,window,document)}):"object"==typeof exports?(l=require("jquery"),n=function(t,e){e.fn.dataTable||require("datatables.net")(t,e),e.fn.dataTable.Buttons||require("datatables.net-buttons")(t,e)},"undefined"==typeof window?module.exports=function(t,e){return t=t||window,e=e||l(t),n(t,e),o(e,t,t.document)}:(n(window,l),module.exports=o(l,window,window.document))):o(jQuery,window,document)}(function(S,C,u){"use strict";var e,o,t=S.fn.dataTable;function T(){return e||C.JSZip}function s(){return o||C.pdfMake}t.Buttons.pdfMake=function(t){if(!t)return s();o=t},t.Buttons.jszip=function(t){if(!t)return T();e=t};function k(t){var e="Sheet1";return e=t.sheetName?t.sheetName.replace(/[\[\]\*\/\\\?\:]/g,""):e}function c(t,e){function o(t){for(var e="",o=0,l=t.length;o',"xl/_rels/workbook.xml.rels":'',"[Content_Types].xml":'',"xl/workbook.xml":'',"xl/worksheets/sheet1.xml":'',"xl/styles.xml":''},$=[{match:/^\-?\d+\.\d%$/,style:60,fmt:function(t){return t/100}},{match:/^\-?\d+\.?\d*%$/,style:56,fmt:function(t){return t/100}},{match:/^\-?\$[\d,]+.?\d*$/,style:57},{match:/^\-?£[\d,]+.?\d*$/,style:58},{match:/^\-?€[\d,]+.?\d*$/,style:59},{match:/^\-?\d+$/,style:65},{match:/^\-?\d+\.\d{2}$/,style:66},{match:/^\([\d,]+\)$/,style:61,fmt:function(t){return-1*t.replace(/[\(\)]/g,"")}},{match:/^\([\d,]+\.\d{2}\)$/,style:62,fmt:function(t){return-1*t.replace(/[\(\)]/g,"")}},{match:/^\-?[\d,]+$/,style:63},{match:/^\-?[\d,]+\.\d{2}$/,style:64},{match:/^(19\d\d|[2-9]\d\d\d)\-(0\d|1[012])\-[0123][\d]$/,style:67,fmt:function(t){return Math.round(25569+Date.parse(t)/864e5)}}];return t.ext.buttons.copyHtml5={className:"buttons-copy buttons-html5",text:function(t){return t.i18n("buttons.copy","Copy")},action:function(t,e,o,l,n){var r=c(e,l),a=e.buttons.exportInfo(l),d=y(l),p=r.str,i=S("
").css({height:1,width:1,overflow:"hidden",position:"fixed",top:0,left:0}),d=(a.title&&(p=a.title+d+d+p),a.messageTop&&(p=a.messageTop+d+d+p),a.messageBottom&&(p=p+d+d+a.messageBottom),l.customize&&(p=l.customize(p,l,e)),S("