311 lines
8.7 KiB
HTML
311 lines
8.7 KiB
HTML
{% extends 'base.html' %}
|
|
|
|
{% block title %}Panel de Administración{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
.admin-container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.tabs {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
border-bottom: 2px solid #ecf0f1;
|
|
}
|
|
|
|
.tab {
|
|
padding: 1rem 2rem;
|
|
cursor: pointer;
|
|
border: none;
|
|
background: none;
|
|
font-size: 1rem;
|
|
color: #7f8c8d;
|
|
border-bottom: 3px solid transparent;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.tab.active {
|
|
color: #3498db;
|
|
border-bottom-color: #3498db;
|
|
}
|
|
|
|
.tab-content {
|
|
display: none;
|
|
}
|
|
|
|
.tab-content.active {
|
|
display: block;
|
|
}
|
|
|
|
.albaran-card {
|
|
background: white;
|
|
border-radius: 8px;
|
|
padding: 1.5rem;
|
|
margin-bottom: 1rem;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.albaran-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid #ecf0f1;
|
|
}
|
|
|
|
.albaran-image {
|
|
max-width: 100%;
|
|
max-height: 400px;
|
|
border-radius: 4px;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.ocr-data {
|
|
background: #f8f9fa;
|
|
padding: 1rem;
|
|
border-radius: 4px;
|
|
margin: 1rem 0;
|
|
font-family: monospace;
|
|
font-size: 0.9rem;
|
|
white-space: pre-wrap;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.referencias-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.referencias-table th,
|
|
.referencias-table td {
|
|
padding: 0.75rem;
|
|
text-align: left;
|
|
border-bottom: 1px solid #ecf0f1;
|
|
}
|
|
|
|
.referencias-table th {
|
|
background: #f8f9fa;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.badge {
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 12px;
|
|
font-size: 0.75rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.badge.pendiente {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.badge.procesado {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.badge.clasificacion {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="admin-container">
|
|
<h1 style="margin-bottom: 2rem;">Panel de Administración</h1>
|
|
|
|
<div class="tabs">
|
|
<button class="tab active" onclick="showTab('albaranes')">Albaranes</button>
|
|
<button class="tab" onclick="showTab('clasificacion')">Pendientes de Clasificación</button>
|
|
</div>
|
|
|
|
<div id="tab-albaranes" class="tab-content active">
|
|
<div id="albaranes-container"></div>
|
|
</div>
|
|
|
|
<div id="tab-clasificacion" class="tab-content">
|
|
<div id="clasificacion-container"></div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
const API_BASE = '/api';
|
|
|
|
function showTab(tabName) {
|
|
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
|
|
|
|
event.target.classList.add('active');
|
|
document.getElementById(`tab-${tabName}`).classList.add('active');
|
|
|
|
if (tabName === 'albaranes') {
|
|
loadAlbaranes();
|
|
} else if (tabName === 'clasificacion') {
|
|
loadClasificacion();
|
|
}
|
|
}
|
|
|
|
function loadAlbaranes() {
|
|
fetch(`${API_BASE}/albaranes/`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const albaranes = data.results || data;
|
|
renderAlbaranes(albaranes);
|
|
});
|
|
}
|
|
|
|
function loadClasificacion() {
|
|
fetch(`${API_BASE}/albaranes/?estado_procesado=clasificacion`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const albaranes = data.results || data;
|
|
renderClasificacion(albaranes);
|
|
});
|
|
}
|
|
|
|
function renderAlbaranes(albaranes) {
|
|
const container = document.getElementById('albaranes-container');
|
|
container.innerHTML = '';
|
|
|
|
albaranes.forEach(albaran => {
|
|
const card = document.createElement('div');
|
|
card.className = 'albaran-card';
|
|
|
|
const estadoClass = albaran.estado_procesado === 'procesado' ? 'procesado' :
|
|
albaran.estado_procesado === 'clasificacion' ? 'clasificacion' : 'pendiente';
|
|
|
|
card.innerHTML = `
|
|
<div class="albaran-header">
|
|
<div>
|
|
<h3>Albarán ${albaran.numero_albaran || albaran.id}</h3>
|
|
<p>Proveedor: ${albaran.proveedor ? albaran.proveedor.nombre : 'Sin asignar'}</p>
|
|
<p>Fecha: ${albaran.fecha_albaran || 'N/A'}</p>
|
|
</div>
|
|
<span class="badge ${estadoClass}">${albaran.estado_procesado}</span>
|
|
</div>
|
|
|
|
<img src="/media/${albaran.archivo_path}" class="albaran-image" alt="Albarán">
|
|
|
|
<div class="ocr-data">${JSON.stringify(albaran.datos_ocr, null, 2)}</div>
|
|
|
|
${albaran.referencias && albaran.referencias.length > 0 ? `
|
|
<table class="referencias-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Referencia</th>
|
|
<th>Descripción</th>
|
|
<th>Unidades</th>
|
|
<th>Precio</th>
|
|
<th>IVA</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${albaran.referencias.map(ref => `
|
|
<tr>
|
|
<td>${ref.referencia}</td>
|
|
<td>${ref.denominacion}</td>
|
|
<td>${ref.unidades}</td>
|
|
<td>${ref.precio_unitario}€</td>
|
|
<td>${ref.impuesto_tipo}%</td>
|
|
</tr>
|
|
`).join('')}
|
|
</tbody>
|
|
</table>
|
|
` : ''}
|
|
`;
|
|
|
|
container.appendChild(card);
|
|
});
|
|
}
|
|
|
|
function renderClasificacion(albaranes) {
|
|
const container = document.getElementById('clasificacion-container');
|
|
container.innerHTML = '';
|
|
|
|
albaranes.forEach(albaran => {
|
|
const card = document.createElement('div');
|
|
card.className = 'albaran-card';
|
|
|
|
card.innerHTML = `
|
|
<div class="albaran-header">
|
|
<h3>Albarán ${albaran.numero_albaran || albaran.id}</h3>
|
|
</div>
|
|
|
|
<img src="/media/${albaran.archivo_path}" class="albaran-image" alt="Albarán">
|
|
|
|
<div style="margin-top: 1rem;">
|
|
<label>Asignar Proveedor:</label>
|
|
<select id="proveedor-${albaran.id}" style="padding: 0.5rem; margin: 0.5rem 0; width: 100%;">
|
|
<option value="">Seleccionar proveedor...</option>
|
|
</select>
|
|
<button class="btn btn-primary" onclick="vincularProveedor(${albaran.id})" style="margin-top: 0.5rem;">
|
|
Vincular Proveedor
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
container.appendChild(card);
|
|
});
|
|
|
|
// Cargar proveedores
|
|
loadProveedores();
|
|
}
|
|
|
|
function loadProveedores() {
|
|
fetch(`${API_BASE}/proveedores/`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const proveedores = data.results || data;
|
|
proveedores.forEach(prov => {
|
|
document.querySelectorAll('select[id^="proveedor-"]').forEach(select => {
|
|
const option = document.createElement('option');
|
|
option.value = prov.id;
|
|
option.textContent = prov.nombre;
|
|
select.appendChild(option);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function vincularProveedor(albaranId) {
|
|
const select = document.getElementById(`proveedor-${albaranId}`);
|
|
const proveedorId = select.value;
|
|
|
|
if (!proveedorId) {
|
|
alert('Selecciona un proveedor');
|
|
return;
|
|
}
|
|
|
|
fetch(`${API_BASE}/albaranes/${albaranId}/vincular_proveedor/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ proveedor_id: proveedorId })
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
alert('Proveedor vinculado correctamente');
|
|
loadClasificacion();
|
|
})
|
|
.catch(error => {
|
|
alert('Error al vincular proveedor: ' + error.message);
|
|
});
|
|
}
|
|
|
|
// Cargar inicial
|
|
loadAlbaranes();
|
|
</script>
|
|
{% endblock %}
|
|
|