mirror of
https://git.imnavajas.es/jjimenez/safekat.git
synced 2025-07-25 22:52:08 +00:00
Corregidos bugs y homegeneizado
This commit is contained in:
@ -1,8 +1,11 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
let dataTable;
|
||||
let productosOriginales = [];
|
||||
let datosComunesPedido = {};
|
||||
|
||||
document.getElementById('importBtn').disabled = true;
|
||||
|
||||
document.getElementById('xmlFile').addEventListener('change', function (e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file || !file.name.endsWith('.zip')) {
|
||||
@ -10,10 +13,19 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('importBtn').disabled = true;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = async function (event) {
|
||||
try {
|
||||
const zip = await JSZip.loadAsync(event.target.result);
|
||||
|
||||
// Reset tabla y memoria de productos
|
||||
if (dataTable) {
|
||||
dataTable.clear().draw();
|
||||
}
|
||||
productosOriginales = [];
|
||||
|
||||
const xmlFiles = Object.values(zip.files).filter(f =>
|
||||
f.name.endsWith('.xml') && !f.name.startsWith('__MACOSX/')
|
||||
);
|
||||
@ -23,11 +35,20 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: 'Procesando...',
|
||||
text: 'Cargando XMLs...',
|
||||
allowOutsideClick: false,
|
||||
showDenyButton: false,
|
||||
didOpen: () => Swal.showLoading()
|
||||
});
|
||||
|
||||
for (const file of xmlFiles) {
|
||||
const content = await file.async('text');
|
||||
parseXmlAndLoadTable(content);
|
||||
await parseXmlAndLoadTable(content);
|
||||
}
|
||||
|
||||
Swal.close();
|
||||
Swal.fire('Éxito', `${xmlFiles.length} archivos XML cargados.`, 'success');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -38,8 +59,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
|
||||
function parseXmlAndLoadTable(xmlText) {
|
||||
let parser = new DOMParser();
|
||||
async function parseXmlAndLoadTable(xmlText) {
|
||||
const parser = new DOMParser();
|
||||
let xmlDoc;
|
||||
|
||||
try {
|
||||
@ -50,7 +71,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return;
|
||||
}
|
||||
|
||||
datosComunesPedido = {
|
||||
const pedidoActual = {
|
||||
orderNumber: xmlDoc.querySelector('orderNumber')?.textContent ?? '',
|
||||
shipping: {
|
||||
address: xmlDoc.querySelector('shippingData > address')?.textContent ?? '',
|
||||
@ -65,13 +86,19 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
const products = Array.from(xmlDoc.getElementsByTagName('product'));
|
||||
const offset = productosOriginales.length;
|
||||
const rows = [];
|
||||
|
||||
products.forEach((prod, idx) => {
|
||||
productosOriginales.push({ index: offset + idx, data: prod });
|
||||
});
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
const product = products[i];
|
||||
const globalIndex = offset + i;
|
||||
|
||||
// Asociar producto con su pedido
|
||||
productosOriginales.push({
|
||||
index: globalIndex,
|
||||
data: product,
|
||||
pedido: { ...pedidoActual }
|
||||
});
|
||||
|
||||
const rows = products.map((product, index) => {
|
||||
const globalIndex = offset + index;
|
||||
const id = product.querySelector('id')?.textContent ?? '';
|
||||
const title = product.querySelector('title')?.textContent ?? '';
|
||||
const pages = product.querySelector('body > pages')?.textContent ?? '';
|
||||
@ -97,40 +124,65 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
});
|
||||
|
||||
return [
|
||||
`<input type="checkbox" class="form-check-input select-row" checked>`,
|
||||
`${datosComunesPedido.orderNumber} - ${id}`,
|
||||
title,
|
||||
tamano,
|
||||
pages,
|
||||
tirada,
|
||||
interior,
|
||||
'',
|
||||
`<button type="button" class="btn btn-sm btn-outline-success importRow">Importar</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger deleteRow">Eliminar</button>`
|
||||
];
|
||||
});
|
||||
// Obtener referencia del pedido
|
||||
const refCliente = `${pedidoActual.orderNumber}-${id}`;
|
||||
|
||||
// Validar fila con su propio pedido
|
||||
const result = await validarProductoXml(product, pedidoActual);
|
||||
|
||||
let checkboxHtml = '';
|
||||
let notaHtml = '';
|
||||
let actionBtnsHtml = '';
|
||||
|
||||
if (result.apto) {
|
||||
checkboxHtml = `<input type="checkbox" class="form-check-input select-row" checked>`;
|
||||
notaHtml = '';
|
||||
actionBtnsHtml = `
|
||||
<div class="d-flex flex-column align-items-start">
|
||||
<button type="button" class="btn btn-outline-success btn-sm mb-1 importRow">
|
||||
<i class="fas fa-file-import me-1"></i> Importar
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
||||
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
checkboxHtml = `<input type="checkbox" class="form-check-input select-row" disabled>`;
|
||||
notaHtml = `<span class="badge bg-danger">${result.reason}</span>`;
|
||||
actionBtnsHtml = `
|
||||
<div class="d-flex flex-column align-items-start">
|
||||
<span class="badge rounded-pill bg-danger mb-2">No Apto</span>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
||||
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
rows.push([checkboxHtml, refCliente, title, tamano, pages, tirada, interior, notaHtml, actionBtnsHtml]);
|
||||
}
|
||||
|
||||
if (!$.fn.DataTable.isDataTable('#xmlTable')) {
|
||||
const headerHtml = `
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="selectAll" /></th>
|
||||
<th>Referencia</th>
|
||||
<th>Título</th>
|
||||
<th>Tamaño</th>
|
||||
<th>Páginas</th>
|
||||
<th>Tirada</th>
|
||||
<th>Interior</th>
|
||||
<th>Notas</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th><th></th><th></th><th></th><th></th>
|
||||
<th></th><th></th><th></th><th></th>
|
||||
</tr>
|
||||
</thead>`;
|
||||
$('#xmlTable').html(headerHtml);
|
||||
$('#xmlTable').html(`
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" id="selectAll" /></th>
|
||||
<th>Referencia</th>
|
||||
<th>Título</th>
|
||||
<th>Tamaño</th>
|
||||
<th>Páginas</th>
|
||||
<th>Tirada</th>
|
||||
<th>Interior</th>
|
||||
<th>Notas</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th><th></th><th></th><th></th><th></th>
|
||||
<th></th><th></th><th></th><th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
`);
|
||||
}
|
||||
|
||||
if (!dataTable) {
|
||||
@ -141,6 +193,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
responsive: true,
|
||||
scrollX: true,
|
||||
dom: 'lfrtip',
|
||||
pageLength: 25,
|
||||
lengthMenu: [5, 10, 25, 50, 100, 250, 500],
|
||||
language: {
|
||||
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
|
||||
},
|
||||
@ -163,8 +217,36 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
rows.forEach(row => dataTable.row.add(row));
|
||||
dataTable.draw(false);
|
||||
}
|
||||
|
||||
if (rows.length > 0) {
|
||||
document.getElementById('importBtn').disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function validarProductoXml(productoXml, pedido) {
|
||||
try {
|
||||
const response = await fetch('/importador/bubok/validar-fila', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '<?= csrf_hash() ?>'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
producto: xmlToJson(productoXml),
|
||||
pedido: pedido
|
||||
})
|
||||
});
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Error validando producto:', error);
|
||||
return { apto: false, reason: 'Error conexión' };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function setupEventListeners() {
|
||||
$('#xmlTable tbody').off('click', '.deleteRow').on('click', '.deleteRow', function () {
|
||||
dataTable.row($(this).parents('tr')).remove().draw();
|
||||
@ -173,9 +255,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
$('#xmlTable tbody').off('click', '.importRow').on('click', '.importRow', async function () {
|
||||
const $row = $(this).closest('tr');
|
||||
const rowIndex = dataTable.row($row).index();
|
||||
const xmlProduct = productosOriginales.find(p => p.index === rowIndex)?.data;
|
||||
const productoObj = productosOriginales.find(p => p.index === rowIndex);
|
||||
|
||||
if (!xmlProduct) return;
|
||||
if (!productoObj) return;
|
||||
|
||||
const xmlProduct = productoObj.data;
|
||||
const pedido = productoObj.pedido;
|
||||
|
||||
try {
|
||||
const response = await fetch('/importador/bubok/importar-fila', {
|
||||
@ -186,32 +271,46 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
producto: xmlToJson(xmlProduct),
|
||||
pedido: datosComunesPedido
|
||||
pedido: pedido
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
const rowData = dataTable.row($row).data();
|
||||
|
||||
if (response.ok && result.status === 200) {
|
||||
const skUrl = result.data?.sk_url?.replace('presupuestocliente', 'presupuestoadmin') ?? null;
|
||||
const htmlLink = skUrl
|
||||
? `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto</a>`
|
||||
: 'Importado';
|
||||
rowData[7] = htmlLink;
|
||||
const skId = result.data?.sk_id ?? '';
|
||||
|
||||
rowData[7] = skUrl
|
||||
? `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto (${skId})</a>`
|
||||
: `<span class="badge bg-success">Importado (${skId})</span>`;
|
||||
|
||||
dataTable.row($row).data(rowData).draw(false);
|
||||
|
||||
let html = skUrl
|
||||
? `La fila se importó exitosamente.<br><br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto (${skId})</a>`
|
||||
: `La fila se importó exitosamente. (${skId})`;
|
||||
|
||||
let icon = 'success';
|
||||
|
||||
if (result.price_warning) {
|
||||
html = skUrl
|
||||
? `La fila se importó con éxito, pero el precio fue ajustado por debajo de costes.<br><br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto (${skId})</a>`
|
||||
: `La fila se importó con advertencia de coste. (${skId})`;
|
||||
icon = 'warning';
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: 'Importado correctamente',
|
||||
html: skUrl
|
||||
? `Se importó correctamente.<br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto</a>`
|
||||
: 'Importación realizada.',
|
||||
icon: 'success',
|
||||
html: html,
|
||||
icon: icon,
|
||||
confirmButtonText: 'Aceptar',
|
||||
customClass: { confirmButton: 'btn btn-success' }
|
||||
});
|
||||
|
||||
} else {
|
||||
rowData[7] = `<span class="badge bg-danger">${result.message ?? 'Error inesperado'}</span>`;
|
||||
rowData[7] = `<span class="badge bg-danger">${result.message ?? 'Error desconocido'}</span>`;
|
||||
dataTable.row($row).data(rowData).draw(false);
|
||||
|
||||
Swal.fire({
|
||||
@ -222,15 +321,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
customClass: { confirmButton: 'btn btn-danger' }
|
||||
});
|
||||
}
|
||||
|
||||
dataTable.row($row).data(rowData).draw(false);
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} catch (error) {
|
||||
console.error('Importación fallida:', error);
|
||||
Swal.fire('Error', 'Error de comunicación con el servidor.', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('#selectAll').off('change').on('change', function () {
|
||||
const checked = $(this).is(':checked');
|
||||
$('#xmlTable tbody input.select-row:enabled').prop('checked', checked);
|
||||
@ -329,8 +427,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
for (const i of filasSeleccionadas) {
|
||||
const productXml = productosOriginales.find(p => p.index === i)?.data;
|
||||
if (!productXml) continue;
|
||||
const productoObj = productosOriginales.find(p => p.index === i);
|
||||
if (!productoObj) continue;
|
||||
|
||||
const productXml = productoObj.data;
|
||||
const pedido = productoObj.pedido;
|
||||
|
||||
try {
|
||||
const response = await fetch('/importador/bubok/importar-fila', {
|
||||
@ -341,7 +442,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
producto: xmlToJson(productXml),
|
||||
pedido: datosComunesPedido
|
||||
pedido: pedido
|
||||
})
|
||||
});
|
||||
|
||||
@ -351,9 +452,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
if (response.ok && result.status === 200) {
|
||||
const skUrl = result.data?.sk_url?.replace('presupuestocliente', 'presupuestoadmin') ?? null;
|
||||
const skId = result.data?.sk_id ?? '';
|
||||
rowData[7] = skUrl
|
||||
? `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto</a>`
|
||||
: '<span class="badge bg-success">Importado</span>';
|
||||
? `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto (${skId})</a>`
|
||||
: `<span class="badge bg-success">Importado (${skId})</span>`;
|
||||
} else {
|
||||
rowData[7] = `<span class="badge bg-danger">${result.message ?? 'Error desconocido'}</span>`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user