modified: templates/admin_rendiciones.html modified: templates/macros/modals.html
312 lines
15 KiB
HTML
312 lines
15 KiB
HTML
{% extends "macros/base.html" %}
|
|
{% from 'macros/modals.html' import alert_modal, rendicion_detail_modal, confirm_modal, edit_rendicion_modal %}
|
|
|
|
{% block title %}Historial de Rendiciones{% endblock %}
|
|
|
|
{% block head %}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h2 class="mb-0">Historial de Rendiciones</h2>
|
|
</div>
|
|
|
|
<div class="card shadow-sm mb-4 border-0">
|
|
<div class="card-body bg-body-tertiary rounded p-3">
|
|
<form method="GET" action="{{ url_for('admin_rendiciones') }}" id="filterForm">
|
|
<div class="row g-2 align-items-end">
|
|
<div class="col-md-2">
|
|
<label class="form-label small text-muted mb-1">Año</label>
|
|
<select name="anio" class="form-select form-select-sm">
|
|
{% for anio in anios_disponibles %}
|
|
<option value="{{ anio }}" {% if anio_actual == anio %}selected{% endif %}>{{ anio }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label small text-muted mb-1">Mes</label>
|
|
<select name="mes" class="form-select form-select-sm">
|
|
<option value="01" {% if mes_actual == '01' %}selected{% endif %}>Enero</option>
|
|
<option value="02" {% if mes_actual == '02' %}selected{% endif %}>Febrero</option>
|
|
<option value="03" {% if mes_actual == '03' %}selected{% endif %}>Marzo</option>
|
|
<option value="04" {% if mes_actual == '04' %}selected{% endif %}>Abril</option>
|
|
<option value="05" {% if mes_actual == '05' %}selected{% endif %}>Mayo</option>
|
|
<option value="06" {% if mes_actual == '06' %}selected{% endif %}>Junio</option>
|
|
<option value="07" {% if mes_actual == '07' %}selected{% endif %}>Julio</option>
|
|
<option value="08" {% if mes_actual == '08' %}selected{% endif %}>Agosto</option>
|
|
<option value="09" {% if mes_actual == '09' %}selected{% endif %}>Septiembre</option>
|
|
<option value="10" {% if mes_actual == '10' %}selected{% endif %}>Octubre</option>
|
|
<option value="11" {% if mes_actual == '11' %}selected{% endif %}>Noviembre</option>
|
|
<option value="12" {% if mes_actual == '12' %}selected{% endif %}>Diciembre</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-1">
|
|
<label class="form-label small text-muted mb-1">Día</label>
|
|
<select name="dia" class="form-select form-select-sm">
|
|
<option value="">Todos</option>
|
|
{% for d in dias_disponibles %}
|
|
<option value="{{ d }}" {% if dia_actual == d %}selected{% endif %}>{{ d }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted mb-1">Zona</label>
|
|
<select name="zona_id" id="zonaSelect" class="form-select form-select-sm">
|
|
<option value="">Todas las Zonas</option>
|
|
{% for z in zonas %}
|
|
<option value="{{ z[0] }}" {% if zona_actual|string == z[0]|string %}selected{% endif %}>{{ z[1] }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted mb-1">Módulo</label>
|
|
<select name="modulo_id" id="moduloSelect" class="form-select form-select-sm">
|
|
<option value="">Todos los Módulos</option>
|
|
{% for m in modulos %}
|
|
<option value="{{ m[0] }}" data-zona="{{ m[2] }}" {% if modulo_actual|string == m[0]|string %}selected{% endif %}>{{ m[1] }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="col-md-1">
|
|
<button type="submit" class="btn btn-primary btn-sm w-100"><i class="bi bi-search"></i> Filtrar</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
{% for category, message in messages %}
|
|
<div class="alert alert-{{ category }}">{{ message|safe }}</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% endwith %}
|
|
|
|
<div class="card shadow-sm">
|
|
<div class="card-body p-0">
|
|
<table class="table table-striped table-hover mb-0">
|
|
<thead class="table-dark">
|
|
<tr>
|
|
<th>Fecha</th>
|
|
<th>Trabajador</th>
|
|
<th>Módulo</th>
|
|
<th>Total Declarado</th>
|
|
<th>Gastos</th>
|
|
<th class="text-end">Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for r in rendiciones %}
|
|
<tr>
|
|
<td class="align-middle">{{ r[1] }}</td>
|
|
<td class="align-middle">{{ r[2] }}</td>
|
|
<td class="align-middle"><span class="badge bg-info text-dark">{{ r[3] }}</span></td>
|
|
|
|
<td class="align-middle">
|
|
${{ "{:,.0f}".format((r[4] or 0) + (r[5] or 0) + (r[6] or 0) + (r[7] or 0)).replace(',', '.') }}
|
|
</td>
|
|
<td class="align-middle text-danger">${{ "{:,.0f}".format(r[8] or 0).replace(',', '.') }}</td>
|
|
<td class="text-end">
|
|
<div class="btn-group" role="group">
|
|
<button type="button" class="btn btn-sm btn-info text-white" data-bs-toggle="modal" data-bs-target="#viewRendicion{{ r[0] }}" title="Ver Detalle"><i class="bi bi-eye"></i></button>
|
|
<button type="button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#editRendicion{{ r[0] }}" title="Editar Valores Declarados"><i class="bi bi-pencil"></i></button>
|
|
<button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#deleteRendicion{{ r[0] }}" title="Eliminar Rendición"><i class="bi bi-trash"></i></button>
|
|
</div>
|
|
|
|
{{ rendicion_detail_modal(r, r[20], r[21], r[22]) }}
|
|
{{ edit_rendicion_modal(r, r[20], workers, modulos) }}
|
|
|
|
{{ confirm_modal(
|
|
id='deleteRendicion' ~ r[0],
|
|
title='Eliminar Rendición',
|
|
message='¿Estás seguro de que deseas eliminar la rendición #' ~ r[0] ~ '? Esta acción no se puede deshacer.',
|
|
action_url=url_for('delete_rendicion', id=r[0]),
|
|
btn_class='btn-danger',
|
|
btn_text='Eliminar'
|
|
) }}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="6" class="text-center py-4 text-muted">Aún no hay rendiciones enviadas.</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{{ alert_modal(id='errorPersonaModal', title='Error de Validación', message='') }}
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
// Función para manejar las etiquetas de jornada (Full/Part Time)
|
|
function updateBadge(selectElement, badgeId) {
|
|
const option = selectElement.options[selectElement.selectedIndex];
|
|
const tipo = option.getAttribute('data-tipo');
|
|
const badgeDiv = document.getElementById(badgeId);
|
|
|
|
if (!badgeDiv) return;
|
|
|
|
if (!tipo) {
|
|
badgeDiv.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
const color = (tipo === 'Full Time') ? 'bg-success' : 'bg-secondary';
|
|
badgeDiv.innerHTML = `<span class="badge ${color}">${tipo}</span>`;
|
|
}
|
|
|
|
function toggleCompDiv(id, select) {
|
|
const compDiv = document.getElementById(`comp_com_div_${id}`);
|
|
compDiv.style.display = select.value ? 'flex' : 'none';
|
|
updateBadge(select, `badge_comp_${id}`);
|
|
updateComisionToggle(select, `cc_${id}`);
|
|
}
|
|
|
|
function updateComisionToggle(selectElement, toggleId) {
|
|
const option = selectElement.options[selectElement.selectedIndex];
|
|
const tipoJornada = option.getAttribute('data-tipo');
|
|
const toggleSwitch = document.getElementById(toggleId);
|
|
|
|
if (toggleSwitch && tipoJornada) {
|
|
// Explicitly set to true if Full Time, false otherwise
|
|
toggleSwitch.checked = (tipoJornada === 'Full Time');
|
|
} else if (toggleSwitch && !selectElement.value) {
|
|
// If "Sin acompañante" is selected, turn it off
|
|
toggleSwitch.checked = false;
|
|
}
|
|
|
|
// Actualizar el badge también
|
|
const baseId = toggleId.split('_')[1];
|
|
const targetBadge = toggleId.startsWith('wc') ? `badge_worker_${baseId}` : `badge_comp_${baseId}`;
|
|
updateBadge(selectElement, targetBadge);
|
|
}
|
|
|
|
// Recalcular total de la línea de producto y el total del sistema
|
|
function recalcProductLine(input) {
|
|
const qty = parseInt(input.value) || 0;
|
|
const price = parseInt(input.getAttribute('data-price')) || 0;
|
|
const rid = input.getAttribute('data-rid');
|
|
const row = input.closest('tr');
|
|
|
|
// Actualizar línea individual
|
|
const lineTotal = qty * price;
|
|
row.querySelector('.item-total-line').innerText = '$' + lineTotal.toLocaleString('es-CL');
|
|
|
|
// Recalcular total general del sistema en el modal
|
|
const modal = document.getElementById(`editRendicion${rid}`);
|
|
let newSysTotal = 0;
|
|
modal.querySelectorAll('.prod-qty-input').forEach(inp => {
|
|
newSysTotal += (parseInt(inp.value) || 0) * (parseInt(inp.getAttribute('data-price')) || 0);
|
|
});
|
|
document.getElementById(`sys_total_${rid}`).innerText = '$' + newSysTotal.toLocaleString('es-CL');
|
|
}
|
|
|
|
function calcTotalEdit(id) {
|
|
const getVal = (inputId) => parseInt(document.getElementById(inputId).value.replace(/\D/g, '')) || 0;
|
|
const total = getVal(`edit_debito_${id}`) + getVal(`edit_credito_${id}`) + getVal(`edit_mp_${id}`) + getVal(`edit_efectivo_${id}`);
|
|
document.getElementById(`display_nuevo_total_${id}`).innerText = '$' + total.toLocaleString('es-CL');
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const editModals = document.querySelectorAll('[id^="editRendicion"]');
|
|
const editForms = document.querySelectorAll('form[action*="/admin/rendiciones/edit/"]');
|
|
const errorModalEl = document.getElementById('errorPersonaModal');
|
|
const errorModal = new bootstrap.Modal(errorModalEl);
|
|
const errorBody = document.getElementById('errorPersonaModalBody');
|
|
|
|
editForms.forEach(form => {
|
|
form.addEventListener('submit', function(e) {
|
|
const workerId = this.querySelector('select[name="worker_id"]').value;
|
|
const companionId = this.querySelector('select[name="companion_id"]').value;
|
|
|
|
if (companionId && workerId === companionId) {
|
|
e.preventDefault();
|
|
errorBody.innerHTML = "<strong>Error:</strong> El trabajador titular y el acompañante no pueden ser la misma persona. Por favor, selecciona a alguien más.";
|
|
errorModal.show();
|
|
}
|
|
});
|
|
});
|
|
|
|
editModals.forEach(modal => {
|
|
// Inicializar badges al abrir
|
|
modal.addEventListener('show.bs.modal', function() {
|
|
const rid = this.id.replace('editRendicion', '');
|
|
updateBadge(this.querySelector('select[name="worker_id"]'), `badge_worker_${rid}`);
|
|
const compSelect = this.querySelector('select[name="companion_id"]');
|
|
if (compSelect.value) updateBadge(compSelect, `badge_comp_${rid}`);
|
|
});
|
|
|
|
modal.addEventListener('hidden.bs.modal', function () {
|
|
const form = this.querySelector('form');
|
|
if (form) {
|
|
form.reset();
|
|
const rid = this.id.replace('editRendicion', '');
|
|
calcTotalEdit(rid);
|
|
// Resetear los subtotales visuales de productos
|
|
this.querySelectorAll('.prod-qty-input').forEach(inp => recalcProductLine(inp));
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
function validarNombresDiferentes(rendicionId) {
|
|
const workerSelect = document.querySelector(`select[name="worker_id"]`);
|
|
const companionSelect = document.querySelector(`select[name="companion_id"]`);
|
|
|
|
if (companionSelect.value && workerSelect.value === companionSelect.value) {
|
|
alert("Error: El trabajador titular y el acompañante no pueden ser la misma persona.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Vincula esta validación al evento submit del formulario de edición
|
|
document.querySelectorAll('form[action*="edit_rendicion"]').forEach(form => {
|
|
form.addEventListener('submit', function(e) {
|
|
const workerSelect = this.querySelector('select[name="worker_id"]');
|
|
const companionSelect = this.querySelector('select[name="companion_id"]');
|
|
|
|
if (companionSelect.value && workerSelect.value === companionSelect.value) {
|
|
e.preventDefault();
|
|
alert("Un trabajador no puede ser su propio acompañante. Por favor, corrige la selección.");
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const zonaSelect = document.getElementById('zonaSelect');
|
|
const moduloSelect = document.getElementById('moduloSelect');
|
|
const moduloOptions = Array.from(moduloSelect.options);
|
|
|
|
function filterModulos() {
|
|
const selectedZona = zonaSelect.value;
|
|
|
|
moduloOptions.forEach(option => {
|
|
if (option.value === "") {
|
|
// Siempre mostramos "Todos los Módulos"
|
|
option.style.display = '';
|
|
} else if (!selectedZona || option.dataset.zona === selectedZona) {
|
|
option.style.display = '';
|
|
} else {
|
|
option.style.display = 'none';
|
|
// Si el módulo seleccionado acaba de ocultarse, reseteamos el select
|
|
if (option.selected) {
|
|
moduloSelect.value = "";
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
zonaSelect.addEventListener('change', filterModulos);
|
|
// Ejecutar al cargar la página por si ya viene con una zona filtrada
|
|
filterModulos();
|
|
});
|
|
</script>
|
|
{% endblock %} |