Ya tenemos la base del proyecto, ahora lo que sigue es darle forma creando los menús

Ya tenemos la base del proyecto, ahora lo que sigue es darle forma creando los menús
En esta serie de publicaciones vamos a hacer un sistema de punto de venta con el Framework de PHP CodeIgniter 4
El sistema será igual al JCPOS que ya veníamos haciendo pero con todas las ventajas que ofrece CodeIgniter
Primero crearemos el proyecto con Composer
composer create-project codeigniter4/appstarter ci4jcpos
Creamos nuestra base de datos en phpmyadmin con el nombre ci4jcpos
CREATE SCHEMA ci4jcpos DEFAULT CHARACTER SET utf8 COLLATE utf8_spanish2_ci
Ahora instalamos la plantilla boilerplate el cual nos instalara la plantilla adminlte3 con el administrador de usuario auth, lo instalamos corriendo el siguiente comando dentro del proyecto
En mi caso yo deje en así app/config/database.php
public array $default = [
'DSN' => '',
'hostname' => '127.0.0.1',
'username' => 'root',
'password' => '',
'database' => 'ci4jcpos',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => true,
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
];
composer require julio101290/boilerplate
Ahora siguiente las instrucciones del paquete https://packagist.org/packages/julio101290/boilerplate corremos el comando migrate para auth
php spark auth:publish
Publish Migration? [y, n]: y
created: Database/Migrations/2017-11-20-223112_create_auth_tables.php
Remember to run `spark migrate -all` to migrate the database.
Publish Models? [y, n]: n
Publish Entities? [y, n]: n
Publish Controller? [y, n]: n
Publish Views? [y, n]: n
Publish Filters? [y, n]: n
Publish Config file? [y, n]: y
created: Config/Auth.php
Publish Language file? [y, n]: n
En app/config/auth.php modifcamos la matriz/arreglo de $views y la dejamos asi
public $views = [
'login' => 'julio101290\boilerplate\Views\Authentication\login',
'register' => 'julio101290\boilerplate\Views\Authentication\register',
'forgot' => 'julio101290\boilerplate\Views\Authentication\forgot',
'reset' => 'julio101290\boilerplate\Views\Authentication\reset',
'emailForgot' => 'julio101290\boilerplate\Views\Authentication\emails\forgot',
'emailActivation' => 'julio101290\boilerplate\Views\Authentication\emails\activation',
];
En app/config/filters.php en la matriz aliases agregamos los siguientes valores, ojo, no quitar los que estaban, solo agregar los que hacen falta
public $aliases = [
'login' => \Myth\Auth\Filters\LoginFilter::class,
'role' => \julio101290\boilerplate\Filters\RoleFilter::class,
'permission' => \julio101290\boilerplate\Filters\PermissionFilter::class,
];
Instalamos boilerplate con el siguiente comando
php spark boilerplate:install
En App/config/validation.php agregamos lo siguiente en la matriz de $$rulesSet
public $$ruleSets = [
\Myth\Auth\Authentication\Passwords\ValidationRules::class,
];
En App/entities/users.php en la matriz $cast lo dejamos así
protected $casts = [
'username' => 'string',
'email' => 'string',
'firstname' => 'string',
'lastname' => 'string',
'active' => 'boolean',
'force_pass_reset' => 'boolean',
];
En app/controller/home.php lo dejamos así para que entre directamente al administrador
<?php
namespace App\Controllers;
class Home extends BaseController
{
public function index()
{
return redirect()->to("/admin");
}
}
En app/config/constants.php al final del archivo le agregamos la siguiente constante para que nos permita debugear, una vez que este en producción se tiene que quitar
define("ENVIRONMENT","development");
En app/config/app.php le quita a la variable $indexPage el valor dejandolo en blanco, la variable defaultLocale y supportedLocales la dejamos con el valor “es”
public string $indexPage = '';
public string $defaultLocale = 'es';
public array $supportedLocales = ['en'];
En el archivo app/config/boilerplate.php asignamos el nombre de la app y en $i18n que es para el lenguaje de los datatables lo dejamos como Spanish
JCPOS es un sistema de punto de venta (POS) de código abierto desarrollado en PHP. Recientemente, JCPOS se ha migrado a CodeIgniter 4, lo que ha mejorado significativamente su rendimiento y escalabilidad. En este artículo, exploraremos los detalles de la migración de JCPOS a CodeIgniter 4 y sus beneficios.
Antes de profundizar en la migración de JCPOS a CodeIgniter 4, es importante comprender qué es CodeIgniter y por qué es una opción popular para desarrolladores de PHP.
CodeIgniter es un framework PHP de código abierto que se utiliza para desarrollar aplicaciones web dinámicas y sitios web. Es popular debido a su facilidad de uso, velocidad y seguridad. Además, CodeIgniter tiene una gran comunidad de desarrolladores que proporciona soporte y actualizaciones regulares.
La migración de JCPOS a CodeIgniter 4 implica actualizar el código de JCPOS para que sea compatible con la última versión del framework. CodeIgniter 4 presenta varias mejoras y cambios significativos en comparación con su versión anterior, CodeIgniter 3. Algunas de estas mejoras incluyen:
Para migrar JCPOS a CodeIgniter 4, los desarrolladores tuvieron que actualizar el código de JCPOS para utilizar las nuevas características y métodos de CodeIgniter 4. Esto incluyó cambios en la estructura del directorio, en la configuración del archivo y en el uso de nuevos métodos y características de CodeIgniter 4.
Una vez completada la migración, JCPOS obtuvo varios beneficios significativos. En primer lugar, el rendimiento y la velocidad de JCPOS se mejoraron considerablemente gracias a la utilización de características avanzadas de PHP 7 y a la optimización de la arquitectura de CodeIgniter 4. Esto significa que el sistema puede manejar más transacciones y usuarios simultáneamente, lo que es especialmente importante en entornos de punto de venta de alta demanda.
Además, la migración a CodeIgniter 4 proporcionó una mayor flexibilidad y escalabilidad a JCPOS. La arquitectura modular de CodeIgniter 4 permite que los desarrolladores de JCPOS agreguen fácilmente nuevas funcionalidades y características al sistema sin afectar negativamente al rendimiento o la estabilidad. Esto significa que JCPOS puede adaptarse y crecer para satisfacer las necesidades cambiantes de sus usuarios.
En conclusión, la migración de JCPOS a CodeIgniter 4 ha mejorado significativamente el rendimiento, la escalabilidad y la flexibilidad del sistema. Los desarrolladores de JCPOS han aprovechado las características avanzadas y la arquitectura modular de CodeIgniter 4 para optimizar el sistema y garantizar su compatibilidad con las últimas tecnologías y tendencias en el desarrollo web.
Nuevo cambio en el cual se podrán mover cn el mouse los modales
Modal Draggable se refiere a la capacidad de arrastrar y mover un cuadro de diálogo modal (o ventana emergente) en una interfaz de usuario. Una ventana modal es un tipo de ventana emergente que requiere que el usuario realice una acción antes de poder interactuar con el resto de la aplicación o sitio web. A menudo se utilizan para solicitar información importante o para mostrar mensajes críticos al usuario.
La función Modal Draggable permite que el usuario arrastre la ventana modal a cualquier lugar en la pantalla para evitar que obstruya información importante o para hacer más fácil su uso en pantallas pequeñas. Esta función se implementa en algunos frameworks y librerías de JavaScript para la creación de interfaces de usuario, como Bootstrap, Materialize y jQuery UI.
Para activarlo en modales ya hechos solo basta con poner el siguiente código, ejemplo
$(function () {
$("#modal-edit-permission").draggable();
$("#modal-create-permission").draggable();
});
Código fuente
https://github.com/julio101290/boilerplate/
Desde Packist
https://packagist.org/packages/julio101290/boilerplate
Saludos y espero que les sirva
Se realizo un pequeño cambio en el proyecto boilerplate para CodeIgniter 4, en el cual las tablas podrán ser responsivas
Si ya están usando este proyecto solo hay que actualizar via composer
composer update
Y en la llamada del datatable agregar responsive:true por ejemplo
var tableUser = $('#table-user').DataTable({
processing: true,
serverSide: true,
responsive: true,
autoWidth: false,
order: [[1, 'asc']],
Y el resultado será el siguiente
Saludos y espero que les sea útil
Un buen negocio o empresa con un numero de empleados considerable siempre va a necesitar un buen sistema de nomina sobre todo para sacar reportes, generar archivos de dispersión de nomina para pagarle a través del banco y sobre todo para generar el timbrado.
Durante las siguientes publicaciones mostraremos como desarrollar un sistema de nomina completo en CodeIgniter 4.x
Primero crearemos la base del proyecto
Creamos el proyecto via composer con el siguiente codigo
composer create-project codeigniter4/appstarter Nomina2023
Creamos la tabla nomina2023 en mariaDB/MySQL o en el motor de su preferencia
en app/config/database.php cambiamos la configuración de la base de datos default lo dejamos de la siguiente forma, igual si ustedes le quieren poner alguna contraseña por seguridad pueden ponersela
public $default = [
'DSN' => '',
'hostname' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'nomina2023',
'DBDriver' => 'MySQLi',
'DBPrefix' => '',
'pConnect' => false,
'DBDebug' => (ENVIRONMENT !== 'production'),
'charset' => 'utf8',
'DBCollat' => 'utf8_general_ci',
'swapPre' => '',
'encrypt' => false,
'compress' => false,
'strictOn' => false,
'failover' => [],
'port' => 3306,
];
en app/config/app.php modificamos las siguientes variables
public $indexPage = '';
public $defaultLocale = 'es';
public $supportedLocales = ['es'];
Para debugear ponemos este codigo al final del archivo app/config/constants.php
define("ENVIRONMENT","development");
Ahora procedemos a instalar boilerplate el cual nos servirá para instalar la plantilla adminLTE3 con un administrador de usuario/roles/permisos/login
Primero instalamos via composer con el siguiente comando
composer require agungsugiarto/boilerplate
Instalamos Auth que es lo que permitirá logearnos administrar usuarios, permisos y roles
php spark auth:publish
Publish Migration? [y, n]: y
created: Database/Migrations/2017-11-20-223112_create_auth_tables.php
Remember to run `spark migrate -all` to migrate the database.
Publish Models? [y, n]: n
Publish Entities? [y, n]: n
Publish Controller? [y, n]: n
Publish Views? [y, n]: n
Publish Filters? [y, n]: n
Publish Config file? [y, n]: y
created: Config/Auth.php
Publish Language file? [y, n]: n
en app/config/auth.php remplazamos el siguiente codigo
public $views = [
'login' => 'agungsugiarto\boilerplate\Views\Authentication\login',
'register' => 'agungsugiarto\boilerplate\Views\Authentication\register',
'forgot' => 'agungsugiarto\boilerplate\Views\Authentication\forgot',
'reset' => 'agungsugiarto\boilerplate\Views\Authentication\reset',
'emailForgot' => 'agungsugiarto\boilerplate\Views\Authentication\emails\forgot',
'emailActivation' => 'agungsugiarto\boilerplate\Views\Authentication\emails\activation',
];
en app/config/filters.php agregamos los siguientes alias
public $aliases = [
'login' => \Myth\Auth\Filters\LoginFilter::class,
'role' => \agungsugiarto\boilerplate\Filters\RoleFilter::class,
'permission' => \agungsugiarto\boilerplate\Filters\PermissionFilter::class,
]
Instalamos, migramos y sembramos boilerplate con el siguiente comando
php spark boilerplate:install
En controller/home.php lo dejamos de la siguiente manera para que siempre nos retorne al admin
<?php
namespace App\Controllers;
class Home extends BaseController
{
public function index()
{
return redirect()->to('/admin');
}
}
En app/config/Boilerplate.php modificamos public $i18n = ‘Indonesian’; a public $i18n = ‘Spanish’; para cambiar el idioma del datable, para el nombre del programa cambiamos public $appName = ‘Boilerplate’; por public $appName = ‘Nomina 2023’;
Tambien modificamos el brand a nuestro antojo yo lo modifique de esta manera
//--------------------------------------------------------------------------
// Theme boilerplate
//
// BG: blue, indigo, purple, pink, red, orange, yellow, green, teal, cyan,
// gray, gray-dark, black
// Type: dark, light
// Shadow: 0-4
//
//--------------------------------------------------------------------------
public $theme = [
'body-sm' => false,
'navbar' => [
'bg' => 'white',
'type' => 'light',
'border' => true,
'user' => [
'visible' => true,
'shadow' => 0,
],
],
'sidebar' => [
'type' => 'dark',
'shadow' => 4,
'border' => false,
'compact' => true,
'links' => [
'bg' => 'blue',
'shadow' => 1,
],
'brand' => [
'bg' => 'gray-dark',
'logo' => [
'icon' => 'favicon.ico', // path to image | this example icon on public root folder.
'text' => '<strong>Nomina</strong>2023',
'shadow' => 2,
],
],
'user' => [
'visible' => true,
'shadow' => 2,
],
],
'footer' => [
'fixed' => false,
'vendorname' => 'CesarSytems',
'vendorlink' => 'https://cesarsystems.com.mx/',
],
];
iniciamos el programa con el siguiente comando
php spark serve
Los usuarios y contraseña por default son los siguientes
+----+--------+-------------+
| No | User | Password |
+----+--------+-------------+
| 1 | admin | super-admin |
| 2 | user | super-user |
+----+--------+-------------+
En este apartado vamos a crear nuestro modulo de citas medicas que posteriormente podremos convertir en consulta, a su vez veremos como crear nuestros propios helpers y usarlos
Que es un helper en codeigniter, pues no es mas que funciones o utilerías que nos pueden servir en diferentes partes del sistema
Creamos la tabla para citas
-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 08-01-2023 a las 23:44:15
-- Versión del servidor: 10.4.17-MariaDB
-- Versión de PHP: 7.4.15
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Base de datos: `medicalsoft`
--
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `citas`
--
CREATE TABLE `citas` (
`id` int(11) NOT NULL,
`idPaciente` int(11) DEFAULT NULL,
`fechaHora` datetime NOT NULL,
`hastaFechaHora` datetime DEFAULT NULL,
`observaciones` varchar(1024) COLLATE utf8_spanish2_ci NOT NULL,
`created_at` datetime NOT NULL,
`deleted_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`estado` varchar(15) COLLATE utf8_spanish2_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;
--
-- Índices para tablas volcadas
--
--
-- Indices de la tabla `citas`
--
ALTER TABLE `citas`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT de las tablas volcadas
--
--
-- AUTO_INCREMENT de la tabla `citas`
--
ALTER TABLE `citas`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Y como de costumbre creamos primeramente el archiv CitasModel.php en la carpeta app/models y le ponemos el siguiente código
<?php
namespace App\Models;
use CodeIgniter\Model;
class CitasModel extends Model {
protected $table = 'citas';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id', 'idPaciente', 'fechaHora', 'hastaFechaHora', 'observaciones', 'created_at', 'updated_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
'observaciones' => 'required|alpha_numeric_space|min_length[3]'
];
protected $validationMessages = [];
protected $skipValidation = false;
public function mdlObtenerDatos() {
$resultado = $this->db->table('citas a, pacientes b')
->select('a.id,concat(b.nombres,\' \',b.apellidos) as nombrePaciente,a.observaciones,a.fechaHora,a.hastaFechaHora,estado,a.created_at,a.updated_at')
->where('a.idPaciente', 'b.id', false)
->where('a.deleted_at', null);
return $resultado;
}
public function mdlObtenerCita($idCita) {
$resultado = $this->db->table('citas a, pacientes b')
->select('a.id,concat(b.nombres,\' \',b.apellidos) as nombrePaciente,a.observaciones,a.fechaHora,a.hastaFechaHora,estado,a.created_at,a.updated_at,a.idPaciente')
->where('a.idPaciente', 'b.id', false)
->where('a.deleted_at', null)
->where('a.id', $idCita,null)->get()->getResultArray();
return $resultado[0];
}
}
Posteriormente creamos el archivo CitasController.php en la carpeta app/controller y le insertamos el siguiente código
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\CitasModel;
use \App\Models\BitacoraModel;
use CodeIgniter\API\ResponseTrait;
class CitasController extends BaseController {
use ResponseTrait;
protected $bitacora;
protected $citas;
public function __construct() {
$this->citas = new CitasModel();
$this->bitacora = new BitacoraModel();
helper('menu');
}
public function index() {
if ($this->request->isAJAX()) {
/*
$start = $this->request->getGet('start');
$length = $this->request->getGet('length');
$search = $this->request->getGet('search[value]');
$order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
$dir = $this->request->getGet('order[0][dir]');
*/
$datos = $this->citas->mdlObtenerDatos();
//where('deleted_at', null);
// $resultado = $this->bitacora->findAll();
// $this->bitacora->getResource()->countAllResults(),
// $this->bitacora->getResource($search)->countAllResults()
// var_dump($datos);
return \Hermawan\DataTables\DataTable::of($datos)->add('action', function ($row) {
return " <div class=\"btn-group\">
<button class=\"btn btn-warning btnEditarCita\" data-toggle=\"modal\" idCita=\"$row->id\" data-target=\"#modalAgregarCitas\"> <i class=\" fa fa-edit \"></i></button>
<button class=\"btn btn-danger btnEliminarCita\" idCita=\"$row->id\"><i class=\"fa fa-times\"></i></button></div>";
}, 'last')
->toJson();
}
$fechaActual = fechaMySQLADateTimeHTML5(fechaHoraActual());
$titulos["fecha"] = $fechaActual;
$titulos["title"] = lang('citas.title');
$titulos["subtitle"] = lang('citas.subtitle');
return view('citas', $titulos);
}
/*
* Lee paciente
*/
public function traeCita() {
$idCita = $this->request->getPost("idCita");
$datosCita = $this->citas->mdlObtenerCita($idCita);
echo json_encode($datosCita);
}
/*
* Guarda o actualiza paciente
*/
public function guardar() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
if ($datos["idCita"] == 0) {
try {
if ($this->citas->save($datos) === false) {
$errores = $this->citas->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
}
$datosBitacora["descripcion"] = "Se guardo la medicamento con los siguientes datos: " . json_encode($datos);
$datosBitacora["usuario"] = $userName;
$this->bitacora->save($datosBitacora);
echo "Guardado Correctamente";
} catch (\PHPUnit\Framework\Exception $ex) {
echo "Error al guardar " . $ex->getMessage();
}
} else {
if ($this->citas->update($datos["idCita"], $datos) == false) {
$errores = $this->citas->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
} else {
$datosBitacora["descripcion"] = "Se actualizo el medicamento con los siguientes datos: " . json_encode($datos);
$datosBitacora["usuario"] = $userName;
$this->bitacora->save($datosBitacora);
echo "Actualizado Correctamente";
return;
}
}
return;
}
public function delete($id)
{
if (!$found = $this->citas->delete($id)) {
return $this->failNotFound(lang('citas.msg.msg_get_fail'));
}
$infoCita = $this->citas->find($id);
$datosBitacora["descripcion"] = "Se elimino la medicamento que contenia los siguientes datos ". json_encode($infoCita);
$this->bitacora->save($datosBitacora);
return $this->respondDeleted($found, lang('citas.msg.msg_delete'));
}
}
Luego Creamos la vista citas.php en app/views
<?= $this->include('agungsugiarto\boilerplate\Views\load\select2') ?>
<?= $this->include('agungsugiarto\boilerplate\Views\load\datatables') ?>
<?= $this->include('agungsugiarto\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('agungsugiarto\boilerplate\Views\layout\index') ?>
<!-- Section content -->
<?= $this->section('content') ?>
<?= $this->include('citasModulos\modalCaptura') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
<div class="card-header">
<div class="float-right">
<div class="btn-group">
<button class="btn btn-primary btnAgregarCitas" data-toggle="modal" data-target="#modalAgregarCitas"><i class="fa fa-plus"></i>
<?= lang('citas.add') ?>
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="tablaCitas" class="table table-striped table-hover va-middle tablaCitas">
<thead>
<tr>
<th>#</th>
<th><?= lang('citas.nombrePaciente') ?></th>
<th><?= lang('citas.observaciones') ?></th>
<th><?= lang('citas.fechaHora') ?></th>
<th><?= lang('citas.hastaFechaHora') ?></th>
<th><?= lang('citas.estado') ?></th>
<th><?= lang('citas.createdAt') ?></th>
<th><?= lang('citas.updateAt') ?></th>
<th><?= lang('citas.actions') ?> </th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- /.card -->
<?= $this->endSection() ?>
<?= $this->section('js') ?>
<script>
/**
* Cargamos la tabla
*/
function cargaTabla() {
$('.tablaCitas').DataTable({
"ajax": "<?= route_to('admin/citas') ?>",
"deferRender": true,
"serverSide": true,
"retrieve": true,
"processing": true
});
}
cargaTabla();
/**
* Carga datos actualizar
*/
/*=============================================
EDITAR PACIENTE
=============================================*/
$(".tablaCitas").on("click", ".btnEditarCita", function () {
var idCita = $(this).attr("idCita");
console.log("idCita ", idCita);
var datos = new FormData();
datos.append("idCita", idCita);
$.ajax({
url: "<?= route_to('admin/citas/traeCita') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#idCita").val(respuesta["id"]);
$("#observaciones").val(respuesta["observaciones"]);
$("#fechaHora").val(respuesta["fechaHora"]);
$("#hastaFechaHora").val(respuesta["hastaFechaHora"]);
//$("#pacientes").val(respuesta["idPaciente"]);
$("#pacientes").empty() //empty select
.append($("<option/>") //add option tag in select
.val(respuesta["idPaciente"]) //set value for option to post it
.text(respuesta["nombrePaciente"])) //set a text for show in select
.val(respuesta["idPaciente"]) //select option of select2
.trigger("change");
}
})
})
/*=============================================
ELIMINAR PACIENTE
=============================================*/
$(".tablaCitas").on("click", ".btnEliminarCita", function () {
var idCita = $(this).attr("idCita");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= route_to('admin/citas') ?>/` + idCita,
method: 'DELETE',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
$(".tablaCitas").DataTable().destroy();
cargaTabla();
//tableUser.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
})
</script>
<?= $this->endSection() ?>
Luego en la carpeta app/views creamos la carpeta citasModulos, creamos el archivo modalCaptura.php y metemos el siguiente código
<!-- Modal Citas -->
<div class="modal fade" id="modalAgregarCitas" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?= lang('citas.createEdit') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form id="form-enfermedad" class="form-horizontal">
<!-- CSRF token -->
<input type="hidden" class="txt_csrfname" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />
<input type="hidden" id="idCita" name="idCita" value="0">
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label"><?= lang('citas.nombrePaciente') ?></label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<select id='pacientes' name='pacientes' style='width: 80%;'>
<option value='0'><?= lang('citas.seleccionePaciente') ?></option>
</select>
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label"><?= lang('citas.observaciones') ?></label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<textarea class="form-control <?= session('error.observaciones ') ? 'is-invalid' : '' ?>" rows="3" placeholder="<?= lang('citas.observaciones') ?>" id="observaciones" name="observaciones" autocomplete="off"></textarea>
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label"><?= lang('citas.fechaHora') ?></label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<input type="datetime-local" id="fechaHora" name="fechaHora" value="<?= $fecha ?>">
</div>
</div>
</div>
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label"><?= lang('citas.hastaFechaHora') ?></label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<input type="datetime-local" id="hastaFechaHora" name="hastaFechaHora" value="<?= $fecha ?>">
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
<button type="button" class="btn btn-primary btn-sm" id="btnGuardarCita"><?= lang('boilerplate.global.save') ?></button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
$(document).on('click', '.btnAgregarCitas', function (e) {
console.log("asdasd");
$(".form-control").val("");
$("#idCita").val("0");
$("#btnGuardarCita").removeAttr("disabled");
})
/*
* AL hacer click al editar
*/
$(document).on('click', '.btnGuardarCita', function (e) {
var idCita = $(this).attr("idCita");
//LIMPIAMOS CONTROLES
$(".form-control").val("");
$("#idCita").val(idCita);
$("#btnGuardarCita").removeAttr("disabled");
})
/**
* Guardar paciente
*/
$(document).on('click', '#btnGuardarCita', function (e) {
var idCita = $("#idCita").val();
var observaciones = $("#observaciones").val();
var idPaciente = $("#pacientes").val();
var fechaHora = $("#fechaHora").val();
var hastaFechaHora = $("#hastaFechaHora").val();
console.log("OBSERVACIONES:",observaciones);
$("#btnGuardarCita").attr("disabled", true);
var datos = new FormData();
datos.append("idCita", idCita);
datos.append("observaciones", observaciones);
datos.append("idPaciente", idPaciente);
datos.append("fechaHora", fechaHora);
datos.append("hastaFechaHora", hastaFechaHora);
$.ajax({
url: "<?= route_to('admin/citas/guardar') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
$('.tablaCitas').DataTable().destroy();
cargaTabla();
$("#btnGuardarCita").removeAttr("disabled");
$('#modalAgregarCitas').modal('hide');
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$("#btnGuardarCita").removeAttr("disabled");
// $('#modalAgregarCita').modal('hide');
}
}
}
)
});
// Initialize select2
$("#pacientes").select2({
ajax: {
url: "<?= site_url('admin/pacientes/traerPacientesAjax') ?>",
type: "post",
dataType: 'json',
delay: 250,
data: function (params) {
// CSRF Hash
var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name
var csrfHash = $('.txt_csrfname').val(); // CSRF hash
return {
searchTerm: params.term, // search term
[csrfName]: csrfHash // CSRF Token
};
},
processResults: function (response) {
// Update CSRF Token
$('.txt_csrfname').val(response.token);
return {
results: response.data
};
},
cache: true
}
});
</script>
<?= $this->endSection() ?>
En este modulo como se vieron el archivo CitasController.php se usaron unas funciones para el formato de las fechas dichas funciones estan en el helper, estas funciones nos sirvieron anteriormente en JCPOS2021, entonces en la carpeta app/Helpers creamos el archivo utilerias_helper.php y metemos el siguiente código
<?php
function strMenuActivo($strMenu1, $strMenu2) {
if ($strMenu1 == $strMenu2) {
$respuesta = 'class="active"';
} else {
$respuesta = "";
}
return $respuesta;
}
//SI LA VARIABLE ESTA VACIA O NO SETA DECLARADA MANDARA CERO SIEMPRE, ES COMO EL VAL DE VISUAL BASIC 6.0
function esCero($value) {
if (empty($value)) {
return "0";
} else {
return $value;
}
}
//FECHA SQL PARA GUARDAR EN BASE DE DATOS
function fechaSQL($fecha) {
return date("Ymd", strtotime($fecha));
}
// CONVIERTE FECHA MYSQLDATETIME A HTML5
function fechaMySQLADateTimeHTML5($fecha) {
return date("Y-m-d", strtotime($fecha)) . "T" . date("H:i:s", strtotime($fecha));
}
function agregarMinutos($fecha, $minutos) {
return date("Y/m/d h:i:s", strtotime($fecha . "+ $minutos minutes"));
/*
$fecha1= new DateTime($fecha);
$fecha1->add(new DateInterval('PT10H30S'));
return $date->format('Y-m-d H:i:s') . "\n";
*
*/
}
//CONVIERTE LA FECHA EN PERIODO
function fechaPeriodo($fecha) {
return date("Ym", strtotime($fecha));
}
//OBTIENE FECHA ACTUAL
function fechaActual() {
return date("Y/m/d");
}
//OBTIENE FECHA HORA ACTUAL
function fechaHoraActual() {
return date("Y-m-d H:i:s ", time());
}
//DIFERENCIA ENTRE MINUTOS
function diferenciaMinutos($fecha_i, $fecha_f) {
$minutos = (strtotime($fecha_i) - strtotime($fecha_f)) / 60;
$minutos = abs($minutos);
$minutos = floor($minutos);
return $minutos;
}
function strSellar($llave, $password, $cadenaOriginal) {
$archivoPem = "/tmp/llave.key.pem";
$comando = "openssl pkcs8 -inform DER -in $llave -passin pass:$password -out $archivoPem";
exec($comando);
$sello = "ok";
//Sellar
$archivo = openssl_pkey_get_private(file_get_contents($archivoPem));
$sig = "";
openssl_sign($cadenaOriginal, $sig, $archivo, OPENSSL_ALGO_SHA256);
$sello = base64_encode($sig);
return $sello;
}
//SOLO DIA
function dia($fecha) {
return date("d", strtotime($fecha));
}
//SOLO MES
function mes($fecha) {
return date("m", strtotime($fecha));
}
//SOLO AÑO
function año($fecha) {
return date("Y", strtotime($fecha));
}
Ahora en app/lenguajes/en/ creamos el archivo citas.php y metemos el siguiente archivo
<?php
$citas["observaciones"] = "Observations";
$citas["nombrePaciente"] = "Patient´s Name";
$citas["fechaHora"] = "Start Date";
$citas["hastaFechaHora"] = "End Date";
$citas["createdAt"] = "Date Creation";
$citas["updateAt"] = "Date Update";
$citas["add"] = "add appointment";
$citas["actions"] = "Acciones";
$citas["estado"] = "status";
$citas["createEdit"] = "add / update appointment";
$citas["seleccionePaciente"] = "Select an Patient";
$citas["title"] = "appointment";
$citas["subtitle"] = "List of appointments";
$citas["msg_delete"] = "The quote has been removed .";
$citas["msg_get_fail"] = "The appointment does not exist or was deleted.";
return $citas;
Ahora en app/lenguajes/es/ creamos el archivo citas.php y metemos el siguiente archivo
<?php
$citas["observaciones"] = "Observaciones";
$citas["nombrePaciente"] = "Nombre Paciente";
$citas["fechaHora"] = "Fecha Inicio Cita";
$citas["obsevaciones"] = "Observaciones";
$citas["hastaFechaHora"] = "Fin Cita";
$citas["createdAt"] = "Fecha Creación";
$citas["updateAt"] = "Fecha de Modificación";
$citas["add"] = "Agregar Cita";
$citas["actions"] = "Acciones";
$citas["estado"] = "Estado";
$citas["createEdit"] = "Crear / Editar Citas";
$citas["seleccionePaciente"] = "Seleccione un paciente";
$citas["title"] = "Citas";
$citas["subtitle"] = "Lista de Citas";
$citas["msg_delete"] = "La cita ha sido eliminada .";
$citas["msg_get_fail"] = "La cita no existe o fue eliminada.";
return $citas;
Luego ya por ultimo creamos las rutas en app/config/routes.php metemos el siguiente codigo
$routes->resource('citas', [
'filter' => 'permission:citas-permiso',
'controller' => 'CitasController',
'except' => 'show'
]);
$routes->post('citas/guardar', 'CitasController::guardar');
$routes->post('citas/traeCita', 'CitasController::traeCita');
Ya creamos el CRUD para pacientes, ahora será necesario crear un CRUD para los medicamentos.
Primero creamos la tabla medicamentos, les dejo la exportación desde phpmyadmin
-- phpMyAdmin SQL Dump
-- version 5.0.4
-- https://www.phpmyadmin.net/
--
-- Servidor: 127.0.0.1
-- Tiempo de generación: 06-01-2023 a las 20:37:36
-- Versión del servidor: 10.4.17-MariaDB
-- Versión de PHP: 7.4.15
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Base de datos: `medicalsoft`
--
-- --------------------------------------------------------
--
-- Estructura de tabla para la tabla `medicamentos`
--
CREATE TABLE `medicamentos` (
`id` int(11) NOT NULL,
`descripcion` varchar(256) COLLATE utf8_spanish2_ci NOT NULL,
`created_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;
--
-- Índices para tablas volcadas
--
--
-- Indices de la tabla `medicamentos`
--
ALTER TABLE `medicamentos`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT de las tablas volcadas
--
--
-- AUTO_INCREMENT de la tabla `medicamentos`
--
ALTER TABLE `medicamentos`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Creamos el archivo MedicamentosModel.php en app/models/
<?php
namespace App\Models;
use CodeIgniter\Model;
class MedicamentosModel extends Model
{
protected $table = 'medicamentos';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id','descripcion', 'created_at','updated_at'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [
'descripcion' => 'required|alpha_numeric_space|min_length[3]'
];
protected $validationMessages = [];
protected $skipValidation = false;
}
Creamos el archivo MedicamentosController.php en app/controller
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\MedicamentosModel;
use \App\Models\BitacoraModel;
use CodeIgniter\API\ResponseTrait;
class MedicamentosController extends BaseController {
use ResponseTrait;
protected $bitacora;
protected $medicamentos;
public function __construct() {
$this->medicamentos = new MedicamentosModel();
$this->bitacora = new BitacoraModel();
helper('menu');
}
public function index() {
if ($this->request->isAJAX()) {
/*
$start = $this->request->getGet('start');
$length = $this->request->getGet('length');
$search = $this->request->getGet('search[value]');
$order = BitacoraModel::ORDERABLE[$this->request->getGet('order[0][column]')];
$dir = $this->request->getGet('order[0][dir]');
*/
$datos = $this->medicamentos->select('id,descripcion,created_at,updated_at')->where('deleted_at', null);
// $resultado = $this->bitacora->findAll();
// $this->bitacora->getResource()->countAllResults(),
// $this->bitacora->getResource($search)->countAllResults()
// var_dump($datos);
return \Hermawan\DataTables\DataTable::of($datos)->add('action', function ($row) {
return " <div class=\"btn-group\">
<button class=\"btn btn-warning btnEditarMedicamento\" data-toggle=\"modal\" idMedicamento=\"$row->id\" data-target=\"#modalAgregarMedicamentos\"> <i class=\" fa fa-edit \"></i></button>
<button class=\"btn btn-danger btnEliminarMedicamento\" idMedicamento=\"$row->id\"><i class=\"fa fa-times\"></i></button></div>";
}, 'last')
->toJson();
}
$titulos["title"] = lang('medicamentos.title');
$titulos["subtitle"] = lang('medicamentos.subtitle');
return view('medicamentos', $titulos);
}
/*
* Lee paciente
*/
public function traeMedicamento() {
$idMedicamento = $this->request->getPost("idMedicamento");
$datosMedicamento = $this->medicamentos->find($idMedicamento);
echo json_encode($datosMedicamento);
}
/*
* Guarda o actualiza paciente
*/
public function guardar() {
helper('auth');
$userName = user()->username;
$idUser = user()->id;
$datos = $this->request->getPost();
if ($datos["idMedicamento"] == 0) {
try {
if ($this->medicamentos->save($datos) === false) {
$errores = $this->medicamentos->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
}
$datosBitacora["descripcion"] = "Se guardo la medicamento con los siguientes datos: " . json_encode($datos);
$datosBitacora["usuario"] = $userName;
$this->bitacora->save($datosBitacora);
echo "Guardado Correctamente";
} catch (\PHPUnit\Framework\Exception $ex) {
echo "Error al guardar " . $ex->getMessage();
}
} else {
if ($this->medicamentos->update($datos["idMedicamento"], $datos) == false) {
$errores = $this->medicamentos->errors();
foreach ($errores as $field => $error) {
echo $error . " ";
}
return;
} else {
$datosBitacora["descripcion"] = "Se actualizo el medicamento con los siguientes datos: " . json_encode($datos);
$datosBitacora["usuario"] = $userName;
$this->bitacora->save($datosBitacora);
echo "Actualizado Correctamente";
return;
}
}
return;
}
public function delete($id)
{
if (!$found = $this->medicamentos->delete($id)) {
return $this->failNotFound(lang('medicamentos.msg.msg_get_fail'));
}
$infoMedicamento = $this->medicamentos->find($id);
$datosBitacora["descripcion"] = "Se elimino la medicamento que contenia los siguientes datos ". json_encode($infoMedicamento);
$this->bitacora->save($datosBitacora);
return $this->respondDeleted($found, lang('medicamentos.msg.msg_delete'));
}
}
Creamos el archivo de la vista medicamentos.php en app/views
<?= $this->include('agungsugiarto\boilerplate\Views\load\select2') ?>
<?= $this->include('agungsugiarto\boilerplate\Views\load\datatables') ?>
<?= $this->include('agungsugiarto\boilerplate\Views\load\nestable') ?>
<!-- Extend from layout index -->
<?= $this->extend('agungsugiarto\boilerplate\Views\layout\index') ?>
<!-- Section content -->
<?= $this->section('content') ?>
<?= $this->include('medicamentosModulos\modalCaptura') ?>
<!-- SELECT2 EXAMPLE -->
<div class="card card-default">
<div class="card-header">
<div class="float-right">
<div class="btn-group">
<button class="btn btn-primary btnAgregarMedicamento" data-toggle="modal" data-target="#modalAgregarMedicamentos"><i class="fa fa-plus"></i>
<?= lang('medicamentos.add') ?>
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table id="tablaMedicamentos" class="table table-striped table-hover va-middle tablaMedicamentos">
<thead>
<tr>
<th>#</th>
<th><?= lang('medicamentos.description') ?></th>
<th><?= lang('medicamentos.createdAt') ?></th>
<th><?= lang('medicamentos.updateAt') ?></th>
<th>Acciones </th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- /.card -->
<?= $this->endSection() ?>
<?= $this->section('js') ?>
<script>
/**
* Cargamos la tabla
*/
function cargaTabla() {
$('.tablaMedicamentos').DataTable({
"ajax": "<?= route_to('admin/medicamentos') ?>",
"deferRender": true,
"serverSide": true,
"retrieve": true,
"processing": true
});
}
cargaTabla();
/**
* Carga datos actualizar
*/
/*=============================================
EDITAR PACIENTE
=============================================*/
$(".tablaMedicamentos").on("click", ".btnEditarMedicamento", function () {
var idMedicamento = $(this).attr("idMedicamento");
console.log("idMedicamento ", idMedicamento);
var datos = new FormData();
datos.append("idMedicamento", idMedicamento);
$.ajax({
url: "<?= route_to('admin/medicamentos/traerMedicamento') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
dataType: "json",
success: function (respuesta) {
console.log(respuesta);
$("#idMedicamento").val(respuesta["id"]);
$("#descripcion").val(respuesta["descripcion"]);
}
})
})
/*=============================================
ELIMINAR PACIENTE
=============================================*/
$(".tablaMedicamentos").on("click", ".btnEliminarMedicamento", function () {
var idMedicamento = $(this).attr("idMedicamento");
Swal.fire({
title: '<?= lang('boilerplate.global.sweet.title') ?>',
text: "<?= lang('boilerplate.global.sweet.text') ?>",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '<?= lang('boilerplate.global.sweet.confirm_delete') ?>'
})
.then((result) => {
if (result.value) {
$.ajax({
url: `<?= route_to('admin/medicamentos') ?>/` + idMedicamento,
method: 'DELETE',
}).done((data, textStatus, jqXHR) => {
Toast.fire({
icon: 'success',
title: jqXHR.statusText,
});
$(".tablaMedicamentos").DataTable().destroy();
cargaTabla();
//tableUser.ajax.reload();
}).fail((error) => {
Toast.fire({
icon: 'error',
title: error.responseJSON.messages.error,
});
})
}
})
})
</script>
<?= $this->endSection() ?>
Creamos la carpeta en views medicamentosModulos y dentro de ella creamos el archivo modelCaptura.php con el siguiente código
<!-- Modal Medicamentos -->
<div class="modal fade" id="modalAgregarMedicamentos" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?= lang('medicamentos.createEdit') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form id="form-enfermedad" class="form-horizontal">
<input type="hidden" id="idMedicamento" name="idMedicamento" value="0">
<div class="form-group row">
<label for="inputName" class="col-sm-2 col-form-label"><?= lang('medicamentos.description') ?></label>
<div class="col-sm-10">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-pencil-alt"></i></span>
</div>
<input type="text" name="descripcion" id="descripcion" class="form-control <?= session('error.descripcion ') ? 'is-invalid' : '' ?>" value="<?= old('descripcion') ?>" placeholder="<?= lang('medicamentos.description') ?>" autocomplete="off">
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal"><?= lang('boilerplate.global.close') ?></button>
<button type="button" class="btn btn-primary btn-sm" id="btnGuardarMedicamento"><?= lang('boilerplate.global.save') ?></button>
</div>
</div>
</div>
</div>
<?= $this->section('js') ?>
<script>
$(document).on('click', '.btnAgregarMedicamento', function (e) {
console.log("asdasd");
$(".form-control").val("");
$("#idMedicamento").val("0");
$("#btnGuardarMedicamento").removeAttr("disabled");
})
/*
* AL hacer click al editar
*/
$(document).on('click', '.btnGuardarMedicamento', function (e) {
var idMedicamento = $(this).attr("idMedicamento");
//LIMPIAMOS CONTROLES
$(".form-control").val("");
$("#idMedicamento").val(idMedicamento);
$("#btnGuardarMedicamento").removeAttr("disabled");
})
/**
* Guardar paciente
*/
$(document).on('click', '#btnGuardarMedicamento', function (e) {
var idMedicamento = $("#idMedicamento").val();
var descripcion = $("#descripcion").val();
$("#btnGuardarMedicamento").attr("disabled", true);
var datos = new FormData();
datos.append("idMedicamento", idMedicamento);
datos.append("descripcion", descripcion);
$.ajax({
url: "<?= route_to('admin/medicamentos/guardar') ?>",
method: "POST",
data: datos,
cache: false,
contentType: false,
processData: false,
//dataType:"json",
success: function (respuesta) {
if (respuesta.match(/Correctamente.*/)) {
Toast.fire({
icon: 'success',
title: "Guardado Correctamente"
});
$('.tablaMedicamentos').DataTable().destroy();
cargaTabla();
$("#btnGuardarMedicamento").removeAttr("disabled");
$('#modalAgregarMedicamentos').modal('hide');
} else {
Toast.fire({
icon: 'error',
title: respuesta
});
$("#btnGuardarMedicamento").removeAttr("disabled");
// $('#modalAgregarMedicamento').modal('hide');
}
}
}
)
});
</script>
<?= $this->endSection() ?>
en app/Languaje/en creamos el archivo medicamentos.php con el siguiente código
<?php
$medicamentos["descrption"] = "Description";
$medicamentos["createdAt"] = "Date Creation";
$medicamentos["updateAt"] = "Date Update";
$medicamentos["add"] = "Add medicine";
$medicamentos["actions"] = "Actions";
$medicamentos["createEdit"] = "Create / Edit medicine";
$medicamentos["title"] = "Medicine";
$medicamentos["subtitle"] = "List of medicines";
$medicamentos["msg_delete"] = "medicine has deleted .";
$medicamentos["msg_get_fail"] = "The medicine not exist or has deleted.";
return $medicamentos;
en app/Languaje/escreamos el archivo medicamentos.php con el siguiente código
<?php
$medicamentos["description"] = "Descripcion";
$medicamentos["createdAt"] = "Fecha Creación";
$medicamentos["updateAt"] = "Fecha de Modificación";
$medicamentos["add"] = "Agregar Medicamentos";
$medicamentos["actions"] = "Acciones";
$medicamentos["createEdit"] = "Crear / Editar Medicamentos";
$medicamentos["title"] = "Medicamentos";
$medicamentos["subtitle"] = "Lista de Medicamentos";
$medicamentos["msg_delete"] = "El medicamento ha sido eliminada .";
$medicamentos["msg_get_fail"] = "La medicamento no existe o fue eliminada.";
return $medicamentos;
en el archivo app/config/routes.php agregamos dentro del grupo admin la siguiente rutas
$routes->resource('medicamentos', [
'filter' => 'permission:medicamentos-permiso',
'controller' => 'MedicamentosController',
'except' => 'show'
]);
$routes->post('medicamentos/guardar', 'MedicamentosController::guardar');
$routes->post('medicamentos/traerMedicamento', 'MedicamentosController::traeMedicamento');
En cualquier sistema es importante tener un log o una bitácora en donde vallamos almacenando lo cambios que vamos realizando en la base de datos, por ejemplo, ir guardando la información que va insertando el usuario a la tabla de clientes, también cuando se elimino y actualizo grabando un timestamp que guarde hasta el segundo exacto de modificación y ya con eso vamos llevando un control
Haremos todo esto en CodeIgniter 4
Empezamos primero creamos la tabla
--
-- Estructura de tabla para la tabla bitacora
CREATE TABLE bitacora (
id bigint(20) NOT NULL,
descripcion text COLLATE utf8_spanish2_ci DEFAULT NULL,
usuario varchar(16) COLLATE utf8_spanish2_ci DEFAULT NULL,
created_at datetime DEFAULT NULL,
deleted_at datetime DEFAULT NULL,
updated_at datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish2_ci;
--
-- Índices para tablas volcadas
--
-- Indices de la tabla bitacora
ALTER TABLE bitacora
ADD PRIMARY KEY (id);
ALTER TABLE bitacora
MODIFY id bigint(20) NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
Creamos el archivo modelo BitacoraModel.php
<?php
namespace App\Models;
use CodeIgniter\Model;
class BitacoraModel extends Model
{
protected $table = 'bitacora';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $allowedFields = ['id','descripcion', 'usuario'];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
const ORDERABLE = [
1 => 'id',
2 => 'descripcion',
3 => 'usuario',
4 => 'created_at',
];
/**
* Get resource data.
*
* @param string $search
*
* @return \CodeIgniter\Database\BaseBuilder
*/
public function getResource(string $search = '')
{
$builder = $this->builder()
->select('id, descripcion, usuario, created_at');
$condition = empty($search)
? $builder
: $builder->groupStart()
->like('descripcion', $search)
->orLike('Usuario', $search)
->orLike('created_at', $search)
->groupEnd();
return $condition->where('deleted_at', null);
}
Ahora usaremos el modelo para guardar cada vez que se haga un cambio al guardar la configuración del hospital
<?php
namespace agungsugiarto\boilerplate\Controllers\Users;
namespace App\Controllers;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\Controller;
use App\Models\ConfiguracionesModel;
use App\Models\BitacoraModel;
use agungsugiarto\boilerplate\Controllers\BaseController;
use agungsugiarto\boilerplate\Entities\Collection;
use agungsugiarto\boilerplate\Models\GroupModel;
use CodeIgniter\Config\Services;
class HospitalController extends Controller
{
use ResponseTrait;
/** @var \agungsugiarto\boilerplate\Models\GroupModel */
protected $group;
protected $configuraciones;
protected $bitacora;
public function __construct()
{
$this->group = new GroupModel();
$this->configuraciones = new ConfiguracionesModel();
$this->bitacora = new BitacoraModel();
$autorize = $this->authorize = Services::authorization();
helper('menu');
}
public function index()
{
$datos = $this->configuraciones->where("id",1)->first();
$data["title"] = lang('settings.settings.title');
$data["subtitle"] = lang('settings.settings.title');
$data["data"] = $datos;
return view('configuracionEmpresa/index',$data);
}
public function guardar()
{
helper('auth');
$userName = user()->username ;
$idUser = user()->id ;
$bitacoraDatos["descripcion"] = "Se Modifico las configuracion con los siguientes datos:". json_encode($_POST);
$bitacoraDatos["usuario"] = $userName;
//GUARDA CONFIGURACIONES
$this->configuraciones->update(1,$_POST);
//GUARDAR EN BITACORA
$this->bitacora->save($bitacoraDatos);
// return redirect()->to("/admin/hospital");
return redirect()->back()->with('sweet-success', 'Actualizado Correctamente');
// return redirect()->back()->with('sweet-success','Guardado Correctamente');
}
}
Ya con eso cada vez que se haga un cambio a a configuración nos guardara un registro sobre quien hizo el cambio y también nos servirá para los próximos módulos que se vallan programando.
En la próxima publicación veremos como mostrar los datos en un datatable.
Veremos como crear el proyecto desde cero, meteremos el login con adminLTE3 y crearemos los menús que vamos a utilizar
Creado con WordPress & Tema de Anders Norén