40097-vm/calculo_costos_v3.php
2026-05-18 23:36:50 +00:00

398 lines
20 KiB
PHP

<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_role']) || !in_array($_SESSION['user_role'], ['Administrador', 'admin'])) {
header('Location: dashboard.php');
exit();
}
$pageTitle = "Cálculo de Costos V3";
include 'db/config.php';
include 'layout_header.php';
$db = db();
// Obtener productos para el select del modal
$stmt_products = $db->query("SELECT id, nombre FROM products ORDER BY nombre ASC");
$productos_select = $stmt_products->fetchAll(PDO::FETCH_ASSOC);
// Obtener videos y sus costos asociados de las tablas V3
$stmt = $db->query("SELECT mv.id, mv.orden, mv.foto_producto, p.nombre as nombre_producto,
mc.costo_producto, mc.costo_fijo_film, mc.comision_asesora,
mc.delivery, mc.costo_publicitario, mc.inversion_total,
mc.promo_1, mc.promo_2, mc.promo_3,
mc.comision_asesora_provincia, mc.delivery_provincia
FROM marketing_videos_v3 mv
LEFT JOIN products p ON mv.producto_id = p.id
LEFT JOIN marketing_costos_v3 mc ON mv.id = mc.video_id
ORDER BY mv.orden ASC, mv.id DESC");
$costos = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<style>
.table-v3 {
font-size: 0.8rem;
border-collapse: separate;
border-spacing: 0 5px;
}
.table-v3 th {
background-color: #f8f9fa;
border-bottom: 2px solid #dee2e6;
white-space: nowrap;
padding: 10px 5px;
position: sticky;
top: 0;
z-index: 10;
}
.table-v3 td {
vertical-align: middle;
padding: 6px 3px;
background-color: #fff;
}
.input-cell {
width: 100%;
min-width: 70px;
padding: 6px;
border: 2px solid #e9ecef;
border-radius: 6px;
text-align: center;
font-size: 0.85rem;
font-weight: 500;
transition: all 0.2s;
}
.input-cell:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.15);
outline: 0;
}
.input-cell.saving { background-color: #fff3cd !important; border-color: #ffc107 !important; }
.input-cell.saved { background-color: #d1e7dd !important; border-color: #198754 !important; }
.recaudo-v3 {
background-color: #f8f9fa;
font-weight: bold;
text-align: center;
padding: 6px 4px;
border-radius: 6px;
min-width: 85px;
border: 1px solid #dee2e6;
font-size: 0.8rem;
}
.recaudo-label {
font-size: 0.65rem;
display: block;
color: #6c757d;
margin-bottom: 2px;
}
.img-v3 {
width: 40px;
height: 40px;
object-fit: cover;
border-radius: 6px;
}
.btn-action {
width: 28px;
height: 28px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 6px;
}
.bg-provincia {
background-color: #fff4e6 !important;
}
.header-provincia {
background-color: #ffe8cc !important;
color: #d9480f !important;
}
</style>
<div class="d-flex justify-content-between align-items-center mb-4 mt-2">
<div>
<p class="text-muted mb-0">Versión V3: Tabla limpia e independiente. Los cambios se guardan automáticamente.</p>
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary" onclick="location.reload()">
<i class="fas fa-sync-alt"></i> Actualizar
</button>
<button type="button" class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#modalNuevoV3">
<i class="fas fa-plus me-2"></i> Nuevo Producto
</button>
</div>
</div>
<?php if (isset($_GET['success'])): ?>
<div class="alert alert-success alert-dismissible fade show shadow-sm" role="alert">
<i class="fas fa-check-circle me-2"></i> ¡Operación realizada con éxito!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<div class="card shadow-sm border-0">
<div class="card-body p-0">
<div class="table-responsive" style="max-height: 70vh;">
<table class="table table-v3 mb-0">
<thead>
<tr>
<th class="text-center">Orden</th>
<th>Producto</th>
<th class="text-center">Imagen</th>
<th class="text-center">Costo Prod.</th>
<th class="text-center">Film</th>
<th class="text-center">Asesora (L)</th>
<th class="text-center header-provincia">Asesora (P)</th>
<th class="text-center">Delivery (L)</th>
<th class="text-center header-provincia">Delivery (P)</th>
<th class="text-center">Publicidad</th>
<th class="text-center">Promo 1</th>
<th class="text-center">Recaudo 1</th>
<th class="text-center">Promo 2</th>
<th class="text-center">Recaudo 2</th>
<th class="text-center">Promo 3</th>
<th class="text-center">Recaudo 3</th>
<th class="text-center">Acción</th>
</tr>
</thead>
<tbody>
<?php if (empty($costos)): ?>
<tr>
<td colspan="17" class="text-center py-5 text-muted">
<i class="fas fa-info-circle me-2"></i> No hay productos en esta lista. Haz clic en "Nuevo Producto" para empezar.
</td>
</tr>
<?php endif; ?>
<?php foreach ($costos as $c): ?>
<?php
$costo_prod = ($c['costo_producto'] ?? 0);
$costo_film = ($c['costo_fijo_film'] ?? 0);
$costo_asesora = ($c['comision_asesora'] ?? 0);
$costo_asesora_p = ($c['comision_asesora_provincia'] ?? 0);
$costo_delivery = ($c['delivery'] ?? 0);
$costo_delivery_p = ($c['delivery_provincia'] ?? 0);
$costo_publicidad = ($c['costo_publicitario'] ?? 0);
function getVal($promo) {
if (empty($promo)) return 0;
preg_match('/[\d.]+/', $promo, $matches);
return isset($matches[0]) ? floatval($matches[0]) : 0;
}
$p1 = getVal($c['promo_1']);
$p2 = getVal($c['promo_2']);
$p3 = getVal($c['promo_3']);
// Cálculos Local
$r1_l = $p1 > 0 ? $p1 - ($costo_prod + $costo_film + $costo_asesora + $costo_delivery + $costo_publicidad) : null;
$r2_l = $p2 > 0 ? $p2 - (($costo_prod + $costo_film) * 2 + $costo_asesora + $costo_delivery + $costo_publicidad) : null;
$r3_l = $p3 > 0 ? $p3 - (($costo_prod + $costo_film) * 3 + $costo_asesora + $costo_delivery + $costo_publicidad) : null;
// Cálculos Provincia
$r1_p = $p1 > 0 ? $p1 - ($costo_prod + $costo_film + $costo_asesora_p + $costo_delivery_p + $costo_publicidad) : null;
$r2_p = $p2 > 0 ? $p2 - (($costo_prod + $costo_film) * 2 + $costo_asesora_p + $costo_delivery_p + $costo_publicidad) : null;
$r3_p = $p3 > 0 ? $p3 - (($costo_prod + $costo_film) * 3 + $costo_asesora_p + $costo_delivery_p + $costo_publicidad) : null;
?>
<tr id="row-<?php echo $c['id']; ?>" data-id="<?php echo $c['id']; ?>">
<td class="text-center fw-bold text-primary"><?php echo $c['orden']; ?></td>
<td style="max-width: 120px;">
<div class="text-truncate fw-bold" title="<?php echo htmlspecialchars($c['nombre_producto']); ?>">
<?php echo htmlspecialchars($c['nombre_producto'] ?: 'General'); ?>
</div>
</td>
<td class="text-center">
<?php if ($c['foto_producto']): ?>
<img src="<?php echo $c['foto_producto']; ?>" class="img-v3">
<?php else: ?>
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width:40px; height:40px;">
<i class="fas fa-image text-muted"></i>
</div>
<?php endif; ?>
</td>
<td><input type="number" step="0.01" class="input-cell cost-input" data-field="costo_producto" value="<?php echo $c['costo_producto']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input" data-field="costo_fijo_film" value="<?php echo $c['costo_fijo_film']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input" data-field="comision_asesora" value="<?php echo $c['comision_asesora']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input bg-provincia" data-field="comision_asesora_provincia" value="<?php echo $c['comision_asesora_provincia']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input" data-field="delivery" value="<?php echo $c['delivery']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input bg-provincia" data-field="delivery_provincia" value="<?php echo $c['delivery_provincia']; ?>"></td>
<td><input type="number" step="0.01" class="input-cell cost-input" data-field="costo_publicitario" value="<?php echo $c['costo_publicitario']; ?>"></td>
<td><input type="text" class="input-cell promo-input" data-field="promo_1" value="<?php echo htmlspecialchars($c['promo_1']); ?>"></td>
<td>
<div class="recaudo-v3 mb-1 <?php echo $r1_l >= 0 ? 'text-success' : 'text-danger'; ?>" id="r1l-<?php echo $c['id']; ?>">
<span class="recaudo-label">LOCAL</span>
<?php echo $r1_l !== null ? 'S/ '.number_format($r1_l, 2) : '-'; ?>
</div>
<div class="recaudo-v3 bg-provincia <?php echo $r1_p >= 0 ? 'text-success' : 'text-danger'; ?>" id="r1p-<?php echo $c['id']; ?>">
<span class="recaudo-label">PROVINCIA</span>
<?php echo $r1_p !== null ? 'S/ '.number_format($r1_p, 2) : '-'; ?>
</div>
</td>
<td><input type="text" class="input-cell promo-input" data-field="promo_2" value="<?php echo htmlspecialchars($c['promo_2']); ?>"></td>
<td>
<div class="recaudo-v3 mb-1 <?php echo $r2_l >= 0 ? 'text-success' : 'text-danger'; ?>" id="r2l-<?php echo $c['id']; ?>">
<span class="recaudo-label">LOCAL</span>
<?php echo $r2_l !== null ? 'S/ '.number_format($r2_l, 2) : '-'; ?>
</div>
<div class="recaudo-v3 bg-provincia <?php echo $r2_p >= 0 ? 'text-success' : 'text-danger'; ?>" id="r2p-<?php echo $c['id']; ?>">
<span class="recaudo-label">PROVINCIA</span>
<?php echo $r2_p !== null ? 'S/ '.number_format($r2_p, 2) : '-'; ?>
</div>
</td>
<td><input type="text" class="input-cell promo-input" data-field="promo_3" value="<?php echo htmlspecialchars($c['promo_3']); ?>"></td>
<td>
<div class="recaudo-v3 mb-1 <?php echo $r3_l >= 0 ? 'text-success' : 'text-danger'; ?>" id="r3l-<?php echo $c['id']; ?>">
<span class="recaudo-label">LOCAL</span>
<?php echo $r3_l !== null ? 'S/ '.number_format($r3_l, 2) : '-'; ?>
</div>
<div class="recaudo-v3 bg-provincia <?php echo $r3_p >= 0 ? 'text-success' : 'text-danger'; ?>" id="r3p-<?php echo $c['id']; ?>">
<span class="recaudo-label">PROVINCIA</span>
<?php echo $r3_p !== null ? 'S/ '.number_format($r3_p, 2) : '-'; ?>
</div>
</td>
<td class="text-center">
<button class="btn btn-danger btn-action" onclick="eliminarRow(<?php echo $c['id']; ?>)" title="Eliminar">
<i class="fas fa-trash-alt"></i>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Modal Nuevo -->
<div class="modal fade" id="modalNuevoV3" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow">
<form action="save_marketing_video_v3.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="redirect" value="calculo_costos_v3.php?success=1">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title"><i class="fas fa-plus-circle me-2"></i> Nuevo Producto (V3)</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-4">
<div class="mb-3">
<label class="form-label fw-bold">Seleccionar Producto</label>
<select name="producto_id" class="form-select form-select-lg" required onchange="fetchProductCost(this.value)">
<option value="">Seleccionar...</option>
<?php foreach ($productos_select as $p): ?>
<option value="<?php echo $p['id']; ?>"><?php echo htmlspecialchars($p['nombre']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">Costo Base (S/)</label>
<input type="number" name="costo_producto" id="costo_producto_nuevo_v3" class="form-control" step="0.01" placeholder="0.00">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-bold">Orden de Lista</label>
<input type="number" name="orden" class="form-control" value="1">
</div>
</div>
<div class="mb-0">
<label class="form-label fw-bold">Imagen del Producto</label>
<input type="file" name="foto_producto" class="form-control">
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary px-4">Crear Registro</button>
</div>
</form>
</div>
</div>
</div>
<script>
function fetchProductCost(productId) {
if (!productId) return;
fetch(`get_product_details.php?id=${productId}`)
.then(response => response.json())
.then(data => {
if (data.success && data.product.costo) {
document.getElementById('costo_producto_nuevo_v3').value = data.product.costo;
}
});
}
document.querySelectorAll('.input-cell').forEach(input => {
// Actualización instantánea visual
input.addEventListener('input', function() {
const row = this.closest('tr');
recalculateRowVisual(row);
});
// Guardado real al salir del cuadro
input.addEventListener('change', function() {
const row = this.closest('tr');
const id = row.dataset.id;
const field = this.dataset.field;
const value = this.value;
this.classList.add('saving');
fetch('update_marketing_costos_field_v3.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id, field, value })
})
.then(response => response.json())
.then(data => {
this.classList.remove('saving');
if (data.success) {
this.classList.add('saved');
setTimeout(() => this.classList.remove('saved'), 1000);
}
});
});
});
function recalculateRowVisual(row) {
const id = row.dataset.id;
const costProd = parseFloat(row.querySelector('[data-field="costo_producto"]').value) || 0;
const costFilm = parseFloat(row.querySelector('[data-field="costo_fijo_film"]').value) || 0;
const costAsesora = parseFloat(row.querySelector('[data-field="comision_asesora"]').value) || 0;
const costAsesoraP = parseFloat(row.querySelector('[data-field="comision_asesora_provincia"]').value) || 0;
const costDelivery = parseFloat(row.querySelector('[data-field="delivery"]').value) || 0;
const costDeliveryP = parseFloat(row.querySelector('[data-field="delivery_provincia"]').value) || 0;
const costPublicidad = parseFloat(row.querySelector('[data-field="costo_publicitario"]').value) || 0;
for (let i = 1; i <= 3; i++) {
const promoVal = row.querySelector(`[data-field="promo_${i}"]`).value;
const match = promoVal.match(/[\d.]+/);
const pVal = match ? parseFloat(match[0]) : 0;
const recaudoElL = row.querySelector(`#r${i}l-${id}`);
const recaudoElP = row.querySelector(`#r${i}p-${id}`);
if (pVal > 0) {
// Local
const recaudoL = pVal - ((costProd + costFilm) * i + costAsesora + costDelivery + costPublicidad);
recaudoElL.innerHTML = `<span class="recaudo-label">LOCAL</span>S/ ${recaudoL.toFixed(2)}`;
recaudoElL.className = 'recaudo-v3 mb-1 ' + (recaudoL >= 0 ? 'text-success' : 'text-danger');
// Provincia
const recaudoP = pVal - ((costProd + costFilm) * i + costAsesoraP + costDeliveryP + costPublicidad);
recaudoElP.innerHTML = `<span class="recaudo-label">PROVINCIA</span>S/ ${recaudoP.toFixed(2)}`;
recaudoElP.className = 'recaudo-v3 bg-provincia ' + (recaudoP >= 0 ? 'text-success' : 'text-danger');
} else {
recaudoElL.innerHTML = `<span class="recaudo-label">LOCAL</span>-`;
recaudoElP.innerHTML = `<span class="recaudo-label">PROVINCIA</span>-`;
}
}
}
function eliminarRow(id) {
if (confirm('¿Eliminar este registro de la V3?')) {
window.location.href = 'delete_marketing_video_v3.php?id=' + id;
}
}
</script>
<?php include 'layout_footer.php'; ?>