home
/
u529748449
/
domains
/
borabilhete.com
/
public_html
/
admin
➕ New
📤 Upload
✎ Editing:
index.php
← Back
<?php require_once __DIR__ . '/conexao.php'; require_once __DIR__ . '/auth.php'; error_reporting(E_ALL); ini_set('display_errors', 1); date_default_timezone_set('America/Sao_Paulo'); require_login(['admin','produtor']); // agente não acessa o dashboard if ($_SESSION['role'] === 'agente') { // alinhado com o botão/rota em plural header('Location: validar_ingresso.php'); exit; } // === Escopo por papel (usando alias 'e' para a tabela eventos) === $scope = scope_sql('e'); $SWHERE = $scope['where']; // ex.: " AND e.produtor_id = ? " $STYPES = $scope['types']; // ex.: "i" $SARGS = $scope['args']; // ex.: [123] // Helper para concatenar binds de 2 blocos (tipos + args) function binds(string $types1, array $args1, string $types2, array $args2): array { return [$types1 . $types2, array_merge($args1, $args2)]; } /* ----------------------------- Filtros (globais do topo) ----------------------------- */ // Lista de eventos para o select (já escopado) $eventos = []; $sqlEv = "SELECT e.id, e.nome FROM eventos e WHERE 1=1 {$SWHERE} ORDER BY e.data DESC"; $stEv = $conn->prepare($sqlEv); if ($STYPES) { $stEv->bind_param($STYPES, ...$SARGS); } $stEv->execute(); $rEv = $stEv->get_result(); while ($row = $rEv->fetch_assoc()) $eventos[] = $row; $stEv->close(); // Período padrão: últimos 30 dias $defaultFrom = (new DateTime('-30 days'))->format('Y-m-d'); $defaultTo = (new DateTime())->format('Y-m-d'); // Recebe filtros $eventoId = isset($_GET['evento']) && ctype_digit($_GET['evento']) ? (int)$_GET['evento'] : 0; $from = !empty($_GET['from']) ? $_GET['from'] : $defaultFrom; $to = !empty($_GET['to']) ? $_GET['to'] : $defaultTo; // Segurança simples do formato (YYYY-MM-DD) if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $from)) $from = $defaultFrom; if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $to)) $to = $defaultTo; // Monta WHERE + binds base (datas e, opcionalmente, evento) $where = "WHERE DATE(p.criado_em) BETWEEN ? AND ?"; $types = 'ss'; $args = [$from, $to]; if ($eventoId > 0) { $where .= " AND p.id_evento = ?"; $types .= 'i'; $args[] = $eventoId; } // Helper para executar uma consulta escalar (1 valor) function scalar(mysqli $conn, string $sql, string $types, array $args) { $st = $conn->prepare($sql); if (!$st) { throw new RuntimeException($conn->error); } if ($types) { $st->bind_param($types, ...$args); } $st->execute(); $res = $st->get_result(); $row = $res->fetch_row(); $st->close(); return $row ? $row[0] : null; } // Mescla binds: filtros do período/evento + escopo (role) [$BT, $BA] = binds($types, $args, $STYPES, $SARGS); /* ----------------------------- Consultas do dashboard (dados) ----------------------------- */ // KPIs $sqlPaidRevenue = " SELECT COALESCE(SUM(i.valor_total), 0) FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} "; $paidRevenue = (float) scalar($conn, $sqlPaidRevenue, $BT, $BA); $sqlTickets = " SELECT COALESCE(SUM(i.quantidade), 0) FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} "; $ticketsSold = (int) scalar($conn, $sqlTickets, $BT, $BA); $sqlCountPaid = " SELECT COUNT(*) FROM pedidos p JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} "; $ordersPaid = (int) scalar($conn, $sqlCountPaid, $BT, $BA); $sqlCountPend = " SELECT COUNT(*) FROM pedidos p JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pendente' {$SWHERE} "; $ordersPending = (int) scalar($conn, $sqlCountPend, $BT, $BA); $sqlCountCanc = " SELECT COUNT(*) FROM pedidos p JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'cancelado' {$SWHERE} "; $ordersCanceled = (int) scalar($conn, $sqlCountCanc, $BT, $BA); // Série por dia (pagos) $series = []; $sqlSeries = " SELECT DATE(p.criado_em) AS dia, COALESCE(SUM(i.valor_total), 0) AS total FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} GROUP BY dia ORDER BY dia ASC "; $st = $conn->prepare($sqlSeries); $st->bind_param($BT, ...$BA); $st->execute(); $r = $st->get_result(); while ($row = $r->fetch_assoc()) { $series[] = $row; } $st->close(); // Por forma de pagamento $pm = []; $sqlPm = " SELECT CASE WHEN p.forma_pagamento IS NULL OR TRIM(p.forma_pagamento) = '' OR LOWER(p.forma_pagamento) IN ('undefined','null') THEN 'Não informado' ELSE p.forma_pagamento END AS forma, COUNT(DISTINCT p.id) AS pedidos, COALESCE(SUM(i.quantidade),0) AS ingressos, COALESCE(SUM(i.valor_total),0) AS total FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} GROUP BY forma ORDER BY total DESC "; $st = $conn->prepare($sqlPm); $st->bind_param($BT, ...$BA); $st->execute(); $r = $st->get_result(); while ($row = $r->fetch_assoc()) $pm[] = $row; $st->close(); // Repasse estimado (por evento x forma de pagamento) // Normaliza nome da forma vindo do banco para: pix | credito | debito | null function normaliza_forma(string $raw): ?string { $s = strtolower(trim($raw)); $s = strtr($s, [ 'á'=>'a','à'=>'a','ã'=>'a','â'=>'a','ä'=>'a', 'é'=>'e','è'=>'e','ê'=>'e','ë'=>'e', 'í'=>'i','ì'=>'i','î'=>'i','ï'=>'i', 'ó'=>'o','ò'=>'o','õ'=>'o','ô'=>'o','ö'=>'o', 'ú'=>'u','ù'=>'u','û'=>'u','ü'=>'u', 'ñ'=>'n','ç'=>'c' ]); // mapeia variações comuns if ($s === 'pix') return 'pix'; if (in_array($s, ['credito','cartao credito','cartao_credito','credit_card','creditcard','mercadopago'], true)) return 'credito'; if (in_array($s, ['debito','cartao debito','cartao_debito','debit_card','debitcard'], true)) return 'debito'; return null; // "Não informado" ou algo diferente } // Busca agregados por EVENTO + FORMA para aplicar a taxa correta de cada evento $sqlPmRepasse = " SELECT e.id AS id_evento, COALESCE(NULLIF(TRIM(p.forma_pagamento), ''), 'Não informado') AS forma, COUNT(DISTINCT p.id) AS pedidos, COALESCE(SUM(i.valor_total),0) AS total, e.taxa_pix_tipo, e.taxa_pix_percentual, e.taxa_pix_valor, e.taxa_credito_tipo, e.taxa_credito_percentual, e.taxa_credito_valor, e.taxa_debito_tipo, e.taxa_debito_percentual, e.taxa_debito_valor FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} GROUP BY e.id, forma "; $st = $conn->prepare($sqlPmRepasse); $st->bind_param($BT, ...$BA); $st->execute(); $r = $st->get_result(); $repasseTotal = 0.0; // Fallbacks (quando não houver configuração no evento) $DEF = [ 'pix' => ['tipo' => 'percentual', 'perc' => 3.00, 'valor' => 0.00], 'credito' => ['tipo' => 'percentual', 'perc' => 8.00, 'valor' => 0.00], 'debito' => ['tipo' => 'percentual', 'perc' => 6.00, 'valor' => 0.00], ]; while ($row = $r->fetch_assoc()) { $formaCanon = normaliza_forma($row['forma']); if (!$formaCanon) { // se a forma não está mapeada (ex.: "Não informado"), considera sem taxa $repasseTotal += (float)$row['total']; continue; } // pega configuração do evento para a forma atual if ($formaCanon === 'pix') { $tipo = $row['taxa_pix_tipo'] ?: $DEF['pix']['tipo']; $perc = ($row['taxa_pix_percentual'] !== null) ? (float)$row['taxa_pix_percentual'] : $DEF['pix']['perc']; $valor = ($row['taxa_pix_valor'] !== null) ? (float)$row['taxa_pix_valor'] : $DEF['pix']['valor']; } elseif ($formaCanon === 'credito') { $tipo = $row['taxa_credito_tipo'] ?: $DEF['credito']['tipo']; $perc = ($row['taxa_credito_percentual'] !== null) ? (float)$row['taxa_credito_percentual'] : $DEF['credito']['perc']; $valor = ($row['taxa_credito_valor'] !== null) ? (float)$row['taxa_credito_valor'] : $DEF['credito']['valor']; } else { // debito $tipo = $row['taxa_debito_tipo'] ?: $DEF['debito']['tipo']; $perc = ($row['taxa_debito_percentual'] !== null) ? (float)$row['taxa_debito_percentual'] : $DEF['debito']['perc']; $valor = ($row['taxa_debito_valor'] !== null) ? (float)$row['taxa_debito_valor'] : $DEF['debito']['valor']; } $bruto = (float)$row['total']; $pedidos = (int)$row['pedidos']; if ($tipo === 'fixa') { // valor fixo por PEDIDO $liquido = max(0.0, $bruto - ($pedidos * max(0.0, $valor))); } else { // percentual sobre o total $p = max(0.0, min(100.0, (float)$perc)) / 100.0; $liquido = $bruto * (1.0 - $p); } $repasseTotal += $liquido; } $st->close(); // Por setor $setoresRows = []; $sqlSetor = " SELECT s.nome_setor, COALESCE(SUM(i.quantidade),0) AS ingressos, COALESCE(SUM(i.valor_total),0) AS total FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN setores s ON s.id = i.id_setor JOIN eventos e ON e.id = p.id_evento $where AND p.status_pagamento = 'pago' {$SWHERE} GROUP BY s.nome_setor ORDER BY total DESC, ingressos DESC LIMIT 12 "; $st = $conn->prepare($sqlSetor); $st->bind_param($BT, ...$BA); $st->execute(); $r = $st->get_result(); while ($row = $r->fetch_assoc()) $setoresRows[] = $row; $st->close(); // Pedidos (tabela) $pedidos = []; $sqlPedidos = " SELECT p.id, e.nome AS evento, p.nome_cliente, p.status_pagamento, COALESCE(NULLIF(TRIM(p.forma_pagamento), ''), 'Não informado') AS forma, p.criado_em, COALESCE(SUM(i.valor_total),0) AS total, COALESCE(SUM(i.quantidade),0) AS ingressos FROM pedidos p JOIN pedidos_itens i ON i.id_pedido = p.id JOIN eventos e ON e.id = p.id_evento $where {$SWHERE} GROUP BY p.id ORDER BY p.criado_em DESC "; $st = $conn->prepare($sqlPedidos); $st->bind_param($BT, ...$BA); $st->execute(); $r = $st->get_result(); while ($row = $r->fetch_assoc()) $pedidos[] = $row; $st->close(); /* ----------------------------- Funções de formatação usadas no dashboard ----------------------------- */ function brl($v){ return 'R$ ' . number_format((float)$v, 2, ',', '.'); } function dt($s){ return (new DateTime($s))->format('d/m/Y H:i'); } ?> <!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <title>Painel Admin</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"> <link rel="stylesheet" href="css/adminprodutor.css?v=2"> <link rel="stylesheet" href="../public/css/header.css"> </head> <body> <?php include __DIR__ . '/includes/header_admin.php'; ?> <div class="container"> <!-- Atalhos --> <div class="top-actions"> <a class="btn" href="cadastrar_evento.php"><i class="fa-solid fa-calendar-plus"></i> Criar Evento</a> <a class="btn" href="listar_eventos.php"><i class="fa-solid fa-folder-open"></i> Meus Eventos</a> <a class="btn" href="validar_ingresso.php"><i class="fa-solid fa-qrcode"></i> Validar ingressos</a> <?php if (!empty($_SESSION['role']) && in_array($_SESSION['role'], ['admin','produtor'], true)): ?> <a class="btn" href="time.php"><i class="fa-solid fa-users"></i> Time</a> <?php endif; ?> <?php if (!empty($_SESSION['role']) && $_SESSION['role'] === 'admin'): ?> <a class="btn" href="taxas.php"><i class="fa-solid fa-percent"></i> Taxas</a> <?php endif; ?> </div> <!-- Filtros globais --> <form class="filters" method="get"> <div class="field"> <label>Evento</label> <select name="evento"> <option value="0">Todos os eventos</option> <?php foreach($eventos as $ev): ?> <option value="<?= (int)$ev['id'] ?>" <?= $eventoId===(int)$ev['id']?'selected':'' ?>> <?= htmlspecialchars($ev['nome']) ?> </option> <?php endforeach; ?> </select> </div> <div class="field"> <label>De</label> <input type="date" name="from" value="<?= htmlspecialchars($from) ?>"> </div> <div class="field"> <label>Até</label> <input type="date" name="to" value="<?= htmlspecialchars($to) ?>"> </div> <button class="submit" type="submit"><i class="fa-solid fa-filter"></i> Aplicar filtros</button> </form> <?php include __DIR__ . '/dashboard.php'; ?> </div> </body> </html>
💾 Save Changes
Cancel
📤 Upload File
×
Select File
Upload
Cancel
➕ Create New
×
Type
📄 File
📁 Folder
Name
Create
Cancel
✎ Rename Item
×
Current Name
New Name
Rename
Cancel
🔐 Change Permissions
×
Target File
Permission (e.g., 0755, 0644)
0755
0644
0777
Apply
Cancel