mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-02-09 04:19:13 +00:00
trabajando en el formulario de la factura
This commit is contained in:
@ -23,6 +23,7 @@ app.logout=Cerrar sesión
|
||||
app.sidebar.inicio=Inicio
|
||||
app.sidebar.presupuestos=Presupuestos
|
||||
app.sidebar.pedidos=Pedidos
|
||||
app.sidebar.facturas=Facturas
|
||||
app.sidebar.configuracion=Configuración
|
||||
app.sidebar.usuarios=Usuarios
|
||||
app.sidebar.direcciones=Mis Direcciones
|
||||
|
||||
0
src/main/resources/i18n/facturas_en.properties
Normal file
0
src/main/resources/i18n/facturas_en.properties
Normal file
24
src/main/resources/i18n/facturas_es.properties
Normal file
24
src/main/resources/i18n/facturas_es.properties
Normal file
@ -0,0 +1,24 @@
|
||||
facturas.title=Facturas
|
||||
facturas.breadcrumb=Facturas
|
||||
facturas.breadcrumb.ver=Ver Factura
|
||||
|
||||
facturas.tabla.id=ID
|
||||
facturas.tabla.cliente=Cliente
|
||||
facturas.tabla.num-factura=Número de Factura
|
||||
facturas.tabla.estado=Estado
|
||||
facturas.tabla.estado-pago=Estado de Pago
|
||||
facturas.tabla.total=Total
|
||||
facturas.tabla.fecha-emision=Fecha de Emisión
|
||||
facturas.tabla.acciones=Acciones
|
||||
|
||||
facturas.estado-pago.pendiente=Pendiente
|
||||
facturas.estado-pago.pagada=Pagada
|
||||
facturas.estado-pago.cancelada=Cancelada
|
||||
|
||||
facturas.estado.borrador=Borrador
|
||||
facturas.estado.validada=Validada
|
||||
|
||||
facturas.delete.title=¿Estás seguro de que deseas eliminar esta factura?
|
||||
facturas.delete.text=Esta acción no se puede deshacer.
|
||||
facturas.delete.ok.title=Factura eliminada
|
||||
facturas.delete.ok.text=La factura ha sido eliminada correctamente.
|
||||
@ -2914,6 +2914,19 @@ File: Main Css File
|
||||
background-color: #0ac7fb !important;
|
||||
}
|
||||
|
||||
.accordion-fill-imprimelibros .accordion-item .accordion-button {
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.accordion-fill-imprimelibros .accordion-item .accordion-button:not(.collapsed) {
|
||||
color: #fff;
|
||||
background-color: #92b2a7 !important;
|
||||
}
|
||||
.accordion-fill-imprimelibros .accordion-item .accordion-button:is(.collapsed) {
|
||||
color: #fff;
|
||||
background-color: #4c5c63 !important;
|
||||
}
|
||||
|
||||
.accordion-warning .accordion-item {
|
||||
border-color: rgba(239, 174, 78, 0.6);
|
||||
}
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
/* global $, bootstrap, window */
|
||||
$(() => {
|
||||
// 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';
|
||||
|
||||
const $table = $('#facturas-datatable'); // en tu HTML está así, aunque el id sea raro
|
||||
const $addBtn = $('#addButton');
|
||||
|
||||
// -----------------------------
|
||||
// DataTable server-side
|
||||
// -----------------------------
|
||||
const dt = $table.DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
searching: true,
|
||||
orderMulti: false,
|
||||
pageLength: 10,
|
||||
lengthMenu: [10, 25, 50, 100],
|
||||
|
||||
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
|
||||
|
||||
ajax: {
|
||||
url: '/facturas/api/datatables',
|
||||
type: 'GET',
|
||||
dataSrc: function (json) {
|
||||
// DataTables espera {draw, recordsTotal, recordsFiltered, data}
|
||||
return json.data || [];
|
||||
},
|
||||
error: function (xhr) {
|
||||
console.error('DataTables error', xhr);
|
||||
}
|
||||
},
|
||||
|
||||
columns: [
|
||||
{ data: 'id' },
|
||||
{ data: 'cliente' },
|
||||
{ data: 'numero_factura' },
|
||||
{ data: 'estado_label', name: 'estado' },
|
||||
{ data: 'estado_pago_label', name: 'estado_pago' },
|
||||
{ data: 'total' },
|
||||
{ data: 'fecha_emision' },
|
||||
{
|
||||
data: 'actions',
|
||||
orderable: false,
|
||||
searchable: false
|
||||
}
|
||||
],
|
||||
|
||||
order: [[0, 'desc']]
|
||||
});
|
||||
|
||||
// -----------------------------
|
||||
// Add
|
||||
// -----------------------------
|
||||
$addBtn.on();
|
||||
|
||||
// -----------------------------
|
||||
// Edit click
|
||||
// -----------------------------
|
||||
$table.on('click', '.btn-view-factura', function () {
|
||||
const row = dt.row($(this).closest('tr')).data();
|
||||
window.location.href = `/facturas/${row.id}`;
|
||||
});
|
||||
|
||||
// -----------------------------
|
||||
// Delete click
|
||||
// -----------------------------
|
||||
$table.on('click', '.btn-delete-factura', function () {
|
||||
const row = dt.row($(this).closest('tr')).data();
|
||||
|
||||
Swal.fire({
|
||||
title: window.languageBundle.get(['facturas.delete.title']) || 'Eliminar factura',
|
||||
html: window.languageBundle.get(['facturas.delete.text']) || 'Esta acción no se puede deshacer.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-danger w-xs mt-2',
|
||||
cancelButton: 'btn btn-light w-xs mt-2'
|
||||
},
|
||||
confirmButtonText: window.languageBundle.get(['app.eliminar']) || 'Eliminar',
|
||||
cancelButtonText: window.languageBundle.get(['app.cancelar']) || 'Cancelar',
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
$.ajax({
|
||||
url: `/facturas/api/${row.id}`,
|
||||
method: 'DELETE',
|
||||
success: function () {
|
||||
Swal.fire({
|
||||
icon: 'success', title: window.languageBundle.get(['facturas.delete.ok.title']) || 'Eliminado',
|
||||
text: window.languageBundle.get(['facturas.delete.ok.text']) || 'La factura ha sido eliminada correctamente.',
|
||||
showConfirmButton: false,
|
||||
timer: 1800,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary w-xs mt-2',
|
||||
},
|
||||
});
|
||||
dt.ajax.reload(null, false);
|
||||
},
|
||||
error: function (xhr) {
|
||||
const msg = (xhr.responseJSON && xhr.responseJSON.message)
|
||||
|| 'Error al eliminar la serie de facturación.';
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'No se pudo eliminar',
|
||||
text: msg,
|
||||
buttonsStyling: false,
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary me-2', // clases para el botón confirmar
|
||||
cancelButton: 'btn btn-light' // clases para cancelar
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
$(() => {
|
||||
|
||||
});
|
||||
@ -0,0 +1,115 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/css/presupuestador.css}" rel="stylesheet"
|
||||
th:unless="${#authorization.expression('isAuthenticated()')}" />
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}" />
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item"><a href="/facturas" th:text="#{facturas.breadcrumb}"></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{facturas.breadcrumb.ver}">
|
||||
Ver factura</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="accordion accordion-fill-imprimelibros mb-3" id="cabeceraFactura">
|
||||
<div class="accordion-item material-shadow">
|
||||
<h2 class="accordion-header" id="cabeceraHeader">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#cabecera" aria-expanded="true" aria-controls="cabecera">
|
||||
Datos de la factura
|
||||
</button>
|
||||
</h2>
|
||||
<div id="cabecera" class="accordion-collapse collapse show" aria-labelledby="cabeceraHeader"
|
||||
data-bs-parent="#cabeceraFactura">
|
||||
<div class="accordion-body">
|
||||
<div th:replace="~{imprimelibros/facturas/partials/factura-cabecera :: factura-cabecera (factura=${factura})}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion accordion-fill-imprimelibros" id="lineasFactura">
|
||||
<div class="accordion-item material-shadow">
|
||||
<h2 class="accordion-header" id="lineasHeader">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#lineas" aria-expanded="true" aria-controls="lineas">
|
||||
Líneas de factura
|
||||
</button>
|
||||
</h2>
|
||||
<div id="lineas" class="accordion-collapse collapse show" aria-labelledby="lineasHeader"
|
||||
data-bs-parent="#lineasFactura">
|
||||
<div class="accordion-body">
|
||||
<!-- <div th:replace="~{imprimelibros/facturas/partials/factura-lineas :: factura-lineas (factura=${factura})}" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion accordion-fill-imprimelibros" id="pagosFactura">
|
||||
<div class="accordion-item material-shadow">
|
||||
<h2 class="accordion-header" id="pagosHeader">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#pagos" aria-expanded="true" aria-controls="pagos">
|
||||
Pagos de factura
|
||||
</button>
|
||||
</h2>
|
||||
<div id="pagos" class="accordion-collapse collapse show" aria-labelledby="pagosHeader"
|
||||
data-bs-parent="#pagosFactura">
|
||||
<div class="accordion-body">
|
||||
<!-- <div th:replace="~{imprimelibros/facturas/partials/factura-cabecera :: factura-cabecera (factura=${factura})}" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="modal" />
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
|
||||
|
||||
<!-- JS de Buttons y dependencias -->
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/facturas/view.js}"></script>
|
||||
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,83 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/css/presupuestador.css}" rel="stylesheet"
|
||||
th:unless="${#authorization.expression('isAuthenticated()')}" />
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}" />
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{facturas.breadcrumb}">
|
||||
Facturas</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<button type="button" class="btn btn-secondary mb-3" id="addButton">
|
||||
<i class="ri-add-line align-bottom me-1"></i> <span
|
||||
th:text="#{app.add}">Añadir</span>
|
||||
</button>
|
||||
|
||||
<table id="facturas-datatable" class="table table-striped table-nowrap responsive w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.id}">ID</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.cliente}">Cliente</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.num-factura}">Número de Factura</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.estado}">Estado</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.estado-pago}">Estado de Pago</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.total}">Total</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.fecha-emision}">Fecha de Emisión</th>
|
||||
<th class="text-start" scope="col" th:text="#{facturas.tabla.acciones}">Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="modal" />
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
|
||||
|
||||
<!-- JS de Buttons y dependencias -->
|
||||
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
|
||||
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/facturas/list.js}"></script>
|
||||
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,56 @@
|
||||
<div th:fragment="factura-cabecera (factura)">
|
||||
|
||||
<h3>
|
||||
<span th:class="|text-${factura.estado.name() == 'borrador' ? 'warning' : 'success'}|"
|
||||
th:text="#{|facturas.estado.${factura.estado.name()}|}">
|
||||
</span>
|
||||
/
|
||||
<span th:class="|text-${factura.estadoPago.name() == 'pendiente' ? 'warning' : 'success'}|"
|
||||
th:text="#{|facturas.estado-pago.${factura.estadoPago.name()}|}">
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<!-- flag readonly -->
|
||||
<th:block th:with="isReadonly=${factura.estado.name() == 'validada'}">
|
||||
|
||||
<div class="row g-3">
|
||||
|
||||
<!-- Número -->
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Número</label>
|
||||
<input type="text" class="form-control" th:value="${factura.numeroFactura}"
|
||||
th:attrappend="readonly=${isReadonly} ? 'readonly' : null">
|
||||
</div>
|
||||
|
||||
<!-- Serie -->
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Serie facturación</label>
|
||||
<input type="text" class="form-control"
|
||||
th:value="${factura.serie != null ? factura.serie.nombreSerie : ''}" readonly>
|
||||
</div>
|
||||
|
||||
<!-- Cliente -->
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Cliente</label>
|
||||
<input type="text" class="form-control" th:value="${factura.cliente.fullName}" readonly>
|
||||
</div>
|
||||
|
||||
<!-- Fecha emisión -->
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Fecha</label>
|
||||
<input type="text" class="form-control" th:value="${factura.fechaEmision != null
|
||||
? #temporals.format(factura.fechaEmision, 'dd/MM/yyyy')
|
||||
: ''}" th:attrappend="readonly=${isReadonly} ? 'readonly' : null">
|
||||
</div>
|
||||
|
||||
<!-- Notas -->
|
||||
<div class="col-md-12">
|
||||
<label class="form-label">Notas</label>
|
||||
<textarea class="form-control" rows="3" th:text="${factura.notas}"
|
||||
th:attrappend="readonly=${isReadonly} ? 'readonly' : null">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</th:block>
|
||||
</div>
|
||||
@ -48,6 +48,11 @@
|
||||
<i class="ri-book-3-line"></i> <span th:text="#{app.sidebar.pedidos}">Pedidos</span>
|
||||
</a>
|
||||
</li>
|
||||
<li th:if="${#authentication.principal.role == 'SUPERADMIN' or #authentication.principal.role == 'ADMIN'}" class="nav-item">
|
||||
<a class="nav-link menu-link" href="/facturas">
|
||||
<i class="ri-bill-line"></i> <span th:text="#{app.sidebar.facturas}">Facturas</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link menu-link" href="/direcciones">
|
||||
<i class="ri-truck-line"></i>
|
||||
|
||||
Reference in New Issue
Block a user