34849-vm/rentabilidad.php
2026-02-03 01:43:03 +00:00

463 lines
26 KiB
PHP

<?php
session_start();
require_once 'db/config.php';
// Verificar si el usuario está logueado y es Administrador
if (!isset($_SESSION['user_id']) || !in_array($_SESSION['user_role'], ['Administrador', 'admin'])) {
header('Location: login.php');
exit;
}
// Manejar acciones GET (como eliminar desde un enlace)
if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action'])) {
$db_get = db();
try {
if ($_GET['action'] === 'remove_product' && isset($_GET['reporte_id']) && isset($_GET['product_id'])) {
$stmt = $db_get->prepare("DELETE FROM rentabilidad_productos WHERE reporte_id = ? AND product_id = ?");
$stmt->execute([$_GET['reporte_id'], $_GET['product_id']]);
$_SESSION['message'] = '<div class="alert alert-info">Producto eliminado de este reporte.</div>';
}
} catch (PDOException $e) {
$_SESSION['message'] = '<div class="alert alert-danger">Error de base de datos: ' . $e->getMessage() . '</div>';
}
header('Location: rentabilidad.php');
exit;
}
$db = db();
$message = '';
// Manejar las acciones del formulario (POST requests)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
try {
switch ($_POST['action']) {
case 'create_report':
// 1. Crear el reporte
$stmt = $db->prepare("INSERT INTO rentabilidad_reportes (fecha_inicio, fecha_fin) VALUES (CURDATE(), CURDATE())");
$stmt->execute();
$reporte_id = $db->lastInsertId();
// 2. Poblar el reporte con todos los productos existentes
$products_stmt = $db->query("SELECT id FROM products");
$products_ids = $products_stmt->fetchAll(PDO::FETCH_COLUMN);
$insert_sql = "INSERT INTO rentabilidad_productos (reporte_id, product_id) VALUES (:reporte_id, :product_id)";
$insert_stmt = $db->prepare($insert_sql);
foreach ($products_ids as $product_id) {
$insert_stmt->execute([':reporte_id' => $reporte_id, ':product_id' => $product_id]);
}
$_SESSION['message'] = '<div class="alert alert-success">Nuevo reporte creado y poblado con todos los productos.</div>';
break;
case 'delete_report':
if (isset($_POST['reporte_id'])) {
$stmt = $db->prepare("DELETE FROM rentabilidad_reportes WHERE id = ?");
$stmt->execute([$_POST['reporte_id']]);
// Los productos asociados se borran en cascada por la BD
$_SESSION['message'] = '<div class="alert alert-success">Reporte eliminado correctamente.</div>';
}
break;
case 'save_report':
if (isset($_POST['reporte_id']) && isset($_POST['fecha_inicio']) && isset($_POST['fecha_fin'])) {
$reporte_id = $_POST['reporte_id'];
$stmt = $db->prepare("UPDATE rentabilidad_reportes SET fecha_inicio = ?, fecha_fin = ? WHERE id = ?");
$stmt->execute([$_POST['fecha_inicio'], $_POST['fecha_fin'], $reporte_id]);
if (isset($_POST['productos'])) {
$sql = "INSERT INTO rentabilidad_productos (reporte_id, product_id, recaudo, recaudo_ct, unidades_vendidas, unidades_vendidas_ct, costo_producto, costo_ads, comision)
VALUES (:reporte_id, :product_id, :recaudo, :recaudo_ct, :unidades_vendidas, :unidades_vendidas_ct, :costo_producto, :costo_ads, :comision)
ON DUPLICATE KEY UPDATE
recaudo = VALUES(recaudo),
recaudo_ct = VALUES(recaudo_ct),
unidades_vendidas = VALUES(unidades_vendidas),
unidades_vendidas_ct = VALUES(unidades_vendidas_ct),
costo_producto = VALUES(costo_producto),
costo_ads = VALUES(costo_ads),
comision = VALUES(comision)";
$stmt = $db->prepare($sql);
foreach ($_POST['productos'] as $product_id => $data) {
$stmt->execute([
':reporte_id' => $reporte_id,
':product_id' => $product_id,
':recaudo' => $data['recaudo'] ?: 0,
':recaudo_ct' => $data['recaudo_ct'] ?: 0,
':unidades_vendidas' => $data['unidades_vendidas'] ?: 0,
':unidades_vendidas_ct' => $data['unidades_vendidas_ct'] ?: 0,
':costo_producto' => $data['costo_producto'] ?: 0,
':costo_ads' => $data['costo_ads'] ?: 0,
':comision' => $data['comision'] ?: 0,
]);
}
}
$_SESSION['message'] = '<div class="alert alert-success">Reporte guardado correctamente.</div>';
}
break;
case 'remove_product':
if (isset($_POST['reporte_id']) && isset($_POST['product_id'])) {
$stmt = $db->prepare("DELETE FROM rentabilidad_productos WHERE reporte_id = ? AND product_id = ?");
$stmt->execute([$_POST['reporte_id'], $_POST['product_id']]);
$_SESSION['message'] = '<div class="alert alert-info">Producto eliminado de este reporte.</div>';
}
break;
case 'add_product':
if (isset($_POST['reporte_id']) && isset($_POST['product_id']) && !empty($_POST['product_id'])) {
$stmt = $db->prepare("INSERT IGNORE INTO rentabilidad_productos (reporte_id, product_id) VALUES (?, ?)");
$stmt->execute([$_POST['reporte_id'], $_POST['product_id']]);
$_SESSION['message'] = '<div class="alert alert-success">Producto añadido al reporte.</div>';
}
break;
}
} catch (PDOException $e) {
$_SESSION['message'] = '<div class="alert alert-danger">Error de base de datos: ' . $e->getMessage() . '</div>';
}
header('Location: rentabilidad.php');
exit;
}
if (isset($_SESSION['message'])) {
$message = $_SESSION['message'];
unset($_SESSION['message']);
}
// --- Carga de datos ---
$master_products = [];
try {
$products_stmt = $db->query("SELECT id, nombre as name, costo FROM products ORDER BY name ASC");
$master_products = $products_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$message .= '<div class="alert alert-danger">Error al cargar productos.</div>';
}
$reports = [];
try {
$reports_stmt = $db->query("SELECT * FROM rentabilidad_reportes ORDER BY fecha_inicio DESC, id DESC");
$reports = $reports_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$message .= '<div class="alert alert-danger">Error al cargar reportes.</div>';
}
$report_data = [];
try {
$report_data_stmt = $db->query("SELECT * FROM rentabilidad_productos");
$report_data_flat = $report_data_stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($report_data_flat as $item) {
$report_data[$item['reporte_id']][$item['product_id']] = $item;
}
} catch (PDOException $e) {
$message .= '<div class="alert alert-danger">Error al cargar datos de rentabilidad.</div>';
}
$pageTitle = "Reportes de Rentabilidad";
include 'layout_header.php';
?>
<?php if(!empty($message)) echo $message; ?>
<div class="card mb-4">
<div class="card-header"><h3 class="card-title">Gestión de Reportes</h3></div>
<div class="card-body">
<form method="POST" action="rentabilidad.php">
<input type="hidden" name="action" value="create_report">
<button type="submit" class="btn btn-primary"><i class="fas fa-plus"></i> Crear Nuevo Reporte de Rentabilidad</button>
</form>
</div>
</div>
<?php if (empty($reports)): ?>
<div class="alert alert-info">No hay reportes. ¡Crea uno para empezar!</div>
<?php endif; ?>
<?php foreach ($reports as $report): ?>
<div class="card mb-4" id="reporte-<?php echo $report['id']; ?>">
<form action="rentabilidad.php" method="POST">
<input type="hidden" name="reporte_id" value="<?php echo $report['id']; ?>">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">Reporte de Rentabilidad</h5>
<?php if (isset($report['fecha_creacion'])): ?>
<small class="text-muted">Registrado el: <?php echo date("d/m/Y", strtotime($report['fecha_creacion'])); ?></small>
<?php endif; ?>
</div>
<hr class="my-2">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex flex-row align-items-center">
<span class="mr-2" style="font-size: 0.9rem;">Periodo del</span>
<input type="date" name="fecha_inicio" class="form-control form-control-sm mr-2" style="width: auto;" value="<?php echo htmlspecialchars($report['fecha_inicio']); ?>">
<span class="mr-2" style="font-size: 0.9rem;">al</span>
<input type="date" name="fecha_fin" class="form-control form-control-sm" style="width: auto;" value="<?php echo htmlspecialchars($report['fecha_fin']); ?>">
</div>
<div>
<button type="submit" name="action" value="save_report" class="btn btn-success"><i class="fas fa-save"></i> Guardar Reporte</button>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead class="text-center">
<tr>
<th rowspan="2" class="align-middle">Producto</th>
<th colspan="2">Recaudo envios</th>
<th colspan="2">Recaudo Contraentrega</th>
<th rowspan="2" class="align-middle">Costo Producto</th>
<th rowspan="2" class="align-middle">Costo Ads</th>
<th rowspan="2" class="align-middle">Comisión</th>
<th rowspan="2" class="align-middle">Utilidad</th>
<th rowspan="2" class="align-middle">Acciones</th>
</tr>
<tr>
<th>Recaudo Env</th>
<th>Unds Vendidas Env</th>
<th>Recaudo CT</th>
<th>Uds vendidas CT</th>
</tr>
</thead>
<tbody>
<?php
// Obtener los IDs de productos que están en este reporte
$product_ids_in_report = array_keys($report_data[$report['id']] ?? []);
$products_in_report = array_filter($master_products, function($p) use ($product_ids_in_report) {
return in_array($p['id'], $product_ids_in_report);
});
// Calcular utilidad para cada producto y almacenar en un nuevo array
$products_with_utility = [];
$total_recaudo_env = 0;
$total_recaudo_ct = 0;
$total_unidades_env = 0;
$total_unidades_ct = 0;
$total_costo_producto_sum = 0;
$total_costo_ads = 0;
$total_comision = 0;
$total_utilidad = 0;
foreach ($products_in_report as $product) {
$report_product_data = $report_data[$report['id']][$product['id']] ?? null;
$recaudo = $report_product_data['recaudo'] ?? 0;
$recaudo_ct = $report_product_data['recaudo_ct'] ?? 0;
$unidades_vendidas = $report_product_data['unidades_vendidas'] ?? 0;
$unidades_vendidas_ct = $report_product_data['unidades_vendidas_ct'] ?? 0;
$costo_producto = $report_product_data['costo_producto'] ?? $product['costo'];
$costo_ads = $report_product_data['costo_ads'] ?? 0;
$comision = $report_product_data['comision'] ?? 0;
$utilidad = (floatval($recaudo) + floatval($recaudo_ct)) - ((intval($unidades_vendidas) + intval($unidades_vendidas_ct)) * floatval($costo_producto)) - floatval($costo_ads) - floatval($comision);
$products_with_utility[] = [
'product' => $product,
'utilidad' => $utilidad,
'recaudo' => $recaudo,
'recaudo_ct' => $recaudo_ct,
'unidades_vendidas' => $unidades_vendidas,
'unidades_vendidas_ct' => $unidades_vendidas_ct,
'costo_producto' => $costo_producto,
'costo_ads' => $costo_ads,
'comision' => $comision,
];
$total_recaudo_env += $recaudo;
$total_recaudo_ct += $recaudo_ct;
$total_unidades_env += $unidades_vendidas;
$total_unidades_ct += $unidades_vendidas_ct;
$total_costo_producto_sum += (intval($unidades_vendidas) + intval($unidades_vendidas_ct)) * floatval($costo_producto);
$total_costo_ads += $costo_ads;
$total_comision += $comision;
$total_utilidad += $utilidad;
}
// Ordenar el array por utilidad de mayor a menor
usort($products_with_utility, function($a, $b) {
return $b['utilidad'] <=> $a['utilidad'];
});
?>
<?php foreach ($products_with_utility as $item): ?>
<?php
$product = $item['product'];
$utilidad = $item['utilidad'];
$recaudo = $item['recaudo'];
$recaudo_ct = $item['recaudo_ct'];
$unidades_vendidas = $item['unidades_vendidas'];
$unidades_vendidas_ct = $item['unidades_vendidas_ct'];
$costo_producto = $item['costo_producto'];
$costo_ads = $item['costo_ads'];
$comision = $item['comision'];
?>
<tr class="product-row">
<td><?php echo htmlspecialchars($product['name']); ?></td>
<td><input type="number" step="0.01" name="productos[<?php echo $product['id']; ?>][recaudo]" value="<?php echo $recaudo; ?>" class="form-control calc-field recaudo-env"></td>
<td><input type="number" step="1" name="productos[<?php echo $product['id']; ?>][unidades_vendidas]" value="<?php echo $unidades_vendidas; ?>" class="form-control calc-field unidades-vendidas-env"></td>
<td><input type="number" step="0.01" name="productos[<?php echo $product['id']; ?>][recaudo_ct]" value="<?php echo $recaudo_ct; ?>" class="form-control calc-field recaudo-ct"></td>
<td><input type="number" step="1" name="productos[<?php echo $product['id']; ?>][unidades_vendidas_ct]" value="<?php echo $unidades_vendidas_ct; ?>" class="form-control calc-field unidades-vendidas-ct"></td>
<td><input type="number" step="0.01" name="productos[<?php echo $product['id']; ?>][costo_producto]" value="<?php echo $costo_producto; ?>" class="form-control calc-field costo-producto"></td>
<td><input type="number" step="0.01" name="productos[<?php echo $product['id']; ?>][costo_ads]" value="<?php echo $costo_ads; ?>" class="form-control calc-field costo-ads"></td>
<td><input type="number" step="0.01" name="productos[<?php echo $product['id']; ?>][comision]" value="<?php echo $comision; ?>" class="form-control calc-field comision"></td>
<td class="text-center align-middle utilidad-cell"><strong>S/ <?php echo number_format($utilidad, 2); ?></strong></td>
<td class="text-center align-middle">
<div class="dropdown">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="actions-<?php echo $product['id']; ?>-<?php echo $report['id']; ?>" data-bs-toggle="dropdown" aria-expanded="false">
Acciones
</button>
<ul class="dropdown-menu" aria-labelledby="actions-<?php echo $product['id']; ?>-<?php echo $report['id']; ?>">
<li>
<a href="rentabilidad.php?action=remove_product&reporte_id=<?php echo $report['id']; ?>&product_id=<?php echo $product['id']; ?>"
class="dropdown-item text-danger"
onclick="return confirm('¿Estás seguro de que quieres quitar este producto del reporte?');">
Eliminar
</a>
</li>
</ul>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($products_in_report)): ?>
<tr><td colspan="10" class="text-center">No hay productos en este reporte. Añade uno para empezar.</td></tr>
<?php endif; ?>
</tbody>
<tfoot class="text-center table-dark">
<tr>
<th>TOTALES</th>
<th id="total-recaudo-env-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_recaudo_env, 2); ?></th>
<th id="total-unidades-env-<?php echo $report['id']; ?>"><?php echo $total_unidades_env; ?></th>
<th id="total-recaudo-ct-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_recaudo_ct, 2); ?></th>
<th id="total-unidades-ct-<?php echo $report['id']; ?>"><?php echo $total_unidades_ct; ?></th>
<th id="total-costo-producto-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_costo_producto_sum, 2); ?></th>
<th id="total-costo-ads-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_costo_ads, 2); ?></th>
<th id="total-comision-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_comision, 2); ?></th>
<th id="total-utilidad-<?php echo $report['id']; ?>">S/ <?php echo number_format($total_utilidad, 2); ?></th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</div>
</form> <!-- Fin del form de guardar -->
<div class="card-footer">
<div class="d-flex justify-content-between align-items-center">
<div>
<form action="rentabilidad.php" method="POST" class="form-inline">
<input type="hidden" name="action" value="add_product">
<input type="hidden" name="reporte_id" value="<?php echo $report['id']; ?>">
<select name="product_id" class="form-control form-control-sm mr-2">
<option value="">-- Selecciona un producto para añadir --</option>
<?php
$products_not_in_report = array_filter($master_products, function($p) use ($product_ids_in_report) {
return !in_array($p['id'], $product_ids_in_report);
});
foreach ($products_not_in_report as $product) {
echo '<option value="' . $product['id'] . '">' . htmlspecialchars($product['name']) . '</option>';
}
?>
</select>
<button type="submit" class="btn btn-info btn-sm"><i class="fas fa-plus"></i> Añadir Producto</button>
</form>
</div>
<div>
<small class="text-muted mr-3">ID del Reporte: <?php echo $report['id']; ?></small>
<button type="button" class="btn btn-danger" onclick="document.getElementById('delete-form-<?php echo $report['id']; ?>').submit();"><i class="fas fa-trash"></i> Eliminar Reporte</button>
</div>
</div>
</div>
<form id="delete-form-<?php echo $report['id']; ?>" action="rentabilidad.php" method="POST" onsubmit="return confirm('¿Estás seguro de que quieres eliminar este reporte completo? Esta acción no se puede deshacer.');" style="display: none;">
<input type="hidden" name="action" value="delete_report">
<input type="hidden" name="reporte_id" value="<?php echo $report['id']; ?>">
</form>
</div>
<?php endforeach; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
function updateTotals(card) {
let totalRecaudoEnv = 0;
let totalUnidadesEnv = 0;
let totalRecaudoCt = 0;
let totalUnidadesCt = 0;
let totalCostoProductoSum = 0;
let totalCostoAds = 0;
let totalComision = 0;
let totalUtilidad = 0;
card.querySelectorAll('.product-row').forEach(row => {
const recaudoEnv = parseFloat(row.querySelector('.recaudo-env').value) || 0;
const unidadesVendidasEnv = parseInt(row.querySelector('.unidades-vendidas-env').value) || 0;
const recaudoCt = parseFloat(row.querySelector('.recaudo-ct').value) || 0;
const unidadesVendidasCt = parseInt(row.querySelector('.unidades-vendidas-ct').value) || 0;
const costoProducto = parseFloat(row.querySelector('.costo-producto').value) || 0;
const costoAds = parseFloat(row.querySelector('.costo-ads').value) || 0;
const comision = parseFloat(row.querySelector('.comision').value) || 0;
const utilidad = (recaudoEnv + recaudoCt) - ((unidadesVendidasEnv + unidadesVendidasCt) * costoProducto) - costoAds - comision;
totalRecaudoEnv += recaudoEnv;
totalUnidadesEnv += unidadesVendidasEnv;
totalRecaudoCt += recaudoCt;
totalUnidadesCt += unidadesVendidasCt;
totalCostoProductoSum += (unidadesVendidasEnv + unidadesVendidasCt) * costoProducto;
totalCostoAds += costoAds;
totalComision += comision;
totalUtilidad += utilidad;
});
const reportId = card.id.split('-')[1];
const formatCurrency = (value) => 'S/ ' + value.toFixed(2);
card.querySelector(`#total-recaudo-env-${reportId}`).textContent = formatCurrency(totalRecaudoEnv);
card.querySelector(`#total-unidades-env-${reportId}`).textContent = totalUnidadesEnv;
card.querySelector(`#total-recaudo-ct-${reportId}`).textContent = formatCurrency(totalRecaudoCt);
card.querySelector(`#total-unidades-ct-${reportId}`).textContent = totalUnidadesCt;
card.querySelector(`#total-costo-producto-${reportId}`).textContent = formatCurrency(totalCostoProductoSum);
card.querySelector(`#total-costo-ads-${reportId}`).textContent = formatCurrency(totalCostoAds);
card.querySelector(`#total-comision-${reportId}`).textContent = formatCurrency(totalComision);
card.querySelector(`#total-utilidad-${reportId}`).textContent = formatCurrency(totalUtilidad);
}
function updateUtility(row) {
const recaudoEnv = parseFloat(row.querySelector('.recaudo-env').value) || 0;
const unidadesVendidasEnv = parseInt(row.querySelector('.unidades-vendidas-env').value) || 0;
const recaudoCt = parseFloat(row.querySelector('.recaudo-ct').value) || 0;
const unidadesVendidasCt = parseInt(row.querySelector('.unidades-vendidas-ct').value) || 0;
const costoProducto = parseFloat(row.querySelector('.costo-producto').value) || 0;
const costoAds = parseFloat(row.querySelector('.costo-ads').value) || 0;
const comision = parseFloat(row.querySelector('.comision').value) || 0;
const totalRecaudo = recaudoEnv + recaudoCt;
const totalUnidades = unidadesVendidasEnv + unidadesVendidasCt;
const utilidad = totalRecaudo - (totalUnidades * costoProducto) - costoAds - comision;
const utilidadCell = row.querySelector('.utilidad-cell strong');
if (utilidadCell) {
utilidadCell.textContent = 'S/ ' + utilidad.toFixed(2);
}
}
document.querySelectorAll('.card.mb-4[id^="reporte-"]').forEach(card => {
card.querySelectorAll('.calc-field').forEach(field => {
field.addEventListener('input', () => {
const row = field.closest('.product-row');
updateUtility(row);
updateTotals(card);
});
});
});
});
</script>
<?php include 'layout_footer.php'; ?>