<?php
namespace App\Controller;
use App\Entity\Equipo;
use App\Entity\Evaluacion;
use App\Entity\Impresora;
use App\Entity\Otro;
use App\Entity\Periodo;
use App\Entity\Red;
use App\Entity\Solicitud;
use App\Entity\Usuario;
use App\Form\EvaluacionSelecType;
use App\Form\EvaluacionType;
use App\Form\SolicitudType;
use App\Form\SolicitudSelecType;
use App\Service\VistaTipoEquipo;
use DateTime;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
#[Route('/programacion/correctivo')]
class ProgManttoCorrectivoController extends AbstractController
{
public EntityManagerInterface $entityManager;
public SerializerInterface $serializer;
/**
* @param EntityManagerInterface $entityManager
*/
public function __construct(EntityManagerInterface $entityManager, SerializerInterface $serializer)
{
$this->entityManager = $entityManager;
$this->serializer = $serializer;
}
#[Route('/', name: 'prog_correctivo_index')]
public function index(Request $request): Response
{
/** @var Usuario $user */
$user = $this->getUser();
$solicitudes = $this->entityManager->getRepository(Solicitud::class)->registroTipoEquipoUsuario($user->getIdUsu(), 1);
$atendidas = array_reduce($solicitudes, function ($carry, $solicitud) {
return $solicitud['estatus'] == 3 ? $carry + 1 : $carry;
}, 0);
$invocation = $this->obtenerAtributoEntidad(null, null);
$solicitar = $this->createForm(SolicitudSelecType::class, null, ['opciones' => $invocation['opciones'], 'opciones_attr' => $invocation['opciones_attr']]);
$solicitar->handleRequest($request);
$evaluar = $this->createForm(EvaluacionSelecType::class, null, ['usuario' => $user]);
$evaluar->handleRequest($request);
if ($solicitar->isSubmitted() && $solicitar->isValid() && $request->isMethod('POST') && $solicitar->get('origen')->getData() === 'form-equipo-solicitud') {
$fallaValue = $solicitar->get('falla')->getData();
if ($fallaValue === null || trim((string) $fallaValue) === '') {
return new JsonResponse(['mensaje' => 'El campo no debe estar vacío'], Response::HTTP_BAD_REQUEST);
}
$invo = $this->mapeoTipoEquipo($solicitar->get('tipo')->getData());
$entidad = $this->consultaEntidad([
'id' => $solicitar->get('marbete')->getData(),
'tipo' => $solicitar->get('tipo')->getData(),
'campo' => $invo['atributo']
]);
if (!$entidad) {
return new JsonResponse(['mensaje' => $solicitar->get('tipo')->getData() . ' no encontrado'], Response::HTTP_NOT_FOUND);
}
$info = $this->programarSolicitudSave($this->construirDatosEntidad($entidad, $solicitar->get('tipo')->getData(), $solicitar));
return new JsonResponse($info);
}
if ($solicitar->isSubmitted() && !$solicitar->isValid() && $solicitar->get('origen')->getData() === 'form-equipo-solicitud') {
$view = $this->renderView('prog_correctivo/index.html.twig', [
'equipos' => $invocation['opciones_type'],
'solicitudes' => $solicitudes,
'atendidas' => $atendidas,
'solicitar' => $solicitar->createView(),
'evaluar' => $evaluar->createView()
]);
$response = new JsonResponse(['form' => $view]);
return $response->setStatusCode(Response::HTTP_BAD_REQUEST);
}
if ($evaluar->isSubmitted() && $evaluar->isValid() && $request->isMethod('POST') && $evaluar->get('origen')->getData() === 'form-equipo-evaluar'){
$solicitudData = $evaluar->get('marbete')->getData();
$solicitud = $this->entityManager->getRepository(Solicitud::class)->find($solicitudData->getIdSol());
if (!$solicitud) {
return new JsonResponse(['mensaje' => 'Solicitud no encontrada'], Response::HTTP_NOT_FOUND);
}
$this->evaluarSolicitudSave([
'reacta' => $evaluar->get('evalua1')->getData(),
'reactb' => $evaluar->get('evalua2')->getData(),
'reactc' => $evaluar->get('evalua3')->getData(),
'reactd' => $evaluar->get('evalua4')->getData(),
'reacte' => $evaluar->get('evalua5')->getData(),
'solicitud' => $solicitud,
'usuario' => $user
]);
return new JsonResponse(['message' => 'Evaluación guardada correctamente', 'id' => $solicitud->getIdSol()]);
}
if ($evaluar->isSubmitted() && !$evaluar->isValid() && $evaluar->get('origen')->getData() === 'form-equipo-evaluar'){
$view = $this->renderView('prog_correctivo/index.html.twig', [
'equipos' => $invocation['opciones_type'],
'solicitudes' => $solicitudes,
'atendidas' => $atendidas,
'solicitar' => $solicitar->createView(),
'evaluar' => $evaluar->createView()
]);
$response = new JsonResponse(['form' => $view]);
return $response->setStatusCode(Response::HTTP_BAD_REQUEST);
}
return $this->render('prog_correctivo/index.html.twig', [
'equipos' => $invocation['opciones_type'],
'solicitudes' => $solicitudes,
'atendidas' => $atendidas,
'solicitar' => $solicitar->createView(),
'evaluar' => $evaluar->createView()
]);
}
/**
* Vista detallada de solicitud
* @Route("/vista/solicitud/{id}", name="prog_correctivo_vista_solicitud", methods={"GET", "POST"})
* @param Request $request
* @return Response
*/
public function vistaSolicitud(Request $request) :Response
{
$solicitud = $this->entityManager->getRepository(Solicitud::class)->detalleTipoEquipoSolicitud($request->get('id'));
return $this->render('prog_solicitud/informacion_solicitud.html.twig', ['info' => $solicitud]);
}
#[Route('/vista/contador', name: 'prog_correctivo_vista')]
public function vistaContador() :JsonResponse
{
/** @var Usuario $user */
$user = $this->getUser();
$cTodoEquipo = $this->entityManager->getRepository(Solicitud::class)->conteoEstatusTipoEquipoUsuario($user->getIdUsu(), 1);
return new JsonResponse(['data' => $cTodoEquipo], Response::HTTP_OK);
}
/**
* Vista detallada por tipo, equipo, impresora, red, otro
* @Route("/vista/{tipo}/{id}", name="prog_correctivo_vista_tipo", methods={"GET", "POST"})
* @param Request $request
* @return Response
*/
public function vistaTipo(Request $request) :Response
{
$service = new VistaTipoEquipo($this->entityManager);
$info = $service->consultaInformacion($request->get('tipo'), $request->get('id'));
return $this->render('prog_solicitud/informacion_tipo.html.twig', ['tipo' => $request->get('tipo'),'info' => $info]);
}
/**
* Elimina campos innecesarios del formulario de solicitud
* @param \Symfony\Component\Form\FormInterface $form
*/
private function eliminarCamposFormulario(\Symfony\Component\Form\FormInterface $form): void
{
$campos = ['tipoEquipo', 'idEquipo', 'periodo', 'tipoMantenimiento', 'srealizado',
'fregistro', 'fatencion', 'ffin', 'evaluacion', 'refacciones', 'estatus',
'usuario', 'ubicacion', 'gestor'];
foreach ($campos as $campo) {
$form->remove($campo);
}
}
/**
* Consulta de solicitudes programadas por equipo, de tipo impresora
* @Route("/programada/consulta/{tipo}/{id}", name="prog_correctivo_programada_tipo", methods={"GET", "POST"})
* @return Response
*/
public function consultaProgramadaTipo(Request $request) :Response
{
$info = [
'tipoEquipo' => $request->get('tipo'),
'tipoMantenimiento' => 'Correctivo',
'siglasMantenimiento' => 'MC'
];
$programadas = $this->entityManager->getRepository(Solicitud::class)->registroEquipoSolicitud($request->get('tipo'), $info['tipoEquipo'], $info['siglasMantenimiento']);
return $this->renderForm('prog_solicitud/programado.html.twig', [
'info' => $info,
'solicitud' => $programadas
]);
}
/**
* Programar solicitud por equipo, solo tipo equipo
* @Route("/solicitud/{tipo}/{id}", name="prog_correctivo_solicitud_tipo", methods={"GET", "POST"})
* @param Request $request
* @return Response
*/
public function programarSolicitud(Request $request) :Response
{
$entidad = $this->obtenerAtributoEntidad(null, $request->get('tipo'));
$entidad = $this->consultaEntidad([
'id' => $request->get('id'),
'tipo' => $request->get('tipo'),
'campo' => $entidad['propiedad']['atributo']
]);
$info = [
'tipoEquipo' => $request->get('tipo'),
'tipoMantenimiento' => 'Correctivo',
'marbete' => $entidad->getMarbete()
];
$form = $this->createForm(SolicitudType::class);
$this->eliminarCamposFormulario($form);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if($form->get('falla')->getData() == "" || $form->get('falla') == null){
return new JsonResponse(['mensaje' => 'El campo no debe estar vacío'], Response::HTTP_BAD_REQUEST);
}
$data = $this->construirDatosEntidad($entidad, $request->get('tipo'), $form);
$info = $this->programarSolicitudSave($data);
return new JsonResponse($info);
}
if ($form->isSubmitted() && !$form->isValid()) {
$view = $this->renderView('prog_solicitud/programar.html.twig', [
'form' => $form->createView(),
'info' => $info
]);
$response = new JsonResponse(['form' => $view]);
$response->setStatusCode(Response::HTTP_BAD_REQUEST);
return $response;
}
return $this->renderForm('prog_solicitud/programar.html.twig', [
'form' => $form,
'info' => $info
]);
}
/**
* Función para crear objeto tipo solicitud e insertar en la base de datos
* @param array $data Array con la información específica a complementar
* @return array Para creación de botón en la vista
*/
private function programarSolicitudSave($data)
{
date_default_timezone_set("America/Mexico_City");
$factual = new DateTime();
# Identificador de solicitud
$partA = date("y");
$partB = substr($data['unidad']->getIdUni(), 3, 3);
$partC = str_pad($data['unidad']->getConsecutivo(), 4,"0", STR_PAD_LEFT);
$idSolicitud = $partA.$partB.$partC;
$save = new Solicitud();
$save->setIdSol($idSolicitud);
$save->setIdEquipo($data['id']);
$save->setTipoEquipo($data['tipo']);
$save->setTipoMantenimiento("MC");
$save->setUnidad($data['unidad']);
$save->setUsuario($data['usuario']);
$save->setUbicacion($data['ubicacion']);
$save->setPeriodo($data['periodo']);
$save->setFalla($data['accion']);
$save->setFregistro($factual);
$save->setFatencion($factual);
$save->setEstatus(1);
$this->entityManager->persist($save);
$this->entityManager->flush();
$unidad = $data['unidad'];
$unidad->setConsecutivo($unidad->getConsecutivo() + 1);
$this->entityManager->persist($unidad);
$this->entityManager->flush();
$info = [
'mensaje' => 'Se ha generado la solicitud de mantenimiento, con el identificador ' . $save->getIdSol(),
'ver_solicitud' => $this->generateUrl('prog_correctivo_vista_solicitud', ['id' => $save->getIdSol()], UrlGeneratorInterface::ABSOLUTE_URL),
'solicitud' => $save->getIdSol(),
'tipo_equipo' => $save->getTipoEquipo(),
'equipo' => $save->getIdEquipo(),
'marbete' => $data['marbete'],
'marca' => $data['marca'],
'modelo' => $data['modelo'],
'falla' => $save->getFalla(),
'tipo_mantenimiento' => $save->getTipoMantenimiento(),
'fregistro' => $save->getFregistro()->format("d M Y, H:i"),
'estatus' => $save->getEstatus()
];
return $info;
}
/**
* Evaluación de mantenimiento por solicitud
* @Route("/evaluacion/{idSol}", name="prog_correctivo_evaluacion", methods={"GET", "POST"})
* @param Solicitud $solicitud
* @param Request $request
* @return Response
*/
public function evaluarSolicitud(Request $request, Solicitud $solicitud) :Response
{
/** @var Usuario $user */
$user = $this->getUser();
$contestada = $this->entityManager->getRepository(Evaluacion::class)->findOneBy(['solicitud' => $solicitud->getIdSol()]);
$nueva = 0;
$info = [
'solicitud' => $solicitud->getIdSol(),
'tipoMantenimiento' => $solicitud->getTipoMantenimiento(),
];
if (empty($contestada) && $solicitud->getEstatus() == 3) {
$nueva = 1;
$form = $this->createForm(EvaluacionType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$invocation = $this->evaluarSolicitudSave([
'reacta' => $form->get('evalua1')->getData(),
'reactb' => $form->get('evalua2')->getData(),
'reactc' => $form->get('evalua3')->getData(),
'reactd' => $form->get('evalua4')->getData(),
'reacte' => $form->get('evalua5')->getData(),
'solicitud' => $solicitud,
'usuario' => $user
]);
return new JsonResponse([
'id' => $solicitud->getIdSol(),
'estatus' => $invocation['estatus'],
'mensaje' => 'Evaluación guardada correctamente'
]);
}
} else {
$form = $this->createForm(EvaluacionType::class, $contestada);
$form->handleRequest($request);
}
if ($form->isSubmitted() && !$form->isValid()) {
$view = $this->renderView('prog_correctivo/evaluacion.html.twig', [
'form' => $form->createView(),
'info' => $info,
'nueva' => $nueva
]);
$response = new JsonResponse(['form' => $view]);
$response->setStatusCode(Response::HTTP_BAD_REQUEST);
return $response;
}
return $this->renderForm('prog_correctivo/evaluacion.html.twig', [
'form' => $form,
'info' => $info,
'nueva' => $nueva
]);
}
/**
* Función para crear objeto tipo evaluacion e insertar en la base de datos
* @param array $data Array con la información específica a complementar
* @return array Para creación de botón en la vista
*/
private function evaluarSolicitudSave($data){
$evaluacion = new Evaluacion();
$evaluacion->setEvalua1($data['reacta']);
$evaluacion->setEvalua2($data['reactb']);
$evaluacion->setEvalua3($data['reactc']);
$evaluacion->setEvalua4($data['reactd']);
$evaluacion->setEvalua5($data['reacte']);
$evaluacion->setSolicitud($data['solicitud']);
$this->entityManager->persist($evaluacion);
$this->entityManager->flush();
date_default_timezone_set("America/Mexico_City");
$time = new DateTime();
$solicitud = $data['solicitud'];
$solicitud->setUsuario($data['usuario']);
$solicitud->setEstatus(4);
$solicitud->setFevaluacion($time);
$this->entityManager->persist($solicitud);
$this->entityManager->flush();
$estatus = "<span class='badge bg-gradient-danger d-block'>No evaluado</span>";
if ($solicitud->getEstatus() == 4){
$estatus="<span class='badge bg-gradient-green d-block'>Evaluado</span>";
}
return ['estatus' => $estatus];
}
/**
* Construye el array de datos para la entidad según su tipo
* @param $entidad
* @param string $tipoEquipo
* @param \Symfony\Component\Form\FormInterface $form
* @param Periodo $periodo
* @return array
*/
private function construirDatosEntidad($entidad, string $tipoEquipo, \Symfony\Component\Form\FormInterface $form): array
{
$periodo = $this->entityManager->getRepository(Periodo::class)->findOneBy(['activo' => 1, 'actual' => 1]);
if (!$periodo) {
return new JsonResponse(['mensaje' => 'No existe periodo activo'], Response::HTTP_BAD_REQUEST);
}
$data = $this->obtenerAtributoEntidad($entidad, $tipoEquipo);
if (is_object($data['marca'])) {
$marca = $this->serializer->serialize($data['marca'], 'json');
} else {
$marca = $data['marca'];
}
$data = [
"tipo" => $tipoEquipo,
"id" => $data['id'],
"marbete" => $entidad->getMarbete(),
"marca" => $marca,
"modelo" => $entidad->getModelo(),
"iduni" => $entidad->getUnidad()->getIdUni(),
"consuni" => $entidad->getUnidad()->getConsecutivo(),
"unidad" => $entidad->getUnidad(),
"usuario" => $entidad->getUsuario(),
"ubicacion" => $entidad->getUbicacion(),
"accion" => $form->get('falla')->getData(),
"periodo" => $periodo->getIdPrd()
];
return $data;
}
private function obtenerAtributoEntidad(Equipo|Impresora|Red|Otro|null $entidad, string|null $tipoEquipo)
{
/** @var Usuario $user */
$user = $this->getUser();
$mappings = $this->mapeoTipoEquipo($tipoEquipo);
if (!$entidad && !$tipoEquipo) {
//throw new \Exception('Categoría de equipo indefinida');
foreach ($this->mapeoTipoEquipo($tipoEquipo) as $tipo) {
$entidad = $this->consultaEntidad([
'id' => $user->getIdUsu(),
'tipo' => $tipo['singular'],
'campo' => null,
'usuario' => $user->getIdUsu()
], 'multiple');
foreach ($entidad as $item) {
$nombreMetodo = $tipo['metodo_id'];
$data['opciones'][$tipo['plural']][$item->getMarbete() . ': ' . $item->getDescripcion()] = $item->$nombreMetodo();
$data['opciones_attr'][$item->$nombreMetodo()] = ['data-tipo' => $tipo['singular'], 'data-id' => $item->getMarbete()];
$data['opciones_type'][$tipo['singular']][$item->$nombreMetodo()] = $item;
}
}
return $data;
}
// Extraemos la configuración específica
$metodoId = $mappings['metodo_id'];
$metodoMarca = $mappings['metodo_marca'];
$data['propiedad'] = $mappings;
$data['id'] = null; // Inicializar por seguridad
// Validación: Si $entidad es un objeto (no null y es object)
if ($entidad instanceof \stdClass || is_object($entidad)) {
if (!method_exists($entidad, $metodoId)) {
throw new \Exception("El objeto no tiene el método: " . $metodoId);
}
// CORRECCIÓN: Usamos $nombreMetodo (string) en lugar del array
$data['id'] = $entidad->$metodoId();
$data['marca'] = $entidad->$metodoMarca();
}
return $data;
}
private function consultaEntidad($data = null, string $control = null)
{
try {
$claseEntity = $this->entityManager->getClassMetadata('App\\Entity\\' . $data['tipo'])->name;
} catch (\Exception $e) {
throw new \Exception("Entidad no encontrada: " . $data['tipo']);
}
$qb = $this->entityManager->createQueryBuilder();
$qb = $qb->select('e');
$qb = $qb->from($claseEntity, 'e');
if (!empty($data['campo'])) {
$qb = $qb->where($qb->expr()->eq('e.' . $data['campo'], ':valor'))
->setParameter('valor', $data['id']);
}
if (!empty($data['usuario'])) {
$qb = $qb->addSelect('u')
->join('e.usuario', 'u')
->where('u.idUsu = :usuario')
->setParameter('usuario', $data['usuario']);
}
$qb = $qb->getQuery();
if($control === 'multiple'){
$qb = $qb->getResult();
} else {
$qb = $qb->getOneOrNullResult();
}
return $qb;
}
private function mapeoTipoEquipo(string|null $tipo){
$mappings = [
'Equipo' => ['metodo_id' => 'getIdEqu', 'metodo_marca' => 'getIdMarca', 'atributo' => 'idEqu', 'singular' => 'Equipo', 'plural' => 'Equipos'],
'Impresora'=> ['metodo_id' => 'getIdImp', 'metodo_marca' => 'getMarca', 'atributo' => 'idImp', 'singular' => 'Impresora', 'plural' => 'Impresoras'],
'Red' => ['metodo_id' => 'getIdRed', 'metodo_marca' => 'getMarca', 'atributo' => 'idRed', 'singular' => 'Red', 'plural' => 'Redes'],
'Otro' => ['metodo_id' => 'getIdOtro', 'metodo_marca' => 'getMarca', 'atributo' => 'idOtro', 'singular' => 'Otro', 'plural' => 'Otros'],
];
if (!in_array($tipo, ['Equipo', 'Impresora', 'Red', 'Otro'], true)) {
//throw new \InvalidArgumentException("Tipo de equipo no válido: " . $tipo);
return $mappings;
} else {
return $mappings[$tipo];
}
}
}