270 lines
11 KiB
PHP
Executable File
270 lines
11 KiB
PHP
Executable File
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h2><i class="bi bi-file-earmark-arrow-up"></i> Importación de Datos</h2>
|
|
<p class="text-muted">Importación masiva de datos al sistema (formato CSV)</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-8 offset-md-2">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Seleccionar Tipo de Importación</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-4">
|
|
<label class="form-label">¿Qué deseas importar?</label>
|
|
<select id="importTypeSelector" class="form-select form-select-lg">
|
|
<option value="">-- Selecciona una opción --</option>
|
|
<option value="houses">Casas</option>
|
|
<option value="payments">Pagos de Agua</option>
|
|
<option value="expenses">Gastos</option>
|
|
<option value="concept_payments">Pagos por Concepto Especial</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div id="importArea" style="display: none;">
|
|
<form id="importForm">
|
|
<input type="hidden" name="type" id="importTypeInput">
|
|
<div id="dynamicFields"></div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Archivo CSV</label>
|
|
<input type="file" class="form-control" name="file" accept=".csv" required>
|
|
</div>
|
|
|
|
<div id="formatInfo" class="alert alert-info small mb-3"></div>
|
|
|
|
<div class="d-flex gap-2">
|
|
<button type="button" id="downloadTemplateBtn" class="btn btn-outline-primary">
|
|
<i class="bi bi-download"></i> Descargar Plantilla
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-upload"></i> Importar
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="placeholder" class="text-center py-5 text-muted">
|
|
<i class="bi bi-arrow-up-circle display-4"></i>
|
|
<p class="mt-3">Selecciona un tipo de importación para continuar</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0"><i class="bi bi-clock-history"></i> Historial de Importaciones</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Fecha</th>
|
|
<th>Tipo</th>
|
|
<th>Registros</th>
|
|
<th>Estado</th>
|
|
<th>Usuario</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="importHistory">
|
|
<tr><td colspan="5" class="text-muted">No hay importaciones recientes</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
$conceptsJson = json_encode($concepts);
|
|
?>
|
|
|
|
<script>
|
|
const conceptsData = <?= $conceptsJson ?>;
|
|
|
|
const importTypes = {
|
|
houses: {
|
|
title: 'Importar Casas',
|
|
description: 'Importa o actualiza la información de las casas del condominio.',
|
|
fieldsHtml: '',
|
|
format: 'number,status,consumption_only,owner_name,owner_email,owner_phone',
|
|
examples: '001,activa,0,Juan Pérez,juan@email.com,555-1234\n002,activa,1,Maria García,maria@email.com,555-5678\n003,deshabitada,0,,,',
|
|
template: 'number,status,consumption_only,owner_name,owner_email,owner_phone\n001,activa,0,Juan Pérez,juan@email.com,555-1234\n002,activa,1,Maria García,maria@email.com,555-5678\n003,deshabitada,0,,,',
|
|
filename: 'plantilla_importar_casas.csv'
|
|
},
|
|
payments: {
|
|
title: 'Importar Pagos de Agua',
|
|
description: 'Importa pagos mensuales de agua para las casas.',
|
|
fieldsHtml: '',
|
|
format: 'year,house_number,month,amount,payment_date,payment_method,notes',
|
|
examples: '2025,001,Enero,250.00,2025-01-15,Efectivo,Pago mensual\n2025,002,Enero,250.00,2025-01-16,Transferencia,Pago transferencia\n2024,003,Diciembre,250.00,2024-12-20,Efectivo,Pago diciembre 2024',
|
|
template: 'year,house_number,month,amount,payment_date,payment_method,notes\n2025,001,Enero,250.00,2025-01-15,Efectivo,Pago mensual\n2025,002,Enero,250.00,2025-01-16,Transferencia,Pago transferencia\n2024,003,Diciembre,250.00,2024-12-20,Efectivo,Pago diciembre 2024',
|
|
filename: 'plantilla_importar_pagos_agua.csv'
|
|
},
|
|
expenses: {
|
|
title: 'Importar Gastos',
|
|
description: 'Importa gastos del condominio.',
|
|
fieldsHtml: '',
|
|
format: 'description,amount,expense_date,category,notes',
|
|
examples: 'Mantenimiento jardín,150.00,2025-01-10,Mantenimiento,Pago jardinero\nCompra insumos,75.50,2025-01-12,Insumos,Tornillos y clavos',
|
|
template: 'description,amount,expense_date,category,notes\nMantenimiento jardín,150.00,2025-01-10,Mantenimiento,Pago jardinero\nCompra insumos,75.50,2025-01-12,Insumos,Tornillos y clavos',
|
|
filename: 'plantilla_importar_gastos.csv'
|
|
},
|
|
concept_payments: {
|
|
title: 'Importar Pagos por Concepto Especial',
|
|
description: 'Importa pagos para uno o varios conceptos especiales.',
|
|
format: 'concept_id,house_number,amount,payment_date,notes',
|
|
examples: '1,001,200.00,2025-01-15,Pago cuota\n1,002,200.00,2025-01-16,Pago cuota\n2,003,300.00,2025-01-17,Pago fondo',
|
|
template: 'concept_id,house_number,amount,payment_date,notes\n1,001,200.00,2025-01-15,Pago cuota\n1,002,200.00,2025-01-16,Pago cuota\n2,003,300.00,2025-01-17,Pago fondo',
|
|
filename: 'plantilla_importar_pagos_concepto.csv'
|
|
}
|
|
};
|
|
|
|
document.getElementById('importTypeSelector').addEventListener('change', function() {
|
|
const type = this.value;
|
|
const importArea = document.getElementById('importArea');
|
|
const placeholder = document.getElementById('placeholder');
|
|
const dynamicFields = document.getElementById('dynamicFields');
|
|
const formatInfo = document.getElementById('formatInfo');
|
|
|
|
if (!type) {
|
|
importArea.style.display = 'none';
|
|
placeholder.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
const config = importTypes[type];
|
|
document.getElementById('importTypeInput').value = type;
|
|
|
|
let fieldsHtml = '';
|
|
let conceptHelp = '';
|
|
|
|
if (type === 'concept_payments') {
|
|
conceptHelp = '<div class="alert alert-secondary mb-3"><strong>Conceptos disponibles (ID - Nombre):</strong><br>';
|
|
conceptsData.forEach(function(c, index) {
|
|
const separator = index === conceptsData.length - 1 ? '' : ' | ';
|
|
conceptHelp += '<code>' + c.id + ' - ' + c.name + '</code>' + separator;
|
|
});
|
|
conceptHelp += '</div>';
|
|
fieldsHtml += conceptHelp;
|
|
}
|
|
|
|
dynamicFields.innerHTML = fieldsHtml;
|
|
|
|
formatInfo.innerHTML = '<strong>Formato esperado:</strong><br>' + config.format + '<br><br>' +
|
|
'<em>Ejemplo:</em><br><code>' + config.examples.replace(/\n/g, '<br>') + '</code><br><br>' +
|
|
'<small class="text-muted">' + config.description + '</small>';
|
|
|
|
importArea.style.display = 'block';
|
|
placeholder.style.display = 'none';
|
|
});
|
|
|
|
document.getElementById('downloadTemplateBtn').addEventListener('click', function() {
|
|
const type = document.getElementById('importTypeSelector').value;
|
|
if (type) {
|
|
downloadTemplate(type);
|
|
}
|
|
});
|
|
|
|
function downloadTemplate(type) {
|
|
const config = importTypes[type];
|
|
const csv = config.template;
|
|
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
|
const link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = config.filename;
|
|
link.click();
|
|
}
|
|
|
|
document.getElementById('importForm').addEventListener('submit', importData);
|
|
|
|
function importData(e) {
|
|
e.preventDefault();
|
|
const form = e.target;
|
|
const formData = new FormData(form);
|
|
const file = formData.get('file');
|
|
|
|
if (!file) {
|
|
Swal.fire('Error', 'Debe seleccionar un archivo', 'error');
|
|
return;
|
|
}
|
|
|
|
Swal.fire({
|
|
title: 'Importando...',
|
|
text: 'Procesando archivo, por favor espere',
|
|
allowOutsideClick: false,
|
|
didOpen: () => Swal.showLoading()
|
|
});
|
|
|
|
fetch('/dashboard.php?page=import_actions&action=import', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
Swal.fire('Éxito', data.message, 'success').then(() => location.reload());
|
|
} else {
|
|
Swal.fire('Error', data.message || 'Error al importar', 'error');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
Swal.fire('Error', 'Error de conexión', 'error');
|
|
});
|
|
}
|
|
|
|
function loadImportHistory() {
|
|
fetch('/dashboard.php?page=import_actions&action=history')
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success && data.data.length > 0) {
|
|
const tbody = document.getElementById('importHistory');
|
|
tbody.innerHTML = '';
|
|
|
|
data.data.forEach(log => {
|
|
const row = document.createElement('tr');
|
|
|
|
// Extraer tipo y registros de los detalles
|
|
const details = log.details || '';
|
|
let type = 'Desconocido';
|
|
let records = '0';
|
|
|
|
if (details.includes('Importación houses')) {
|
|
type = 'Casas';
|
|
} else if (details.includes('Importación payments')) {
|
|
type = 'Pagos de Agua';
|
|
} else if (details.includes('Importación expenses')) {
|
|
type = 'Gastos';
|
|
} else if (details.includes('Importación concept_payments')) {
|
|
type = 'Pagos por Concepto';
|
|
}
|
|
|
|
const recordsMatch = details.match(/(\d+)\s+registros/);
|
|
if (recordsMatch) {
|
|
records = recordsMatch[1];
|
|
}
|
|
|
|
row.innerHTML = `
|
|
<td>${new Date(log.created_at).toLocaleString('es-MX')}</td>
|
|
<td>${type}</td>
|
|
<td>${records}</td>
|
|
<td><span class="badge bg-success">Exitoso</span></td>
|
|
<td>${log.username || 'N/A'}</td>
|
|
`;
|
|
|
|
tbody.appendChild(row);
|
|
});
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error al cargar historial:', error);
|
|
});
|
|
}
|
|
|
|
// Cargar historial al iniciar la página
|
|
document.addEventListener('DOMContentLoaded', loadImportHistory);
|
|
|
|
</script>
|