Ver código fonte

modificación a la data retornada por getUnprogrammedVisits y funciones relacionadas a las visitas no programadas.

EmilianoOrtiz 1 semana atrás
pai
commit
1b1a3d57dc

+ 184 - 41
sistema-mantenimiento-back/app/Http/Controllers/PreventiveMaintenanceController.php

@@ -2231,6 +2231,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.', $programmedWorkOrders);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function newUnprogrammedOrder(Request $request)
     {
         DB::enableQueryLog();
@@ -2379,6 +2380,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.');
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function getUnprogrammedVisits($idUser, $line)
     {
         DB::enableQueryLog();
@@ -2403,19 +2405,22 @@ class PreventiveMaintenanceController extends Controller
             'EQUI_TIPO AS TIPO_EQUIPAMIENTO',
             'EQUI_MODE AS MODELO_EQUIPAMIENTO',
             'EQUI_IDEQ AS ID_EQUIPAMIENTO',
-            'RVTN_ESTA AS ESTATUS',
+            'RVTN_ESTA AS ESTADO',
             'RVTN_USRE AS USRREG',
             'RVTN_FERE AS FECREG',
-            'RVTN_UARE AS USAURE',
-            'RVTN_FARE AS FEAURE',
-            'RVTN_USCA AS USRCAN',
-            'RVTN_FECA AS FECCAN',
-            'RVTN_USFI AS USRFIN',
-            'RVTN_FEFI AS FECFIN',
-            'RVTN_USMO AS USRMOD',
             'RVTN_FEMO AS FECMOD',
+            'RVTN_PRIO AS PRIORIDAD',
+            'RVTN_DEIN AS DESCRIPCION',
+            'RVTN_TIAC AS TIPO_ACTIVACION',
+            'usrReg.USUA_NOMB AS USRREG_NOMB',
+            'usrReg.USUA_APPA AS USRREG_APPA',
+            'usrReg.USUA_APMA AS USRREG_APMA'
         ])->where('RVTN_NULI', '=', $line)
             ->join('S002V01TEQUI', 'EQUI_COEQ', '=', 'RVTN_EQRE')
+            ->leftJoin('S002V01TUSUA as usrReg', function ($join) {
+                $join->on('usrReg.USUA_IDUS', '=', 'S002V01TRVTN.RVTN_USRE')
+                    ->on('usrReg.USUA_NULI', '=', 'S002V01TRVTN.RVTN_NULI');
+            })
             ->orderBy('RVTN_IDVI', 'desc')->get()->all();
 
         foreach ($visits as $visit) {
@@ -2423,19 +2428,12 @@ class PreventiveMaintenanceController extends Controller
             $visit->EQUIPAMIENTO = $this->encryptionController->encrypt($visit->EQUIPAMIENTO);
             $visit->ID_EQUIPAMIENTO = $this->encryptionController->encrypt($visit->ID_EQUIPAMIENTO);
 
-            switch ($visit->ESTATUS) {
-                case 'P':
-                    $usrReg = DB::table('S002V01TUSUA')->where([
-                        ['USUA_NULI', '=', $line],
-                        ['USUA_IDUS', '=', $visit->USRREG]
-                    ])->first();
-
-                    $nameReg = $this->functionsController->joinName($usrReg->USUA_NOMB, $usrReg->USUA_APPA, $usrReg->USUA_APMA);
-                    $nameReg .= " (" . $visit->USRREG . ")";
-
-                    $visit->USRREG = $nameReg;
-                    break;
+            $nameReg = $this->functionsController->joinName($visit->USRREG_NOMB, $visit->USRREG_APPA, $visit->USRREG_APMA);
+            if (!empty($nameReg)) {
+                $visit->USRREG = trim((string) $nameReg) . " (" . $visit->USRREG . ")";
             }
+
+            unset($visit->USRREG_NOMB, $visit->USRREG_APPA, $visit->USRREG_APMA);
         }
 
         $now = $this->functionsController->now();
@@ -2459,6 +2457,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.', $visits);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function getUnprogrammedVisit($idVisit, $idUser, $line)
     {
         DB::enableQueryLog();
@@ -2616,16 +2615,21 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.', $visit);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function updateVisitStatus(Request $request)
     {
+        Log::info($request->all());
         DB::enableQueryLog();
 
+        // RVTN_ESTA enum: 'VA','EP','CP','CE','P','C','R','A','F'
+        // VA, EP, CP, CE: Solo para RVTN_TIAC='A' (Automática)
+        // P, C, R, A, F: Solo para RVTN_TIAC='M' (Manual)
         $validator = Validator::make($request->all(), [
             'id_user' => 'required|string',
             'linea' => 'required|integer',
             'id_visit' => 'required|string',
             'comments' => 'required|string|min:35',
-            'status' => 'required|string|in:C,R,A,F'
+            'status' => 'required|string|in:VA,EP,CP,CE,P,C,R,A,F'
         ]);
 
         if ($validator->fails()) {
@@ -2664,6 +2668,18 @@ class PreventiveMaintenanceController extends Controller
             ['RVTN_IDVI', '=', $idVisit],
         ])->first();
 
+        // Validar que el estado solicitado corresponda al tipo de activación
+        $automaticStates = ['VA', 'EP', 'CP', 'CE'];
+        $manualStates = ['P', 'C', 'R', 'A', 'F'];
+        $isRequestedStateAutomatic = in_array($form['status'], $automaticStates);
+        $isRequestedStateManual = in_array($form['status'], $manualStates);
+
+        if (($visit->RVTN_TIAC === 'A' && !$isRequestedStateAutomatic) ||
+            ($visit->RVTN_TIAC === 'M' && !$isRequestedStateManual)
+        ) {
+            return $this->responseController->makeResponse(true, "El estado {$form['status']} no corresponde al tipo de activación de la visita.", [], 400);
+        }
+
         $commentsArr = json_decode($visit->RVTN_COME, true);
         $commentsArr["C$form[status]"] = $form['comments'];
         $commentsStr = json_encode($commentsArr);
@@ -2678,19 +2694,24 @@ class PreventiveMaintenanceController extends Controller
             'RVTN_FEMO' => $nowStr,
         ];
 
-        if ($form['status'] == 'A' || $form['status'] == 'R') {
+        // Estados automáticos: VA, EP, CP, CE
+        if (in_array($form['status'], ['VA', 'EP', 'CP', 'CE'])) {
             $updateArr['RVTN_UARE'] = $idUser;
             $updateArr['RVTN_FARE'] = $nowStr;
         }
 
-        if ($form['status'] == 'F') {
-            $updateArr['RVTN_USFI'] = $idUser;
-            $updateArr['RVTN_FEFI'] = $nowStr;
-        }
-
-        if ($form['status'] == 'C') {
+        // Estados manuales
+        if ($form['status'] == 'P') {
+            // Pendiente - Ya registrado en creación
+        } elseif ($form['status'] == 'C') {
             $updateArr['RVTN_USCA'] = $idUser;
             $updateArr['RVTN_FECA'] = $nowStr;
+        } elseif ($form['status'] == 'R' || $form['status'] == 'A') {
+            $updateArr['RVTN_UARE'] = $idUser;
+            $updateArr['RVTN_FARE'] = $nowStr;
+        } elseif ($form['status'] == 'F') {
+            $updateArr['RVTN_USFI'] = $idUser;
+            $updateArr['RVTN_FEFI'] = $nowStr;
         }
 
         DB::table('S002V01TRVTN')->where([
@@ -4786,6 +4807,7 @@ class PreventiveMaintenanceController extends Controller
         $this->functionsController->registerLog($actions, $idUser, $nowStr, $idac, $line);
         return $this->responseController->makeResponse(false, 'EXITO.', $workOrders);
     }
+    // Visitas técnicas no programadas (Preventivas)
     public function getVisit($idVisit, $idUser, $line)
     {
         DB::enableQueryLog();
@@ -4918,12 +4940,19 @@ class PreventiveMaintenanceController extends Controller
         $activationTypes = ['M' => 'Manual', 'A' => 'Automática'];
         $visit->TIPO_ACTIVACION = $activationTypes[$visit->TIPO_ACTIVACION];
 
-        // Mapear ESTADO
+        // Mapear ESTADO (RVTN_ESTA enum: 'VA','EP','CP','CE','P','C','R','A','F')
+        // VA, EP, CP, CE: Solo para RVTN_TIAC='A' (Automática)
+        // P, C, R, A, F: Solo para RVTN_TIAC='M' (Manual)
         $orderStates = [
-            'VA' => 'Validado',
-            'EP' => 'En progreso',
-            'CP' => 'Cerrado pendiente',
-            'CE' => 'Cerrado',
+            'VA' => 'Validado',           // Automática
+            'EP' => 'En progreso',        // Automática
+            'CP' => 'Cerrado pendiente',  // Automática
+            'CE' => 'Cerrado',            // Automática
+            'P' => 'Pendiente',           // Manual
+            'C' => 'Cancelado',           // Manual
+            'R' => 'Rechazado',           // Manual
+            'A' => 'Aprobado',            // Manual
+            'F' => 'Finalizado',          // Manual
         ];
         $visit->ESTADO = $orderStates[$visit->ESTADO];
 
@@ -4957,6 +4986,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.', $visit);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function assignOperariosToPreventiveVisit(Request $request)
     {
         DB::enableQueryLog();
@@ -5044,6 +5074,49 @@ class PreventiveMaintenanceController extends Controller
             }
         }
 
+        // Validación de cupo global (basado en RVTN_PEIN)
+        $planilla = json_decode($visit->RVTN_PEIN, true);
+        $cupoRequerido = 0;
+        if (!empty($planilla) && is_array($planilla)) {
+            foreach ($planilla as $pe) {
+                $cupoRequerido += intval($pe['CANT'] ?? 0);
+            }
+        }
+
+        // Obtener último VA
+        $statusHistoryArr = json_decode($visit->RVTN_HIES, true);
+        $vaObj = null;
+        if (!empty($statusHistoryArr)) {
+            for ($i = count($statusHistoryArr) - 1; $i >= 0; $i--) {
+                if ($statusHistoryArr[$i]['ESTADO'] == 'VA') {
+                    $vaObj = $statusHistoryArr[$i];
+                    break;
+                }
+            }
+        }
+
+        $atencionActual = $vaObj && array_key_exists('ATENCION', $vaObj) ? $vaObj['ATENCION'] : [];
+        $aceptadosActual = 0;
+        foreach ($atencionActual as $itm) {
+            if (($itm['RESPUESTA'] ?? '') === 'A') $aceptadosActual++;
+        }
+
+        if ($cupoRequerido > 0 && $aceptadosActual >= $cupoRequerido) {
+            return $this->responseController->makeResponse(true, 'La planilla ya está completa. No se pueden asignar más operarios.', [], 401);
+        }
+
+        // Evitar invitación duplicada al mismo operario (ya invitado o ya respondió)
+        $yaInvitados = [];
+        foreach ($atencionActual as $itm) {
+            $yaInvitados[$itm['ID']] = $itm['RESPUESTA'] ?? '';
+        }
+
+        foreach ($audience as $opId) {
+            if (array_key_exists($opId, $yaInvitados)) {
+                return $this->responseController->makeResponse(true, "El operario $opId ya fue invitado o respondió anteriormente.", [], 401);
+            }
+        }
+
         // Iniciar transacción
         DB::beginTransaction();
 
@@ -5087,6 +5160,26 @@ class PreventiveMaintenanceController extends Controller
                 }
             }
 
+            // Revalidar cupo justo antes de insertar (concurrencia)
+            $vaObjRef = null;
+            if (!empty($statusHistoryArr)) {
+                for ($i = count($statusHistoryArr) - 1; $i >= 0; $i--) {
+                    if ($statusHistoryArr[$i]['ESTADO'] == 'VA') {
+                        $vaObjRef = $statusHistoryArr[$i];
+                        break;
+                    }
+                }
+            }
+            $atencionRef = $vaObjRef && array_key_exists('ATENCION', $vaObjRef) ? $vaObjRef['ATENCION'] : [];
+            $aceptadosRef = 0;
+            foreach ($atencionRef as $itm) {
+                if (($itm['RESPUESTA'] ?? '') === 'A') $aceptadosRef++;
+            }
+            if ($cupoRequerido > 0 && $aceptadosRef >= $cupoRequerido) {
+                DB::rollBack();
+                return $this->responseController->makeResponse(true, 'La planilla ya está completa. No se pueden asignar más operarios.', [], 401);
+            }
+
             // Crear nuevas invitaciones
             $newInvitations = [];
             foreach ($audience as $operarioId) {
@@ -5171,6 +5264,7 @@ class PreventiveMaintenanceController extends Controller
         }
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function getVisitAttendance($idVisit, $idUser, $line)
     {
         DB::enableQueryLog();
@@ -5225,6 +5319,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO', $attendanceAux);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function getVisitStaff($idVisit, $idUser, $line)
     {
         DB::enableQueryLog();
@@ -5331,6 +5426,7 @@ class PreventiveMaintenanceController extends Controller
 
         return $this->responseController->makeResponse(false, 'EXITO', $staffArr);
     }
+    // Visitas técnicas no programadas (Preventivas)
     public function getVisitStatusHistory($idOrder, $idUser, $line)
     {
         DB::enableQueryLog();
@@ -5365,15 +5461,19 @@ class PreventiveMaintenanceController extends Controller
             return $this->responseController->makeResponse(true, 'La visita solicitada no está registrada.', [], 404);
         }
 
+        // RVTN_ESTA enum: 'VA','EP','CP','CE','P','C','R','A','F'
+        // VA, EP, CP, CE: Solo para RVTN_TIAC='A' (Automática)
+        // P, C, R, A, F: Solo para RVTN_TIAC='M' (Manual)
         $visitStates = [
-            'PE' => 'Pendiente',
-            'VA' => 'Validado',
-            'RE' => 'Rechazado',
-            'EP' => 'En progreso',
-            'CE' => 'Cerrado',
-            'CP' => 'Cerrado pendiente',
-            'CA' => 'Cancelado',
-            'EL' => 'Eliminado'
+            'VA' => 'Validado',           // Automática
+            'EP' => 'En progreso',        // Automática
+            'CP' => 'Cerrado pendiente',  // Automática
+            'CE' => 'Cerrado',            // Automática
+            'P' => 'Pendiente',           // Manual
+            'C' => 'Cancelado',           // Manual
+            'R' => 'Rechazado',           // Manual
+            'A' => 'Aprobado',            // Manual
+            'F' => 'Finalizado',          // Manual
         ];
 
         $statusHistoryArr = json_decode($visit->HISTORIAL, true);
@@ -5415,6 +5515,7 @@ class PreventiveMaintenanceController extends Controller
         return $this->responseController->makeResponse(false, 'EXITO.', $statusHistoryArr);
     }
 
+    // Visitas técnicas no programadas (Preventivas)
     public function attendPreventiveVisit(Request $request)
     {
         DB::enableQueryLog();
@@ -5475,6 +5576,15 @@ class PreventiveMaintenanceController extends Controller
             return $this->responseController->makeResponse(true, 'La cadena de comentarios tiene una longitud menor a 10 caracteres.', [], 400);
         }
 
+        // Cupo global requerido (RVTN_PEIN)
+        $planilla = json_decode($visit->RVTN_PEIN, true);
+        $cupoRequerido = 0;
+        if (!empty($planilla) && is_array($planilla)) {
+            foreach ($planilla as $pe) {
+                $cupoRequerido += intval($pe['CANT'] ?? 0);
+            }
+        }
+
         // Obtener historial de estados
         $statusHistoryArr = json_decode($visit->RVTN_HIES, true);
 
@@ -5511,6 +5621,15 @@ class PreventiveMaintenanceController extends Controller
             return $this->responseController->makeResponse(true, "Ya ha $respuestaAnterior esta invitación.", [], 401);
         }
 
+        // Bloquear aceptación si la planilla ya está completa (con base en aceptados actuales)
+        $aceptadosActual = 0;
+        foreach ($atencionArr as $itm) {
+            if (($itm['RESPUESTA'] ?? '') === 'A') $aceptadosActual++;
+        }
+        if ($form['attendance'] == 'A' && $cupoRequerido > 0 && $aceptadosActual >= $cupoRequerido) {
+            return $this->responseController->makeResponse(true, 'La planilla ya está completa. No es posible aceptar esta invitación.', [], 401);
+        }
+
         // Iniciar transacción
         DB::beginTransaction();
 
@@ -5602,6 +5721,30 @@ class PreventiveMaintenanceController extends Controller
                 $comments = $form['data'];
             }
 
+            // Última verificación de cupo (concurrencia) antes de confirmar respuesta
+            $statusHistoryCheck = json_decode(DB::table('S002V01TRVTN')->where([
+                ['RVTN_NULI', '=', $form['linea']],
+                ['RVTN_IDVI', '=', $idVisit]
+            ])->value('RVTN_HIES'), true);
+            $vaObjChk = null;
+            if (!empty($statusHistoryCheck)) {
+                for ($i = count($statusHistoryCheck) - 1; $i >= 0; $i--) {
+                    if ($statusHistoryCheck[$i]['ESTADO'] == 'VA') {
+                        $vaObjChk = $statusHistoryCheck[$i];
+                        break;
+                    }
+                }
+            }
+            $aceptadosChk = 0;
+            $atencionChk = $vaObjChk && array_key_exists('ATENCION', $vaObjChk) ? $vaObjChk['ATENCION'] : [];
+            foreach ($atencionChk as $itm) {
+                if (($itm['RESPUESTA'] ?? '') === 'A') $aceptadosChk++;
+            }
+            if ($form['attendance'] == 'A' && $cupoRequerido > 0 && $aceptadosChk >= $cupoRequerido) {
+                DB::rollBack();
+                return $this->responseController->makeResponse(true, 'La planilla ya está completa. No es posible aceptar esta invitación.', [], 401);
+            }
+
             // Actualizar el objeto en ATENCION
             $statusHistoryArr[$vaStatusIndex]['ATENCION'][$operatorIndex]['RESPUESTA'] = $form['attendance'];
             $statusHistoryArr[$vaStatusIndex]['ATENCION'][$operatorIndex]['FIRMA'] = $signature;