preparando el imprimir

This commit is contained in:
2025-10-12 21:42:04 +02:00
parent 6641c1f077
commit 26c2ca543a
41 changed files with 1325 additions and 208 deletions

View File

@ -1,9 +1,14 @@
import PresupuestoWizard from './wizard.js';
if($('#presupuesto_id').val() == null || $('#presupuesto_id').val() === '') {
sessionStorage.removeItem('formData');
}
const app = new PresupuestoWizard({
mode: 'private',
readonly: false,
presupuestoId: $('#presupuesto_id').val(),
canSave: true,
useSessionCache: false,
useSessionCache: true,
});
app.init();

View File

@ -1,5 +1,8 @@
import PresupuestoWizard from './wizard.js';
// remove formData from sessionStorage to avoid conflicts
sessionStorage.removeItem('formData');
const app = new PresupuestoWizard({
mode: 'public',
readonly: false,

View File

@ -4,6 +4,6 @@ const app = new PresupuestoWizard({
mode: 'public',
readonly: true,
canSave: false,
useSessionCache: false,
useSessionCache: true,
});
app.init();

View File

@ -180,6 +180,8 @@ export default class PresupuestoWizard {
async init() {
const self = this;
$.ajaxSetup({
beforeSend: function (xhr) {
const token = document.querySelector('meta[name="_csrf"]')?.content;
@ -190,7 +192,7 @@ export default class PresupuestoWizard {
const root = document.getElementById('presupuesto-app');
const mode = root?.dataset.mode || 'public';
const presupuestoId = root?.dataset.id || null;
const presupuestoId = this.opts.presupuestoId || null;
let stored = null;
if (this.opts.useSessionCache) {
@ -249,26 +251,19 @@ export default class PresupuestoWizard {
const alert = $('#form-errors');
const servicios = [];
$('.service-checkbox:checked').each(function () {
const $servicio = $(this);
servicios.push({
id: $servicio.attr('id') ?? $(`label[for="${$servicio.attr('id')}"] .service-title`).text().trim(),
label: $(`label[for="${$servicio.attr('id')}"] .service-title`).text().trim(),
units: $servicio.attr('id') === 'marcapaginas' ? self.formData.servicios.datosMarcapaginas.marcapaginas_tirada : 1,
price: $servicio.data('price') ?? $(`label[for="${$servicio.attr('id')}"] .service-price`).text().trim().replace(" " + self.divExtras.data('currency'), ''),
});
});
const payload = {
id: this.opts.presupuestoId,
mode: this.opts.mode,
presupuesto: this.#getPresupuestoData(),
servicios: servicios,
servicios: this.formData.servicios.servicios,
datosMaquetacion: this.formData.servicios.datosMaquetacion,
datosMarcapaginas: this.formData.servicios.datosMarcapaginas,
cliente_id: $('#cliente_id').val() || null,
};
try {
alert.addClass('d-none').find('ul').empty();
$.ajax({
url: '/presupuesto/save',
url: '/presupuesto/api/save',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(payload)
@ -341,7 +336,7 @@ export default class PresupuestoWizard {
...this.#getInteriorData(),
...this.#getCubiertaData(),
selectedTirada: this.formData.selectedTirada
};
@ -501,6 +496,18 @@ export default class PresupuestoWizard {
$('.alto-faja-max').text(`max: ${this.formData.datosGenerales.alto} mm`);
// check if selected tirada is still valid
const tiradas = [
parseInt(this.formData.datosGenerales.tirada1),
parseInt(this.formData.datosGenerales.tirada2) || 0,
parseInt(this.formData.datosGenerales.tirada3) || 0,
parseInt(this.formData.datosGenerales.tirada4) || 0,
].filter(t => t > 0).sort((a, b) => a - b);
if (!tiradas.includes(this.formData.selectedTirada)) {
this.formData.selectedTirada = tiradas[0];
}
this.#loadInteriorData(data);
const interiorData = this.#getInteriorData();
@ -1592,7 +1599,14 @@ export default class PresupuestoWizard {
const $target = $(e.currentTarget);
if ($target.prop('checked')) {
this.formData.servicios.servicios.push($target.val());
this.formData.servicios.servicios.push(
$target.val(),
{
id: $target.attr('id') ?? $(`label[for="${$target.attr('id')}"] .service-title`).text().trim(),
label: $(`label[for="${$target.attr('id')}"] .service-title`).text().trim(),
units: $target.attr('id') === 'marcapaginas' ? self.formData.servicios.datosMarcapaginas.marcapaginas_tirada : 1,
price: $target.data('price') ?? $(`label[for="${$target.attr('id')}"] .service-price`).text().trim().replace(" " + self.divExtras.data('currency'), ''),
});
} else {
const index = this.formData.servicios.servicios.indexOf($target.val());
if (index > -1) {
@ -1615,7 +1629,7 @@ export default class PresupuestoWizard {
this.divExtras.addClass('animate-fadeInUpBounce');
for (const extra of servicios) {
if (this.formData.servicios.servicios.includes(extra.id) && !extra.checked) {
if (this.formData.servicios.servicios.some(s => s.id === extra.id) && !extra.checked) {
extra.checked = true;
if (extra.id === "marcapaginas" || extra.id === "maquetacion") {
extra.price = extra.id === "marcapaginas" ?
@ -1626,11 +1640,6 @@ export default class PresupuestoWizard {
}
const item = new ServiceOptionCard(extra);
this.divExtras.append(item.render());
if (item.checked) {
if (!this.formData.servicios.servicios.includes(extra.id)) {
this.formData.servicios.servicios.push(extra.id);
}
}
}
this.#cacheFormData();

View File

@ -0,0 +1,151 @@
(() => {
// 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 = new DataTable('#presupuestos-clientes-user-datatable', {
processing: true,
serverSide: true,
orderCellsTop: true,
pageLength: 50,
lengthMenu: [10, 25, 50, 100, 500],
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
responsive: true,
dom: 'lBrtip',
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/clientes',
method: 'GET',
},
order: [[0, 'asc']],
columns: [
{ data: 'id', name: 'id', orderable: true },
{ data: 'titulo', name: 'titulo', orderable: true },
{ data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', orderable: true },
{ data: 'tipoCubierta', name: 'tipoCubierta', orderable: true },
{ data: 'tipoImpresion', name: 'tipoImpresion', orderable: true },
{ data: 'selectedTirada', name: 'selectedTirada', orderable: true },
{ data: 'paginas', name: 'paginas', orderable: true },
{ data: 'estado', name: 'estado', orderable: true },
{ data: 'totalConIva', name: 'totalConIva', orderable: true },
{ data: 'updatedAt', name: 'updatedAt', orderable: true },
{ data: 'actions', orderable: false, searchable: false }
],
});
$('#presupuestos-clientes-user-datatable').on('click', '.btn-edit-privado', function (e) {
e.preventDefault();
const id = $(this).data('id');
if (id) {
window.location.href = '/presupuesto/edit/' + id;
}
});
$('#presupuestos-clientes-user-datatable').on('click', '.btn-delete-privado', function (e) {
e.preventDefault();
const id = $(this).data('id');
Swal.fire({
title: window.languageBundle.get(['presupuesto.delete.title']) || 'Eliminar presupuesto',
html: window.languageBundle.get(['presupuesto.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(['presupuesto.delete.button']) || 'Eliminar',
cancelButtonText: window.languageBundle.get(['app.cancelar']) || 'Cancelar',
}).then((result) => {
if (!result.isConfirmed) return;
$.ajax({
url: '/presupuesto/' + id,
type: 'DELETE',
success: function () {
Swal.fire({
icon: 'success', title: window.languageBundle.get(['presupuesto.delete.ok.title']) || 'Eliminado',
text: window.languageBundle.get(['presupuesto.delete.ok.text']) || 'El presupuesto ha sido eliminado con éxito.',
showConfirmButton: true,
customClass: {
confirmButton: 'btn btn-secondary w-xs mt-2',
},
});
$('#presupuestos-anonimos-datatable').DataTable().ajax.reload(null, false);
},
error: function (xhr) {
// usa el mensaje del backend; fallback genérico por si no llega JSON
const msg = (xhr.responseJSON && xhr.responseJSON.message)
|| 'Error al eliminar el presupuesto.';
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
},
});
}
});
});
});
$('#presupuestos-clientes-user-datatable').on('keyup', '.presupuesto-filter', function (e) {
const colName = $(this).data('col');
const colIndex = table.column(colName + ':name').index();
if (table.column(colIndex).search() !== this.value) {
table.column(colIndex).search(this.value).draw();
}
});
$('#presupuestos-clientes-user-datatable').on('change', '.presupuesto-select-filter', function (e) {
const name = $(this).data('col');
const colIndex = table.column(name + ':name').index();
if (table.column(colIndex).search() !== this.value) {
table.column(colIndex).search(this.value).draw();
}
});
$('#addPresupuestoButton').on('click', async function (e) {
e.preventDefault();
window.location.href = '/presupuesto/add/private/' + $('#cliente_id').val();
});
})();

View File

@ -24,12 +24,11 @@ import { preguntarTipoPresupuesto } from './presupuesto-utils.js';
processing: true,
serverSide: true,
orderCellsTop: true,
stateSave: true,
pageLength: 50,
lengthMenu: [10, 25, 50, 100, 500],
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
responsive: true,
dom: 'Bflrtip',
dom: 'lBrtip',
buttons: {
dom: {
button: {
@ -51,20 +50,20 @@ import { preguntarTipoPresupuesto } from './presupuesto-utils.js';
},
order: [[0, 'asc']],
columns: [
{ data: 'id', name: 'id', title: 'ID', orderable: true },
{ data: 'titulo', name: 'titulo', title: 'Título', orderable: true },
{ data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', title: 'Encuadernación', orderable: true },
{ data: 'tipoCubierta', name: 'tipoCubierta', title: 'Cubierta', orderable: true },
{ data: 'tipoImpresion', name: 'tipoImpresion', title: 'Tipo de impresión', orderable: true },
{ data: 'tirada', name: 'selectedTirada', title: 'Tirada', orderable: true },
{ data: 'paginas', name: 'paginas', title: 'Páginas', orderable: true },
{ data: 'estado', name: 'estado', title: 'Estado', orderable: true },
{ data: 'totalConIva', name: 'totalConIva', title: 'Total con IVA', orderable: true },
{ data: 'pais', name: 'pais', title: 'País', orderable: true },
{ data: 'region', name: 'region', title: 'Región', orderable: true },
{ data: 'ciudad', name: 'ciudad', title: 'Ciudad', orderable: true },
{ data: 'updatedAt', name: 'updatedAt', title: 'Actualizado el', orderable: true },
{ data: 'actions', title: 'Acciones', orderable: false, searchable: false }
{ data: 'id', name: 'id', orderable: true },
{ data: 'titulo', name: 'titulo', orderable: true },
{ data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', orderable: true },
{ data: 'tipoCubierta', name: 'tipoCubierta', orderable: true },
{ data: 'tipoImpresion', name: 'tipoImpresion', orderable: true },
{ data: 'selectedTirada', name: 'selectedTirada', orderable: true },
{ data: 'paginas', name: 'paginas', orderable: true },
{ data: 'estado', name: 'estado', orderable: true },
{ data: 'totalConIva', name: 'totalConIva', 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', orderable: false, searchable: false }
],
});
@ -130,6 +129,148 @@ import { preguntarTipoPresupuesto } from './presupuesto-utils.js';
});
});
$('#presupuestos-anonimos-datatable').on('keyup', '.presupuesto-filter', function (e) {
const colName = $(this).data('col');
const colIndex = table_anonimos.column(colName + ':name').index();
if (table_anonimos.column(colIndex).search() !== this.value) {
table_anonimos.column(colIndex).search(this.value).draw();
}
});
$('#presupuestos-anonimos-datatable').on('change', '.presupuesto-select-filter', function (e) {
const colName = $(this).data('col');
const colIndex = table_anonimos.column(colName + ':name').index();
const value = $(this).val();
table_anonimos.column(colIndex).search(value).draw();
});
const table_clientes = new DataTable('#presupuestos-clientes-datatable', {
processing: true,
serverSide: true,
orderCellsTop: true,
pageLength: 50,
lengthMenu: [10, 25, 50, 100, 500],
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
responsive: true,
dom: 'lBrtip',
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/clientes',
method: 'GET',
},
order: [[0, 'asc']],
columns: [
{ data: 'id', name: 'id', orderable: true },
{ data: 'user', name: 'user.fullName', orderable: true },
{ data: 'titulo', name: 'titulo', orderable: true },
{ data: 'tipoEncuadernacion', name: 'tipoEncuadernacion', orderable: true },
{ data: 'tipoCubierta', name: 'tipoCubierta', orderable: true },
{ data: 'tipoImpresion', name: 'tipoImpresion', orderable: true },
{ data: 'selectedTirada', name: 'selectedTirada', orderable: true },
{ data: 'paginas', name: 'paginas', orderable: true },
{ data: 'estado', name: 'estado', orderable: true },
{ data: 'totalConIva', name: 'totalConIva', orderable: true },
{ data: 'updatedAt', name: 'updatedAt', orderable: true },
{ data: 'actions', orderable: false, searchable: false }
],
});
$('#presupuestos-clientes-datatable').on('click', '.btn-edit-privado', function (e) {
e.preventDefault();
const id = $(this).data('id');
if (id) {
window.location.href = '/presupuesto/edit/' + id;
}
});
$('#presupuestos-clientes-datatable').on('click', '.btn-delete-privado', function (e) {
e.preventDefault();
const id = $(this).data('id');
Swal.fire({
title: window.languageBundle.get(['presupuesto.delete.title']) || 'Eliminar presupuesto',
html: window.languageBundle.get(['presupuesto.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(['presupuesto.delete.button']) || 'Eliminar',
cancelButtonText: window.languageBundle.get(['app.cancelar']) || 'Cancelar',
}).then((result) => {
if (!result.isConfirmed) return;
$.ajax({
url: '/presupuesto/' + id,
type: 'DELETE',
success: function () {
Swal.fire({
icon: 'success', title: window.languageBundle.get(['presupuesto.delete.ok.title']) || 'Eliminado',
text: window.languageBundle.get(['presupuesto.delete.ok.text']) || 'El presupuesto ha sido eliminado con éxito.',
showConfirmButton: true,
customClass: {
confirmButton: 'btn btn-secondary w-xs mt-2',
},
});
$('#presupuestos-clientes-datatable').DataTable().ajax.reload(null, false);
},
error: function (xhr) {
// usa el mensaje del backend; fallback genérico por si no llega JSON
const msg = (xhr.responseJSON && xhr.responseJSON.message)
|| 'Error al eliminar el presupuesto.';
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
},
});
}
});
});
});
$('#presupuestos-clientes-datatable').on('keyup', '.presupuesto-filter', function (e) {
const colName = $(this).data('col');
const colIndex = table_clientes.column(colName + ':name').index();
if (table_clientes.column(colIndex).search() !== this.value) {
table_clientes.column(colIndex).search(this.value).draw();
}
});
$('#presupuestos-clientes-datatable').on('change', '.presupuesto-select-filter', function (e) {
const colName = $(this).data('col');
const colIndex = table_clientes.column(colName + ':name').index();
const value = $(this).val();
table_clientes.column(colIndex).search(value).draw();
});
$('#addPresupuestoButton').on('click', async function (e) {
e.preventDefault();