falta terminar albaranes

This commit is contained in:
2025-04-20 22:10:56 +02:00
parent 61abcb3dbd
commit 19fd76e910
21 changed files with 1731 additions and 464 deletions

View File

@ -0,0 +1,481 @@
class AlbaranComponent {
constructor(item) {
this.item = item;
this.id = item.id;
this.numero = item.numero_albaran;
this.cliente = item.cliente;
this.att = item.att;
this.direccion = item.direccion;
this.envio_id = item.envio_id;
this.selectorTabla = `#tablaAlbaran${this.id}`;
this.table = null;
}
mount(selector) {
const dom = this.render();
$(selector).append(dom);
requestAnimationFrame(() => this.init());
}
render() {
const { id, numero } = this;
const accordion = $('<div>', {
class: 'accordion accordion-bordered mt-3 accordion-albaran',
id: 'accordioAlbaran' + id,
albaran: id
});
const card = $('<div>', { class: 'card accordion-item active' });
const header = $('<h2>', {
class: 'accordion-header',
id: 'headingAlbaran' + id
});
const button = $('<button>', {
type: 'button',
class: 'accordion-button collapsed',
'data-bs-toggle': 'collapse',
'data-bs-target': '#accordionAlbaranTip' + id,
'aria-expanded': 'false',
'aria-controls': 'accordionAlbaranTip' + id,
'albaran': id,
}).css({ 'background-color': '#F0F8FF' }).append($('<h5>').html(numero));
const collapseDiv = $('<div>', {
id: 'accordionAlbaranTip' + id,
class: 'accordion-collapse collapse',
'data-bs-parent': '#accordioAlbaran' + id
});
const body = $('<div>', { class: 'accordion-body' });
// Cabecera HTML
const cabecera = this._buildCabecera();
const tableWrapper = $('<div>', {
class: 'table-responsive'
}).append(this._buildTable());
const botones = this._buildBotonera();
header.append(button);
card.append(header);
collapseDiv.append(body);
body.append(cabecera, tableWrapper, botones);
card.append(collapseDiv);
accordion.append(card);
return accordion;
}
_buildCabecera() {
return $(`
<div class="col-12 d-flex justify-content-between align-items-center my-3">
<!-- Fechas a la izquierda pegadas -->
<div class="d-flex align-items-center">
<div class="d-flex align-items-center me-3">
<label class="me-2 mb-0 white-space-nowrap">${window.language.Albaran.fechaCreacion}:</label>
<label class="mb-0">${this.item.fecha_creacion}</label>
</div>
<div class="d-flex align-items-center ml-5">
<label class="me-2 mb-0 white-space-nowrap">${window.language.Albaran.fechaAlbaran}:</label>
<input id="fecha_albaran_${this.id}" class="cambios-albaran form-control form-control-sm"
style="max-width: 130px;" albaran_id=${this.id} value="${this.item.fecha_albaran == null ? '' : this.item.fecha_albaran}">
</div>
</div>
<!-- Envío a la derecha -->
<div class="d-flex align-items-center ms-auto">
<label class="me-1 mb-0">${window.language.Albaran.numEnvio}:</label>
<label class="mb-0">${this.envio_id}</label>
</div>
</div>
<div class="col-12 d-flex justify-content-between align-items-center mb-3">
<!-- Cliente a la izquierda -->
<div class="d-flex align-items-center">
<label class="me-2 mb-0">${window.language.Albaran.cliente}:</label>
<label class="mb-0 text-left">${this.cliente}</label>
</div>
<!-- Nº Albarán a la derecha -->
<div class="d-flex align-items-center ms-auto">
<label class="me-2 mb-0">${window.language.Albaran.albaran}:</label>
<label class="mb-0 text-end">${this.item.numero_albaran}</label>
</div>
</div>
<div class="col-12 d-flex justify-content-between mb-3">
<div class="col-1">
<label>${window.language.Albaran.att}:</label>
</div>
<div class="col-11">
<input id="att_${this.item.id}" class="cambios-albaran form-control" data-albaranId=${this.item.id} value="${this.att}">
</div>
</div>
<div class="col-12 d-flex justify-content-between mb-3">
<div class="col-1">
<label>${window.language.Albaran.direccion}:</label>
</div>
<div class="col-11">
<input id="direccion_${this.item.id}" class="cambios-albaran form-control" data-albaranId=${this.item.id} value="${this.direccion}">
</div>
</div>
`);
}
_buildTable() {
return $('<table>', {
id: 'tablaAlbaran' + this.id,
width: '100%',
class: 'table table-responsive table-striped table-hover table-albaran'
}).append(
$('<thead>').append(
$('<tr>').append(
$('<th>').css({ 'max-width': '20px' }),
$('<th>'),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'8%' }).text(window.language.Albaran.pedido),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'8%' }).text(window.language.Albaran.unidades),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller' }).text(window.language.Albaran.titulo),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'15%' }).text(window.language.Albaran.ISBN),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'15%' }).text(window.language.Albaran.refCliente),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'8%' }).text(window.language.Albaran.precioU),
$('<th>', { class: 'lp-header', scope: 'col' }).css({ 'font-size': 'smaller', 'max-width':'8%' }).text(window.language.Albaran.subtotal),
$('<th>'),
)
),
$('<tbody>')
);
}
_buildBotonera() {
const id = this.id;
const mostrarPreciosChecked = this.item.mostrar_precios == 1 ? 'checked' : '';
return $(`
<div class="row mt-5">
<div class="col-12 d-flex align-items-center">
<div class="d-flex align-items-center">
<label for="mostrar_precios_${id}" class="me-2 mb-0">${window.language.Albaran.mostrarPrecios}:</label>
<input type="checkbox" id="mostrar_precios_${id}" class="form-check-input mostrar-precios" albaran_id="${id}" ${mostrarPreciosChecked}>
</div>
<div class="d-flex align-items-center mx-5">
<label for="cajas_albaran_${id}" class="me-2 mb-0">${window.language.Albaran.cajas}:</label>
<input type="number" id="cajas_albaran_${id}" class="form-control" albaran_id="${id}" value="${this.item.cajas}" min="0" max="200" step="1">
</div>
<!-- Botones alineados a la derecha -->
<div class="ms-auto d-flex gap-2 flex-wrap justify-content-end">
<button id="add_iva_albaran_${id}" class="add-iva-albaran btn btn-sm btn-light" type="button">
${window.language.Albaran.addIva} <i class="ti ti-plus"></i>
</button>
<button id="nueva_linea_albaran_${id}" class="nueva-linea-albaran btn btn-sm btn-light" type="button">
${window.language.Albaran.nuevaLinea} <i class="ti ti-plus"></i>
</button>
<button id="imprimir_albaran_${id}" class="imprimir-albaran btn btn-sm btn-light" type="button">
${window.language.Albaran.imprimirAlbaran} <i class="ti ti-printer"></i>
</button>
<button id="borrar_albaran_${id}" class="borrar-albaran btn btn-sm btn-danger" type="button">
${window.language.Albaran.borrarAlbaran} <i class="ti ti-trash"></i>
</button>
</div>
</div>
</div>
`);
}
init() {
this.table = $('#tablaAlbaran' + this.id).DataTable({
processing: true,
serverSide: true,
autoWidth: true,
responsive: true,
scrollX: true,
order: [[1, 'asc']],
orderable: false,
lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500],
pageLength: 50,
dom: 'lrtip',
ajax: {
url: "/albaranes/datatablesAlbaranLinea?albaranId",
data: {
albaranId: this.id
},
type: 'GET',
},
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
columns: [
{ data: "action" },
{ data: "id", visible: false },
{ data: "pedido"},
{ data: "unidades" },
{ data: "titulo" },
{ data: "isbn" },
{ data: "ref_cliente" },
{ data: "precio_unidad" },
{ data: "total" },
{ data: "iva_reducido", visible: false },
],
columnDefs: [
{
orderable: false,
searchable: false,
targets: [0]
}
],
drawCallback: (settings) => {
if ($('#mostrar_precios_' + this.id).is(':checked')) {
this.table
.column(7).visible(true)
.column(8).visible(true);
}
else {
this.table
.column(7).visible(false)
.column(8).visible(false);
}
requestAnimationFrame(() => {
this._initAutoNumericInputs();
});
}
});
$('#accordionAlbaranTip' + this.id).on('shown.bs.collapse', () => {
if (this.table) {
this.table.columns.adjust().draw(false);
}
});
$('#tablaAlbaran' + this.id).on('click', '.btn-delete-albaran-lineas', (e) => {
e.preventDefault();
const table = $('#tablaAlbaran' + this.id).DataTable();
const id = $(e.currentTarget).attr('data-id');
const url = `/albaranes/borrarAlbaranLinea`;
const data = { linea: id };
$.ajax({
url: url,
type: 'POST',
data: data,
success: (response) => {
if (response.success) {
table.draw(false);
} else {
Swal.fire({
title: 'Error',
text: 'No se ha podido borrar la línea del albarán',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
table.draw(false);
}
},
error: (xhr, status, error) => {
console.error(error);
}
});
});
$('#mostrar_precios_' + this.id).on('change', (e) => {
const checked = $(e.currentTarget).is(':checked');
if (checked) {
this.table
.column(7).visible(true)
.column(8).visible(true);
} else {
this.table
.column(7).visible(false)
.column(8).visible(false);
}
$.post('/albaranes/updateAlbaran', {
albaranId: this.id,
fieldName: 'mostrar_precios',
fieldValue: checked ? 1 : 0
}, (response) => {
if (response.success) {
this.table.ajax.reload(null, false);
} else {
Swal.fire({
title: 'Error',
text: 'No se ha podido actualizar el albarán',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
}
)
});
$('#direccion_' + this.item.id).on('change', (e) => {
const value = $(e.currentTarget).val();
const albaranId = $(e.currentTarget).attr('data-albaranId');
$.post('/albaranes/updateAlbaran', {
albaranId: albaranId,
fieldName: 'direccion_albaran',
fieldValue: value
}, (response) => {
if (response.success) {
this.table.ajax.reload(null, false);
} else {
Swal.fire({
title: 'Error',
text: 'No se ha podido actualizar el albarán',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
});
});
$('#att_' + this.item.id).on('change', (e) => {
const value = $(e.currentTarget).val();
const albaranId = $(e.currentTarget).attr('data-albaranId');
$.post('/albaranes/updateAlbaran', {
albaranId: albaranId,
fieldName: 'att_albaran',
fieldValue: value
}, (response) => {
if (response.success) {
this.table.ajax.reload(null, false);
} else {
Swal.fire({
title: 'Error',
text: 'No se ha podido actualizar el albarán',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
});
});
$("#borrar_albaran_" + this.item.id).on('click', (e) => {
e.preventDefault();
const albaranId = this.id;
const url = `/albaranes/borrarAlbaran`;
const data = { albaranId: albaranId };
Swal.fire({
title: window.language.Albaran.borrarAlbaran,
text: window.language.Albaran.borrarAlbaranConfirm,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: window.language.Albaran.borrar,
cancelButtonText: window.language.Albaran.cancelar,
customClass: {
confirmButton: 'btn btn-primary me-1',
cancelButton: 'btn btn-outline-secondary'
},
buttonsStyling: false
}).then((result) => {
$.ajax({
url: url,
type: 'POST',
data: data,
success: (response) => {
if (response.success) {
// quitar del dom el albarán
$(`#accordioAlbaran${albaranId}`).remove();
} else {
Swal.fire({
title: 'Error',
text: 'No se ha podido borrar el albarán',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
},
error: (xhr, status, error) => {
console.error(error);
}
});
});
});
}
_initAutoNumericInputs() {
const config_2 = {
decimalPlaces: 2,
digitGroupSeparator: '.',
decimalCharacter: ',',
unformatOnSubmit: true,
decimalPlacesShownOnFocus: 2,
decimalPlacesShownOnBlur: 2,
watchExternalChanges: true
};
const config_4 = {
decimalPlaces: 4,
digitGroupSeparator: '.',
decimalCharacter: ',',
unformatOnSubmit: true,
decimalPlacesShownOnFocus: 4,
decimalPlacesShownOnBlur: 4,
watchExternalChanges: true
};
// 🔥 Forzar limpieza completa de instancias anteriores
document.querySelectorAll('.autonumeric-2, .autonumeric-4').forEach(el => {
if (AutoNumeric.getAutoNumericElement(el)) {
AutoNumeric.getAutoNumericElement(el).remove();
}
});
// Inicializar nuevos
AutoNumeric.multiple('.autonumeric-2', config_2);
AutoNumeric.multiple('.autonumeric-4', config_4);
}
}
export default AlbaranComponent;

View File

@ -4,13 +4,9 @@ import AlbaranComponent from '../../components/albaranComponent.js';
class EnvioEdit {
constructor() {
this.tableCols = [
{ data: "rowSelected" },
{ data: "cajasRaw", defaultContent: "" },
{ data: "cajas", defaultContent: "" },
{ data: "pedido" },
{ data: "presupuesto" },
{ data: "titulo" },
@ -26,17 +22,15 @@ class EnvioEdit {
this.buscarPedidos = new ClassSelect($("#buscadorPedidos"), '/logistica/selectAddLinea', "", true, { 'envio': $("#id").val() });
this.contadorCajas = parseInt($("#nextCaja").val()) || 1;
this.btnAddLinea = $("#btnAddLinea");
this.btnAddCaja = $("#btnAddCaja");
this.btnDeleteLinea = $("#btnEliminarLineas");
this.btnGuardarComentarios = $("#guardarComentarios");
this.btnSelectAll = $("#btnSelectAll");
this.btnGenerarAlbaran = $("#btnGenerarAlbaran");
this.btnbtnSelectAll = $("#btnSelectAll");
this.cajas = $("#cajas");
}
init() {
this.table = $('#tableLineasEnvio').DataTable({
processing: true,
serverSide: true,
@ -44,6 +38,8 @@ class EnvioEdit {
responsive: true,
scrollX: true,
orderCellsTop: true,
orderable: false,
order: [[7, 'asc']],
lengthMenu: [5, 10, 25, 50, 75, 100, 250, 500, 1000, 2500],
pageLength: 50,
"dom": 'lrtip',
@ -54,32 +50,20 @@ class EnvioEdit {
"language": {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
rowGroup: {
dataSrc: 'cajasRaw',
startRender: function (rows, group) {
// Forzar el grupo a string (DataTables puede pasarlo como undefined o null de forma interna)
const groupStr = group == null || group === 0 || group === '0' ? '__SIN__ASIGNAR__' : group.toString();
const nombreGrupo = groupStr === '__SIN__ASIGNAR__' ? 'SIN ASIGNAR' : groupStr;
let totalUnidades = 0;
let totalPeso = 0;
rows.data().each(function (row) {
const unidades = parseInt(row.unidadesEnvioRaw) || 0;
totalUnidades += unidades;
totalPeso += (parseFloat(row.pesoUnidad) || 0) * unidades;
});
return `
<label class="switch switch-square">
<input type="checkbox" class="switch-input switch-grupo" data-grupo="${groupStr}" id="switch-grupo-${groupStr}">
<span class="switch-toggle-slider"></span>
<span class="switch-label">
CAJA: ${nombreGrupo} [unidades: ${totalUnidades}, peso: <span class="peso-grupo" data-valor="${totalPeso}">${totalPeso.toFixed(1)}</span> kg]
</span>
</label>
`;
}
footerCallback: function (row, data, start, end, display) {
let totalUnidades = 0;
let totalPeso = 0;
data.forEach(row => {
const unidades = parseFloat(row.unidadesEnvioRaw) || 0;
const pesoUnidad = parseFloat(row.pesoUnidad) || 0;
totalUnidades += unidades;
totalPeso += unidades * pesoUnidad;
});
// Mostrar en spans personalizados del <tfoot>
$('#footer-unidades-envio').text(totalUnidades);
$('#footer-peso').text(totalPeso.toFixed(2));
},
"columnDefs": [
{
@ -89,105 +73,64 @@ class EnvioEdit {
"searchable": false,
},
{
"targets": [3, 4, 6, 7, 8],
"targets": [1, 2, 4, 5, 6],
"className": "text-center",
},
{
targets: [1, 9, 10, 11],
targets: [7, 8, 9],
visible: false
}
],
"order": [[1, "asc"]],
"orderFixed": [[1, 'asc']],
]
});
$('#tableLineasEnvio').on('change', '.switch-grupo', function () {
const grupo = $(this).data('grupo');
const checked = $(this).is(':checked');
const table = $('#tableLineasEnvio').DataTable();
table.rows().every(function () {
const rowData = this.data();
const node = $(this.node());
const valorCaja = (rowData.cajasRaw === null || rowData.cajasRaw === '' ||
rowData.cajasRaw === 0 || rowData.cajasRaw === '0' || rowData.cajasRaw === undefined)
? '__SIN__ASIGNAR__'
: rowData.cajasRaw.toString();
if (valorCaja == grupo) {
node.find('.checkbox-linea-envio').prop('checked', checked);
}
});
});
$('#tableLineasEnvio').on('draw.dt', () => {
const table = this.table;
this._aplicarDroppableEnGrupos(table);
// Aplica draggable a filas si aún no lo tienen
this.table.rows({ page: 'current' }).every(function () {
const $row = $(this.node());
if (!$row.hasClass('draggable-applied')) {
$row.addClass('draggable-applied');
$row.draggable({
helper: 'clone',
revert: 'invalid',
start: () => $row.css('opacity', 0.5),
stop: () => $row.css('opacity', 1)
this.cajas.on('change', (e) => {
const value = $(e.currentTarget).val();
if (value < 0) {
Swal.fire({
title: 'Atención!',
text: 'El número de cajas no puede ser negativo.',
icon: 'info',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
$(e.currentTarget).val(0);
return;
}
$.post('/logistica/updateCajasEnvio', {
id: $('#id').val(),
cajas: value
}, function (response) {
if (!response.status) {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
});
document.querySelectorAll('.peso-grupo').forEach(el => {
const valor = parseFloat(el.getAttribute('data-valor')) || 0;
new AutoNumeric(el, valor, {
decimalPlaces: 1,
digitGroupSeparator: ',',
decimalCharacter: '.',
minimumValue: '0',
suffixText: '',
modifyValueOnWheel: false
$(e.currentTarget).val(0);
}
}).fail(() => {
Swal.fire({
title: 'Error',
text: 'No se pudo actualizar el número de cajas.',
icon: 'error',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
});
$('#tableLineasEnvio').on('change', '.checkbox-linea-envio', function () {
const $row = $(this).closest('tr');
const table = $('#tableLineasEnvio').DataTable();
const rowData = table.row($row).data();
const valorCaja = (rowData.cajasRaw === null || rowData.cajasRaw === '' || rowData.cajasRaw === 0 || rowData.cajasRaw === '0')
? '__SIN__ASIGNAR__'
: rowData.cajasRaw;
// 1. Filtrar todas las filas del mismo grupo
let total = 0;
let seleccionadas = 0;
table.rows().every(function () {
const data = this.data();
const grupo = (data.cajasRaw === null || data.cajasRaw === '' || data.cajasRaw === 0 || data.cajasRaw === '0')
? 'SIN ASIGNAR'
: data.cajasRaw;
if (grupo == valorCaja) {
total++;
if ($(this.node()).find('.checkbox-linea-envio').is(':checked')) {
seleccionadas++;
}
}
});
// 2. Actualizar el checkbox del grupo
const checkGrupo = $(`.switch-grupo[data-grupo="${valorCaja}"]`);
if (seleccionadas === total) {
checkGrupo.prop('checked', true);
} else {
checkGrupo.prop('checked', false);
}
$(e.currentTarget).val(0);
});
});
@ -210,7 +153,6 @@ class EnvioEdit {
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -225,7 +167,6 @@ class EnvioEdit {
title: 'Error',
text: 'No se pudo actualizar el dato.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -239,39 +180,33 @@ class EnvioEdit {
this.buscarPedidos.init();
this.btnAddLinea.on('click', this._addEnvioLinea.bind(this));
this.btnAddCaja.on('click', this._addCaja.bind(this));
this.btnDeleteLinea.on('click', this._deleteLineas.bind(this));
this.btnGenerarAlbaran.on('click', this._generarAlbaran.bind(this));
if (this.btnAddLinea.length) this.btnAddLinea.on('click', this._addEnvioLinea.bind(this));
if (this.btnDeleteLinea.length) this.btnDeleteLinea.on('click', this._deleteLineas.bind(this));
if (this.btnGenerarAlbaran.length) this.btnGenerarAlbaran.on('click', this._generarAlbaran.bind(this));
this.btnGuardarComentarios.on('click', () => {
$.post('/logistica/updateComentariosEnvio', {
id: $('#id').val(),
comentarios: $('#comentarios').val()
}, function (response) {
if (response.status) {
popSuccessAlert('Comentarios guardados correctamente');
} else {
popErrorAlert(response.message);
}
}).fail((error) => {
popErrorAlert(error.responseJSON.message);
if (this.btnGuardarComentarios.length) {
this.btnGuardarComentarios.on('click', () => {
$.post('/logistica/updateComentariosEnvio', {
id: $('#id').val(),
comentarios: $('#comentarios').val()
}, function (response) {
if (response.status) {
popSuccessAlert('Comentarios guardados correctamente');
} else {
popErrorAlert(response.message);
}
}).fail((error) => {
popErrorAlert(error.responseJSON.message);
});
});
});
}
this.btnSelectAll.on('click', () => {
$('.switch-grupo').each(function () {
const $switch = $(this);
if (!$switch.is(':checked')) {
$switch.prop('checked', true).trigger('change');
} else {
// incluso si ya está marcado, forzamos el evento por seguridad
$switch.trigger('change');
}
});
});
this.btnbtnSelectAll.on('click', () => {
const checkboxes = this.table.$('input[type="checkbox"]');
const allChecked = checkboxes.length === checkboxes.filter(':checked').length;
checkboxes.prop('checked', !allChecked);
}
);
this._getAlbaranes();
}
@ -281,7 +216,6 @@ class EnvioEdit {
envio_id: $('#id').val(),
}, function (response) {
if (response.status && response.data) {
for (let i = 0; i < response.data.length; i++) {
const albaran = response.data[i];
new AlbaranComponent(albaran).mount('#contenedorAlbaranes');
@ -291,7 +225,6 @@ class EnvioEdit {
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -305,7 +238,6 @@ class EnvioEdit {
title: 'Error',
text: 'No se han podido obtener los albaranes.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -317,8 +249,6 @@ class EnvioEdit {
}
_generarAlbaran() {
// se seleccionan los id de las lineas de envio con checkbox marcado
const table = this.table;
const selectedRows = table.rows({ page: 'current' }).nodes().filter((node) => {
const checkbox = $(node).find('.checkbox-linea-envio');
@ -327,14 +257,13 @@ class EnvioEdit {
const ids = selectedRows.map((node) => {
const rowData = table.row(node).data();
return rowData.id;
}
).toArray();
}).toArray();
if (ids.length <= 0) {
Swal.fire({
title: 'Atención!',
text: 'Debe seleccionar al menos una línea de envío para generar el albarán.',
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -344,20 +273,20 @@ class EnvioEdit {
});
return;
}
const idEnvio = $('#id').val();
$.post('/albaranes/generarAlbaran', {
envio_id: idEnvio,
envio_lineas: ids
envio_lineas: ids,
cajas: this.cajas.val()
}, function (response) {
if (response.status && response.albaran) {
new AlbaranComponent(response.albaran).mount('#contenedorAlbaranes');
} else {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -371,7 +300,6 @@ class EnvioEdit {
title: 'Error',
text: 'No se pudo generar el albarán.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -380,7 +308,6 @@ class EnvioEdit {
buttonsStyling: false
});
});
}
_deleteLineas() {
@ -392,11 +319,10 @@ class EnvioEdit {
const ids = selectedRows.map((node) => {
const rowData = table.row(node).data();
return rowData.id;
}
).toArray();
}).toArray();
if (ids.length > 0) {
Swal.fire({
title: 'Eliminar líneas de envío',
text: '¿Está seguro de que desea eliminar las líneas seleccionadas?',
icon: 'warning',
@ -411,18 +337,15 @@ class EnvioEdit {
}).then((result) => {
if (result.isConfirmed) {
$.post('/logistica/deleteLineasEnvio', {
ids: ids
}, function (response) {
if (response.status) {
table.draw(false);
}
else {
} else {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -437,7 +360,6 @@ class EnvioEdit {
title: 'Error',
text: 'No se pudo eliminar la línea de envío.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -454,7 +376,6 @@ class EnvioEdit {
title: 'Sin filas seleccionadas',
text: 'Marca al menos una línea para eliminarla.',
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -465,160 +386,12 @@ class EnvioEdit {
}
}
_addCaja() {
const table = this.table;
this.contadorCajas = this._calcularSiguienteNumeroCaja();
const contadorCajas = this.contadorCajas;
let moved = false;
// Recorremos todas las filas visibles
table.rows({ page: 'current' }).every(function () {
const $row = $(this.node());
const checkbox = $row.find('.checkbox-linea-envio');
if (checkbox.is(':checked')) {
const rowData = this.data();
$.post('/logistica/updateCajaLinea', {
id: rowData.id,
caja: contadorCajas
}, function (response) {
if (response.status) {
table.draw(false);
} else {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
table.ajax.reload();
}
}).fail(() => {
Swal.fire({
title: 'Error',
text: 'No se pudo actualizar el grupo.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
table.ajax.reload();
});
moved = true;
}
});
if (moved) {
table.draw(false); // Redibuja sin cambiar de página
this.contadorCajas++;
} else {
Swal.fire({
title: 'Sin filas seleccionadas',
text: 'Marca al menos una línea para moverla a una nueva caja.',
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
}
_aplicarDroppableEnGrupos(table) {
const self = this;
setTimeout(() => {
$('.dtrg-group').each(function () {
const $grupo = $(this);
let nombreGrupo = $grupo.text().toUpperCase().replace('CAJA:', '').trim();
if (nombreGrupo.includes('SIN ASIGNAR')) {
nombreGrupo = '__SIN__ASIGNAR__';
}
// Evitar aplicar múltiples veces
if (!$grupo.hasClass('droppable-applied')) {
$grupo.addClass('droppable-applied');
$grupo.droppable({
accept: 'tr:not(.dtrg-group)',
hoverClass: 'table-primary',
drop: function (event, ui) {
const row = table.row(ui.draggable);
const rowData = row.data();
rowData.cajas = nombreGrupo;
row.data(rowData).invalidate();
$.post('/logistica/updateCajaLinea', {
id: rowData.id,
caja: nombreGrupo
}, function (response) {
if (response.status) {
self._reordenarCajas();
} else {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
table.ajax.reload();
}
}).fail(() => {
Swal.fire({
title: 'Error filas seleccionadas',
text: 'No se pudo actualizar el grupo.',
icon: 'error',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
table.ajax.reload();
});
}
});
}
});
}, 50); // pequeño delay para asegurar que el DOM esté listo
}
_addEnvioLinea() {
if (!this.buscarPedidos.getVal()) {
Swal.fire({
title: 'Atención!',
text: 'Debe seleccionar un pedido antes de añadir una línea de envío.',
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -626,7 +399,6 @@ class EnvioEdit {
},
buttonsStyling: false
});
return;
}
@ -637,35 +409,6 @@ class EnvioEdit {
}, {},
(response) => {
if (response.status) {
if (parseInt(response.data.total_unidades) > parseInt(response.data.unidades_envio)) {
const text = `<div style="text-align: left;">
Se ha añadido un nuevo envío parcial:\n
<ul>
<li>Unidades totales en pedido: {unidadesTotal}</li>
<li>Unidades añadidos: {unidadesEnvio}</li>
<li>Unidades enviadas: {unidadesEnviadas}</li>
<li>Unidades en envíos no finalizados: {unidadesPendientes}</li>
</ul>
</div>`;
const unidades_pendientes = parseInt(response.data.total_unidades) -
parseInt(response.data.unidades_enviadas) - parseInt(response.data.unidades_envio);
const textFinal = text.replace('{unidadesTotal}', response.data.total_unidades)
.replace('{unidadesEnvio}', response.data.unidades_envio)
.replace('{unidadesEnviadas}', response.data.unidades_enviadas)
.replace('{unidadesPendientes}', unidades_pendientes);
Swal.fire({
title: 'Atención!',
html: textFinal,
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
this.table.draw();
this.buscarPedidos.empty();
} else {
@ -673,7 +416,6 @@ class EnvioEdit {
title: 'Atención!',
text: response.message,
icon: 'info',
showCancelButton: false,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
@ -686,79 +428,6 @@ class EnvioEdit {
console.error(error);
}).get();
}
_calcularSiguienteNumeroCaja() {
const cajasUsadas = new Set();
this.table.rows().every(function () {
const data = this.data();
const caja = data.cajas;
if (caja !== null && caja !== '' && !isNaN(parseInt(caja))) {
cajasUsadas.add(parseInt(caja));
}
});
// Buscar el menor número libre empezando desde 1
let i = 1;
while (cajasUsadas.has(i)) {
i++;
}
return i;
}
_reordenarCajas() {
const table = this.table;
const mapaOriginalANuevo = {};
const cajasDetectadas = [];
// 1. Recolectar cajas distintas en orden
table.rows().every(function () {
const data = this.data();
const caja = data.cajas;
if (caja !== null && caja !== '' && !isNaN(parseInt(caja))) {
const cajaNum = parseInt(caja);
if (!cajasDetectadas.includes(cajaNum)) {
cajasDetectadas.push(cajaNum);
}
}
});
cajasDetectadas.sort((a, b) => a - b);
// 2. Construir mapa de renumeración
cajasDetectadas.forEach((valorOriginal, idx) => {
mapaOriginalANuevo[valorOriginal] = idx + 1;
});
// 3. Aplicar cambios si hace falta
table.rows().every(function () {
const data = this.data();
const original = parseInt(data.cajas);
const nuevo = mapaOriginalANuevo[original];
if (original !== nuevo) {
data.cajas = nuevo;
// Persistir en backend
$.post('/logistica/updateCajaLinea', {
id: data.id,
caja: nuevo
});
this.data(data).invalidate();
}
});
// 4. Actualizar contador interno
this.contadorCajas = cajasDetectadas.length + 1;
table.draw(false);
}
}
document.addEventListener('DOMContentLoaded', function () {
@ -778,7 +447,6 @@ document.addEventListener('DOMContentLoaded', function () {
console.log("Error getting translations:", error);
}
).post();
});
export default EnvioEdit;