Sistema de Gestión para Gimnasios, desarrollado con CodeIgniter 4 y MySQL, ideal para administrar de forma eficiente todas las operaciones de un centro deportivo.
🚀 ¿Qué incluye este sistema?
✔️ Registro y control de usuarios
✔️ Gestión de membresías y planes de pago
✔️ Control de asistencia diaria
✔️ Reportes de ingresos y membresías activas
✔️ Historial de pagos y suscripciones
✔️ Panel administrativo con estadísticas gráficas
🛠️ Tecnologías utilizadas: Backend: CodeIgniter 4 (framework PHP moderno, ligero y seguro) Base de datos: MySQL Frontend: HTML, Bootstrap 5, (personalizable y responsive).
Ticket de Pago
Dompdf
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<style>
*{
margin: 0;
padding: 0;
}
body {
font-family: "DejaVu Sans", sans-serif;
font-size: 10px;
margin: 0;
padding: 0;
width: 100%;
}
.ticket {
padding: 10px;
}
.logo {
text-align: center;
margin-bottom: 5px;
}
.logo img {
width: 80px;
height: auto;
}
.center {
text-align: center;
}
.bold {
font-weight: bold;
}
.title {
font-size: 14px;
}
.subtitle {
font-size: 11px;
}
.line {
border-top: 1px dashed #000;
margin: 8px 0;
}
table {
width: 100%;
}
td {
vertical-align: top;
}
.totales td {
font-size: 11px;
padding: 2px 0;
}
.totales .label {
font-weight: bold;
}
.footer {
text-align: center;
font-size: 9px;
margin-top: 10px;
font-style: italic;
}
</style>
</head>
<body>
<div class="ticket">
<div class="logo">
<img src="logo.png" alt="Logo">
</div>
<div class="center bold title">GIMNASIO ELITE FITNESS</div>
<div class="center subtitle">RUC: 12345678901</div>
<div class="center">Av. Ejemplo 123 - Lima</div>
<div class="center">Tel: 987 654 321</div>
<div class="line"></div>
<div><strong>Fecha:</strong> 2025-06-19 10:23 AM</div>
<div><strong>Cliente:</strong> Juan Pérez</div>
<div><strong>DNI:</strong> 12345678</div>
<div><strong>Atendido por:</strong> Admin</div>
<div class="line"></div>
<table>
<tr>
<td>Membresía Mensual</td>
<td style="text-align: right;">S/ 100.00</td>
</tr>
</table>
<div class="line"></div>
<table class="totales">
<tr>
<td class="label">TOTAL</td>
<td style="text-align: right;" class="label">S/ 100.00</td>
</tr>
<tr>
<td>Efectivo</td>
<td style="text-align: right;">S/ 100.00</td>
</tr>
<tr>
<td>Cambio</td>
<td style="text-align: right;">S/ 0.00</td>
</tr>
</table>
<div class="line"></div>
<div class="footer">
¡Gracias por su pago!<br>
Su compromiso con la salud es nuestra motivación.
</div>
</div>
</body>
</html>
Logo en ticket con DOMPDF
- Es muy importantes tener activo la extensión gd de PHP para mostrar imágenes en el pdf.
- Agregar las opciones a dompdf
- Agregar la ruta absoluta de la imagen.
use Dompdf\Dompdf;
use Dompdf\Options;
$options = new Options();
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
Reportes de Movimientos
Caja – Pagos

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
margin: 20px;
color: #444;
}
.header {
display: flex;
align-items: center;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
margin-bottom: 20px;
}
.header img {
width: 80px;
margin-right: 20px;
}
.header .company-info {
font-size: 14px;
}
.title {
background-color: #4CAF50;
color: white;
padding: 6px;
margin-bottom: 8px;
font-weight: bold;
}
.box {
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
margin-bottom: 15px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 8px;
}
th {
background-color: #E0F2F1;
color: #00695C;
text-align: left;
padding: 6px;
}
td {
padding: 6px;
border-bottom: 1px solid #eee;
}
.total-row {
font-weight: bold;
background-color: #F1F8E9;
}
.highlight {
color: #388E3C;
font-weight: bold;
}
</style>
</head>
<body>
<div class="header">
<img src="<?= base_url('uploads/logo.png') ?>" alt="Logo">
<div class="company-info">
<strong>Mi Empresa S.A.</strong><br>
RUC: 12345678901<br>
Dirección: Av. Principal 123, Lima<br>
Teléfono: (01) 234-5678
</div>
</div>
<div class="box">
<div class="title">Monto Inicial y Gastos</div>
<table>
<tr>
<th>Monto Inicial</th>
<th>Gastos</th>
</tr>
<tr>
<td>S/ 90,000.00</td>
<td>S/ 0.00</td>
</tr>
</table>
</div>
<div class="box">
<div class="title">Ventas por Método de Pago</div>
<table>
<tr>
<th>Método de Pago</th>
<th>Total</th>
</tr>
<tr>
<td>—</td>
<td>S/ 0.00</td>
</tr>
<tr class="total-row">
<td>Total General</td>
<td class="highlight">S/ 0.00</td>
</tr>
</table>
</div>
<div class="box">
<div class="title">Membresías por Método de Pago</div>
<table>
<tr>
<th>Método de Pago</th>
<th>Total</th>
</tr>
<tr>
<td>Efectivo</td>
<td>S/ 150.00</td>
</tr>
<tr class="total-row">
<td>Total General</td>
<td class="highlight">S/ 150.00</td>
</tr>
</table>
</div>
<div class="box">
<div class="title">Resumen del Cuadre de Caja</div>
<table>
<tr>
<td>Monto Inicial</td>
<td>S/ 90,000.00</td>
</tr>
<tr>
<td>Total Métodos de Pago</td>
<td>S/ 0.00</td>
</tr>
<tr>
<td>Gastos</td>
<td>S/ 0.00</td>
</tr>
<tr>
<td>Pagos Membresías</td>
<td>S/ 150.00</td>
</tr>
<tr class="total-row">
<td>Saldo Restante</td>
<td class="highlight">S/ 90,150.00</td>
</tr>
</table>
</div>
</body>
</html>
CREAR CÓDIGO QR.
https://github.com/endroid/qr-code
$qrName = uniqid($user['username'] . '_');
$directorio = 'images/qrcodes/' . $qrName . '.png';
$companyModel = new CompanyModel();
$company = $companyModel->select('name')->first();
//CREAR CODIGO QR
$builder = new Builder(
writer: new PngWriter(),
writerOptions: [],
validateResult: false,
data: $qrName,
encoding: new Encoding('UTF-8'),
errorCorrectionLevel: ErrorCorrectionLevel::High,
size: 300,
margin: 10,
roundBlockSizeMode: RoundBlockSizeMode::Margin,
logoPath: base_url('/images/logo.png'),
logoResizeToWidth: 50,
logoPunchoutBackground: true,
labelText: $company['name'],
labelFont: new OpenSans(20),
labelAlignment: LabelAlignment::Center
);
$result = $builder->build();
$result->saveToFile($directorio);
Descargar CARD con Canvas
https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js
html2canvas(document.querySelector('.profile-card-3')).then(function (canvas) {
// Crea un enlace para descargar la imagen
let link = document.createElement('a');
link.download = 'tarjeta.png';
link.href = canvas.toDataURL();
link.click();
});
Modal Tarjeta
<div class="modal fade" id="modalTarjeta" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" role="dialog" aria-labelledby="modalTitleId" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="modalTitleId"> Tarjeta </h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="text-center"> <button id="download-btn" class="btn btn-primary btn-sm">Descargar Tarjeta</button> </div> <hr> <div class="row"> <div class="col-md-8 mx-auto"> <div class="card profile-card-3"> <div class="background-block"></div> <div class="profile-thumb-block"> <img id="card-avatar" src="https://randomuser.me/api/portraits/men/78.jpg" alt="profile-image" class="profile" /> </div> <div class="card-content"> <h2 id="card-name"></h2> <div class="icon-block"> <img id="card-qr" class="img-thumbnail" src="https://randomuser.me/api/portraits/men/78.jpg" alt="qr-image" /> </div> </div> </div> </div> </div> </div> </div> </div> </div>
Estilos Tarjeta
css
/*Profile Card 3*/
.profile-card-3 {
font-family: "Open Sans", Arial, sans-serif;
position: relative;
float: left;
overflow: hidden;
width: 100%;
text-align: center;
border: none;
}
.profile-card-3 .background-block {
float: left;
width: 100%;
height: 180px;
background: #000;
}
.profile-card-3 .card-content {
width: 100%;
padding: 15px 25px;
color: #232323;
float: left;
background: #efefef;
height: 50%;
border-radius: 0 0 5px 5px;
position: relative;
z-index: 9999;
}
.profile-card-3 .card-content::before {
content: "";
background: #efefef;
width: 120%;
height: 100%;
left: 11px;
bottom: 51px;
position: absolute;
z-index: -1;
transform: rotate(-13deg);
}
.profile-card-3 .profile {
border-radius: 50%;
position: absolute;
top: 15%;
left: 50%;
max-width: 100px;
opacity: 1;
box-shadow: 3px 3px 20px rgba(0, 0, 0, 0.5);
border: 2px solid rgba(255, 255, 255, 1);
-webkit-transform: translate(-50%, 0%);
transform: translate(-50%, 0%);
z-index: 99999;
}
.profile-card-3 h2 {
margin: 0 0 5px;
font-weight: 600;
font-size: 25px;
}
.profile-card-3 h2 small {
display: block;
font-size: 15px;
margin-top: 10px;
}
.profile-card-3 i {
display: inline-block;
font-size: 16px;
color: #232323;
text-align: center;
border: 1px solid #232323;
width: 30px;
height: 30px;
line-height: 30px;
border-radius: 50%;
margin: 0 5px;
}
.profile-card-3 .icon-block {
float: left;
width: 100%;
margin-top: 15px;
}
.profile-card-3 .icon-block a {
text-decoration: none;
}
.profile-card-3 i:hover {
background-color: #232323;
color: #fff;
text-decoration: none;
}