|
|
@@ -2234,6 +2234,7 @@ class PreventiveMaintenanceController extends Controller
|
|
|
// Visitas técnicas no programadas (Preventivas)
|
|
|
public function newUnprogrammedOrder(Request $request)
|
|
|
{
|
|
|
+ Log::info($request->all());
|
|
|
DB::enableQueryLog();
|
|
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
|
@@ -2347,15 +2348,29 @@ class PreventiveMaintenanceController extends Controller
|
|
|
'CI' => $form['comments']
|
|
|
];
|
|
|
|
|
|
+
|
|
|
$now = $this->functionsController->now();
|
|
|
$nowStr = $now->toDateTimeString();
|
|
|
+ $statusHistoryStr = json_encode([
|
|
|
+ [
|
|
|
+ 'FECHA' => $nowStr,
|
|
|
+ 'ESTADO' => 'P',
|
|
|
+ 'USUARIO' => $idUser,
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+
|
|
|
+
|
|
|
$commentsStr = json_encode($commentsArr);
|
|
|
$staffStr = json_encode($staff);
|
|
|
$idVisit = DB::table('S002V01TRVTN')->insertGetId([
|
|
|
'RVTN_NULI' => $form['linea'],
|
|
|
'RVTN_EQRE' => $equipmentCode,
|
|
|
+ 'RVTN_DEIN' => $form['description'],
|
|
|
+ 'RVTN_TIAC' => 'M',
|
|
|
'RVTN_PEIN' => $staffStr,
|
|
|
'RVTN_MAUT' => $form['resources'],
|
|
|
+ 'RVTN_ESTA' => 'P',
|
|
|
+ 'RVTN_HIES' => $statusHistoryStr,
|
|
|
'RVTN_COME' => $commentsStr,
|
|
|
'RVTN_USRE' => $idUser,
|
|
|
'RVTN_FERE' => $nowStr,
|
|
|
@@ -2624,6 +2639,7 @@ class PreventiveMaintenanceController extends Controller
|
|
|
// 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)
|
|
|
+ // EP y C son compartidos entre ambos tipos
|
|
|
$validator = Validator::make($request->all(), [
|
|
|
'id_user' => 'required|string',
|
|
|
'linea' => 'required|integer',
|
|
|
@@ -2668,48 +2684,134 @@ class PreventiveMaintenanceController extends Controller
|
|
|
['RVTN_IDVI', '=', $idVisit],
|
|
|
])->first();
|
|
|
|
|
|
+ if (is_null($visit)) {
|
|
|
+ return $this->responseController->makeResponse(true, 'La visita solicitada no existe.', [], 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ $currentStatus = $visit->RVTN_ESTA;
|
|
|
+ $newStatus = $form['status'];
|
|
|
+ $visitType = $visit->RVTN_TIAC; // 'A' = Automática, 'M' = Manual
|
|
|
+
|
|
|
// 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)
|
|
|
+ $isRequestedStateAutomatic = in_array($newStatus, $automaticStates);
|
|
|
+ $isRequestedStateManual = in_array($newStatus, $manualStates);
|
|
|
+
|
|
|
+ // EP y C son compartidos, ajustar validación
|
|
|
+ if ($newStatus === 'EP' || $newStatus === 'C') {
|
|
|
+ // Permitir EP y C para ambos tipos
|
|
|
+ } elseif (($visitType === 'A' && !$isRequestedStateAutomatic) ||
|
|
|
+ ($visitType === 'M' && !$isRequestedStateManual)
|
|
|
) {
|
|
|
- return $this->responseController->makeResponse(true, "El estado {$form['status']} no corresponde al tipo de activación de la visita.", [], 400);
|
|
|
+ return $this->responseController->makeResponse(true, "El estado {$newStatus} no corresponde al tipo de activación de la visita.", [], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Matriz de transiciones permitidas
|
|
|
+ $allowedTransitions = [
|
|
|
+ 'A' => [ // Visitas Automáticas
|
|
|
+ 'VA' => ['EP', 'C'], // Validado -> En Proceso o Cancelar
|
|
|
+ 'EP' => ['CP', 'C'], // En Proceso -> Cerrado Pendiente o Cancelar
|
|
|
+ 'CP' => ['CE', 'C'], // Cerrado Pendiente -> Cerrado o Cancelar (aunque C desde CP está bloqueado)
|
|
|
+ 'CE' => [] // Cerrado - Estado final, no se puede cambiar
|
|
|
+ ],
|
|
|
+ 'M' => [ // Visitas Manuales
|
|
|
+ 'P' => ['A', 'R', 'C'], // Pendiente -> Aprobar, Rechazar o Cancelar
|
|
|
+ 'A' => ['EP', 'C'], // Aprobado -> En Proceso o Cancelar
|
|
|
+ 'EP' => ['F', 'C'], // En Proceso -> Finalizar o Cancelar
|
|
|
+ 'F' => [], // Finalizado - Estado final, no se puede cambiar
|
|
|
+ 'R' => [] // Rechazado - Estado final, no se puede cambiar
|
|
|
+ ]
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Validar transición permitida
|
|
|
+ $currentStatusTransitions = $allowedTransitions[$visitType][$currentStatus] ?? [];
|
|
|
+
|
|
|
+ // Si el estado actual no está en la matriz, no permitir cambios
|
|
|
+ if (!array_key_exists($currentStatus, $allowedTransitions[$visitType])) {
|
|
|
+ return $this->responseController->makeResponse(true, "El estado actual {$currentStatus} no permite cambios.", [], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validar si la transición está permitida
|
|
|
+ if (!in_array($newStatus, $currentStatusTransitions)) {
|
|
|
+ $statusNames = [
|
|
|
+ 'VA' => 'Validado',
|
|
|
+ 'EP' => 'En Proceso',
|
|
|
+ 'CP' => 'Cerrado Pendiente',
|
|
|
+ 'CE' => 'Cerrado',
|
|
|
+ 'P' => 'Pendiente',
|
|
|
+ 'A' => 'Aprobado',
|
|
|
+ 'R' => 'Rechazado',
|
|
|
+ 'F' => 'Finalizado',
|
|
|
+ 'C' => 'Cancelado'
|
|
|
+ ];
|
|
|
+ $currentStatusName = $statusNames[$currentStatus] ?? $currentStatus;
|
|
|
+ $newStatusName = $statusNames[$newStatus] ?? $newStatus;
|
|
|
+ return $this->responseController->makeResponse(true, "No se puede cambiar de {$currentStatusName} a {$newStatusName}. Transición no permitida.", [], 400);
|
|
|
}
|
|
|
|
|
|
+ // Validar cancelación desde estados finales
|
|
|
+ if ($newStatus === 'C') {
|
|
|
+ $finalStates = $visitType === 'A' ? ['CE'] : ['F', 'R'];
|
|
|
+ if (in_array($currentStatus, $finalStates)) {
|
|
|
+ return $this->responseController->makeResponse(true, "No se puede cancelar una visita que ya está en estado final.", [], 400);
|
|
|
+ }
|
|
|
+ // También bloquear desde CP según aclaración
|
|
|
+ if ($currentStatus === 'CP') {
|
|
|
+ return $this->responseController->makeResponse(true, "No se puede cancelar una visita en estado Cerrado Pendiente.", [], 400);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Actualizar comentarios
|
|
|
$commentsArr = json_decode($visit->RVTN_COME, true);
|
|
|
- $commentsArr["C$form[status]"] = $form['comments'];
|
|
|
+ if (!is_array($commentsArr)) {
|
|
|
+ $commentsArr = [];
|
|
|
+ }
|
|
|
+ $commentsArr["C$newStatus"] = $form['comments'];
|
|
|
$commentsStr = json_encode($commentsArr);
|
|
|
|
|
|
+ // Obtener y actualizar historial de estados
|
|
|
+ $statusHistoryArr = json_decode($visit->RVTN_HIES, true);
|
|
|
+ if (!is_array($statusHistoryArr)) {
|
|
|
+ $statusHistoryArr = [];
|
|
|
+ }
|
|
|
+
|
|
|
$now = $this->functionsController->now();
|
|
|
$nowStr = $now->toDateTimeString();
|
|
|
|
|
|
+ // Agregar nuevo estado al historial
|
|
|
+ $statusHistoryArr[] = [
|
|
|
+ 'FECHA' => $nowStr,
|
|
|
+ 'ESTADO' => $newStatus,
|
|
|
+ 'USUARIO' => $idUser
|
|
|
+ ];
|
|
|
+ $statusHistoryStr = json_encode($statusHistoryArr);
|
|
|
+
|
|
|
+ // Preparar actualización
|
|
|
$updateArr = [
|
|
|
- 'RVTN_ESTA' => $form['status'],
|
|
|
+ 'RVTN_ESTA' => $newStatus,
|
|
|
'RVTN_COME' => $commentsStr,
|
|
|
+ 'RVTN_HIES' => $statusHistoryStr,
|
|
|
'RVTN_USMO' => $idUser,
|
|
|
'RVTN_FEMO' => $nowStr,
|
|
|
];
|
|
|
|
|
|
// Estados automáticos: VA, EP, CP, CE
|
|
|
- if (in_array($form['status'], ['VA', 'EP', 'CP', 'CE'])) {
|
|
|
+ if (in_array($newStatus, ['VA', 'EP', 'CP', 'CE'])) {
|
|
|
$updateArr['RVTN_UARE'] = $idUser;
|
|
|
$updateArr['RVTN_FARE'] = $nowStr;
|
|
|
}
|
|
|
|
|
|
// Estados manuales
|
|
|
- if ($form['status'] == 'P') {
|
|
|
+ if ($newStatus == 'P') {
|
|
|
// Pendiente - Ya registrado en creación
|
|
|
- } elseif ($form['status'] == 'C') {
|
|
|
+ } elseif ($newStatus == 'C') {
|
|
|
$updateArr['RVTN_USCA'] = $idUser;
|
|
|
$updateArr['RVTN_FECA'] = $nowStr;
|
|
|
- } elseif ($form['status'] == 'R' || $form['status'] == 'A') {
|
|
|
+ } elseif ($newStatus == 'R' || $newStatus == 'A') {
|
|
|
$updateArr['RVTN_UARE'] = $idUser;
|
|
|
$updateArr['RVTN_FARE'] = $nowStr;
|
|
|
- } elseif ($form['status'] == 'F') {
|
|
|
+ } elseif ($newStatus == 'F') {
|
|
|
$updateArr['RVTN_USFI'] = $idUser;
|
|
|
$updateArr['RVTN_FEFI'] = $nowStr;
|
|
|
}
|
|
|
@@ -2719,6 +2821,75 @@ class PreventiveMaintenanceController extends Controller
|
|
|
['RVTN_IDVI', '=', $idVisit],
|
|
|
])->update($updateArr);
|
|
|
|
|
|
+ // Obtener audiencia para notificaciones (operarios y regulador)
|
|
|
+ $audience = [];
|
|
|
+
|
|
|
+ // Obtener operarios que aceptaron la invitación (del último estado VA)
|
|
|
+ $statusHistoryForAudience = json_decode($visit->RVTN_HIES, true);
|
|
|
+ if (is_array($statusHistoryForAudience)) {
|
|
|
+ // Buscar el último estado VA
|
|
|
+ $lastVAStatus = null;
|
|
|
+ for ($i = count($statusHistoryForAudience) - 1; $i >= 0; $i--) {
|
|
|
+ if ($statusHistoryForAudience[$i]['ESTADO'] === 'VA') {
|
|
|
+ $lastVAStatus = $statusHistoryForAudience[$i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($lastVAStatus && isset($lastVAStatus['ATENCION']) && is_array($lastVAStatus['ATENCION'])) {
|
|
|
+ foreach ($lastVAStatus['ATENCION'] as $item) {
|
|
|
+ if (($item['RESPUESTA'] ?? '') === 'A') {
|
|
|
+ $audience[] = $item['ID'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Agregar regulador (quien registró la visita)
|
|
|
+ if (!empty($visit->RVTN_USRE) && !in_array($visit->RVTN_USRE, $audience)) {
|
|
|
+ $audience[] = $visit->RVTN_USRE;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Preparar mensajes de notificación según el estado
|
|
|
+ $statusMessages = [
|
|
|
+ 'A' => 'Aprobación',
|
|
|
+ 'R' => 'Rechazo',
|
|
|
+ 'C' => 'Cancelación',
|
|
|
+ 'EP' => 'Inicio',
|
|
|
+ 'F' => 'Finalización',
|
|
|
+ 'VA' => 'Validación',
|
|
|
+ 'CP' => 'Cerrado Pendiente',
|
|
|
+ 'CE' => 'Cierre'
|
|
|
+ ];
|
|
|
+
|
|
|
+ $statusAction = $statusMessages[$newStatus] ?? 'Cambio de estado';
|
|
|
+ $notificationTitle = "Visita Técnica No Programada #$idVisit";
|
|
|
+ $notificationMessage = "La visita técnica no programada #$idVisit ha sido {$statusAction}.";
|
|
|
+
|
|
|
+ // Notificación general para todos los cambios de estado (A, R, C, EP, F, VA, CE, CP)
|
|
|
+ if (in_array($newStatus, ['A', 'R', 'C', 'EP', 'F', 'VA', 'CE', 'CP']) && !empty($audience)) {
|
|
|
+ $this->notificationsController->emitNotification(
|
|
|
+ 'S002V01M10GMPR',
|
|
|
+ $notificationTitle,
|
|
|
+ $notificationMessage,
|
|
|
+ [[
|
|
|
+ 'BOTON' => 'Ver detalles',
|
|
|
+ 'FUNCION' => 'openPreventiveWorkOrderDetails',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt($idVisit)])
|
|
|
+ ], [
|
|
|
+ 'BOTON' => 'Ir al módulo',
|
|
|
+ 'FUNCION' => 'openModule',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt('GMPR/AOTR/RVTP')])
|
|
|
+ ]],
|
|
|
+ $audience,
|
|
|
+ $idUser,
|
|
|
+ $form['linea'],
|
|
|
+ $this->getSocketClient(),
|
|
|
+ $idVisit,
|
|
|
+ 'Preventivo'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
$actions = DB::getQueryLog();
|
|
|
$name = $this->functionsController->joinName($usr->USUA_NOMB, $usr->USUA_APPA, $usr->USUA_APMA);
|
|
|
|
|
|
@@ -2738,6 +2909,342 @@ class PreventiveMaintenanceController extends Controller
|
|
|
return $this->responseController->makeResponse(false, 'EXITO.');
|
|
|
}
|
|
|
|
|
|
+ // Visitas técnicas no programadas (Preventivas)
|
|
|
+ // Registrar comentario de finalización de un operario en estado CP
|
|
|
+ public function registerOperatorClosingComment(Request $request)
|
|
|
+ {
|
|
|
+ DB::enableQueryLog();
|
|
|
+
|
|
|
+ $validator = Validator::make($request->all(), [
|
|
|
+ 'id_user' => 'required|string',
|
|
|
+ 'linea' => 'required|integer',
|
|
|
+ 'id_visit' => 'required|string',
|
|
|
+ 'comment' => 'required|string|min:35'
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if ($validator->fails()) {
|
|
|
+ return $this->responseController->makeResponse(
|
|
|
+ true,
|
|
|
+ "Se encontraron uno o más errores.",
|
|
|
+ $this->responseController->makeErrors(
|
|
|
+ $validator->errors()->messages()
|
|
|
+ ),
|
|
|
+ 401
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ $form = $request->all();
|
|
|
+ $idUser = $this->encryptionController->decrypt($form['id_user']);
|
|
|
+ if (!$idUser) {
|
|
|
+ return $this->responseController->makeResponse(true, 'El ID del usuario que realizó la solicitud no está encriptado correctamente.', [], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ $usr = DB::table('S002V01TUSUA')->where([
|
|
|
+ ['USUA_NULI', '=', $form['linea']],
|
|
|
+ ['USUA_IDUS', '=', $idUser],
|
|
|
+ ])->first();
|
|
|
+
|
|
|
+ if (is_null($usr)) {
|
|
|
+ return $this->responseController->makeResponse(true, 'El usuario que realizó la consulta no está registrado.', [], 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ $idVisit = $this->encryptionController->decrypt($form['id_visit']);
|
|
|
+ if (!$idVisit) {
|
|
|
+ return $this->responseController->makeResponse(true, 'El ID de la visita solicitada no está encriptado correctamente.', [], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ $visit = DB::table('S002V01TRVTN')->where([
|
|
|
+ ['RVTN_NULI', '=', $form['linea']],
|
|
|
+ ['RVTN_IDVI', '=', $idVisit],
|
|
|
+ ])->first();
|
|
|
+
|
|
|
+ if (is_null($visit)) {
|
|
|
+ return $this->responseController->makeResponse(true, 'La visita solicitada no existe.', [], 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validar que la visita está en estado EP o CP
|
|
|
+ if (!in_array($visit->RVTN_ESTA, ['EP', 'CP'])) {
|
|
|
+ return $this->responseController->makeResponse(true, 'La visita no está en estado En Proceso o Cerrado Pendiente. Solo se pueden registrar comentarios de finalización en estos estados.', [], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Iniciar transacción
|
|
|
+ DB::beginTransaction();
|
|
|
+
|
|
|
+ try {
|
|
|
+ // Obtener historial de estados
|
|
|
+ $statusHistoryArr = json_decode($visit->RVTN_HIES, true);
|
|
|
+ if (!is_array($statusHistoryArr)) {
|
|
|
+ DB::rollBack();
|
|
|
+ return $this->responseController->makeResponse(true, 'No se encontró un historial de estados válido para la visita.', [], 500);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Buscar el último estado VA para obtener la lista de operarios que aceptaron
|
|
|
+ $lastVAStatus = null;
|
|
|
+ $acceptedOperators = [];
|
|
|
+ for ($i = count($statusHistoryArr) - 1; $i >= 0; $i--) {
|
|
|
+ if ($statusHistoryArr[$i]['ESTADO'] === 'VA') {
|
|
|
+ $lastVAStatus = $statusHistoryArr[$i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!$lastVAStatus || !isset($lastVAStatus['ATENCION']) || !is_array($lastVAStatus['ATENCION'])) {
|
|
|
+ DB::rollBack();
|
|
|
+ return $this->responseController->makeResponse(true, 'No se encontró información de operarios asignados a la visita.', [], 404);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Obtener lista de operarios que aceptaron
|
|
|
+ foreach ($lastVAStatus['ATENCION'] as $item) {
|
|
|
+ if (($item['RESPUESTA'] ?? '') === 'A') {
|
|
|
+ $acceptedOperators[] = $item['ID'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validar que el usuario es uno de los operarios que aceptó
|
|
|
+ if (!in_array($idUser, $acceptedOperators)) {
|
|
|
+ DB::rollBack();
|
|
|
+ return $this->responseController->makeResponse(true, 'El usuario no está autorizado para registrar comentarios de finalización. Solo los operarios que aceptaron la invitación pueden registrar comentarios.', [], 401);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Buscar el objeto CP en el historial o crearlo si no existe
|
|
|
+ $cpStatusIndex = null;
|
|
|
+ $cpStatus = null;
|
|
|
+ $isFirstComment = false;
|
|
|
+ for ($i = count($statusHistoryArr) - 1; $i >= 0; $i--) {
|
|
|
+ if ($statusHistoryArr[$i]['ESTADO'] === 'CP') {
|
|
|
+ $cpStatusIndex = $i;
|
|
|
+ $cpStatus = $statusHistoryArr[$i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Si no existe objeto CP, crear uno nuevo y cambiar estado de EP a CP
|
|
|
+ if ($cpStatusIndex === null) {
|
|
|
+ $now = $this->functionsController->now();
|
|
|
+ $nowStr = $now->toDateTimeString();
|
|
|
+ $isFirstComment = true;
|
|
|
+
|
|
|
+ $cpStatus = [
|
|
|
+ 'FECHA' => $nowStr,
|
|
|
+ 'ESTADO' => 'CP',
|
|
|
+ 'USUARIO' => $idUser,
|
|
|
+ 'COMENTARIOS_OPERARIOS' => []
|
|
|
+ ];
|
|
|
+ $cpStatusIndex = count($statusHistoryArr);
|
|
|
+ $statusHistoryArr[] = $cpStatus;
|
|
|
+ } else {
|
|
|
+ // Asegurar que existe el array de comentarios
|
|
|
+ if (!isset($cpStatus['COMENTARIOS_OPERARIOS']) || !is_array($cpStatus['COMENTARIOS_OPERARIOS'])) {
|
|
|
+ $cpStatus['COMENTARIOS_OPERARIOS'] = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validar que el operario no haya registrado comentario ya
|
|
|
+ foreach ($cpStatus['COMENTARIOS_OPERARIOS'] as $existingComment) {
|
|
|
+ if (isset($existingComment['ID']) && $existingComment['ID'] === $idUser) {
|
|
|
+ DB::rollBack();
|
|
|
+ return $this->responseController->makeResponse(true, 'Ya ha registrado su comentario de finalización para esta visita.', [], 400);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Registrar el comentario del operario
|
|
|
+ $now = $this->functionsController->now();
|
|
|
+ $nowStr = $now->toDateTimeString();
|
|
|
+
|
|
|
+ $operatorName = $this->functionsController->joinName($usr->USUA_NOMB, $usr->USUA_APPA, $usr->USUA_APMA);
|
|
|
+
|
|
|
+ $cpStatus['COMENTARIOS_OPERARIOS'][] = [
|
|
|
+ 'ID' => $idUser,
|
|
|
+ 'COMENTARIO' => $form['comment'],
|
|
|
+ 'FECHA' => $nowStr
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Actualizar el objeto en el historial
|
|
|
+ $statusHistoryArr[$cpStatusIndex] = $cpStatus;
|
|
|
+ $statusHistoryStr = json_encode($statusHistoryArr);
|
|
|
+
|
|
|
+ // Contar comentarios registrados vs total de operarios
|
|
|
+ $commentsRegistered = count($cpStatus['COMENTARIOS_OPERARIOS']);
|
|
|
+ $totalOperators = count($acceptedOperators);
|
|
|
+ $isComplete = $commentsRegistered >= $totalOperators;
|
|
|
+
|
|
|
+ // Preparar actualización de la visita
|
|
|
+ $updateArr = [
|
|
|
+ 'RVTN_HIES' => $statusHistoryStr,
|
|
|
+ 'RVTN_USMO' => $idUser,
|
|
|
+ 'RVTN_FEMO' => $nowStr,
|
|
|
+ ];
|
|
|
+
|
|
|
+ // Si es el primer comentario, cambiar estado de EP a CP
|
|
|
+ if ($isFirstComment) {
|
|
|
+ $updateArr['RVTN_ESTA'] = 'CP';
|
|
|
+ $updateArr['RVTN_UARE'] = $idUser;
|
|
|
+ $updateArr['RVTN_FARE'] = $nowStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Actualizar comentarios si es necesario
|
|
|
+ $commentsArr = json_decode($visit->RVTN_COME, true);
|
|
|
+ if (!is_array($commentsArr)) {
|
|
|
+ $commentsArr = [];
|
|
|
+ }
|
|
|
+ // Solo agregar comentario de cambio de estado si es el primer comentario (cambio EP -> CP)
|
|
|
+ if ($isFirstComment) {
|
|
|
+ $commentsArr['CCP'] = 'Inicio de registro de comentarios de finalización por operarios.';
|
|
|
+ }
|
|
|
+ $commentsStr = json_encode($commentsArr);
|
|
|
+ $updateArr['RVTN_COME'] = $commentsStr;
|
|
|
+
|
|
|
+ // Actualizar la visita
|
|
|
+ DB::table('S002V01TRVTN')->where([
|
|
|
+ ['RVTN_NULI', '=', $form['linea']],
|
|
|
+ ['RVTN_IDVI', '=', $idVisit],
|
|
|
+ ])->update($updateArr);
|
|
|
+
|
|
|
+ // Obtener regulador para notificaciones
|
|
|
+ $regulatorId = $visit->RVTN_USRE;
|
|
|
+ $regulatorAudience = !empty($regulatorId) ? [$regulatorId] : [];
|
|
|
+
|
|
|
+ // Obtener audiencia completa (operarios y regulador) para notificación de cambio de estado
|
|
|
+ $audience = [];
|
|
|
+ if (!empty($lastVAStatus['ATENCION']) && is_array($lastVAStatus['ATENCION'])) {
|
|
|
+ foreach ($lastVAStatus['ATENCION'] as $item) {
|
|
|
+ if (($item['RESPUESTA'] ?? '') === 'A') {
|
|
|
+ $audience[] = $item['ID'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!empty($regulatorId) && !in_array($regulatorId, $audience)) {
|
|
|
+ $audience[] = $regulatorId;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Si es el primer comentario (cambio EP -> CP), notificar a todos
|
|
|
+ if ($isFirstComment && !empty($audience)) {
|
|
|
+ $notificationTitle = "Visita Técnica No Programada #$idVisit";
|
|
|
+ $notificationMessage = "La visita técnica no programada #$idVisit ha pasado a estado Cerrado Pendiente.";
|
|
|
+
|
|
|
+ $this->notificationsController->emitNotification(
|
|
|
+ 'S002V01M10GMPR',
|
|
|
+ $notificationTitle,
|
|
|
+ $notificationMessage,
|
|
|
+ [[
|
|
|
+ 'BOTON' => 'Ver detalles',
|
|
|
+ 'FUNCION' => 'openPreventiveWorkOrderDetails',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt($idVisit)])
|
|
|
+ ], [
|
|
|
+ 'BOTON' => 'Ir al módulo',
|
|
|
+ 'FUNCION' => 'openModule',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt('GMPR/AOTR/RVTP')])
|
|
|
+ ]],
|
|
|
+ $audience,
|
|
|
+ $idUser,
|
|
|
+ $form['linea'],
|
|
|
+ $this->getSocketClient(),
|
|
|
+ $idVisit,
|
|
|
+ 'Preventivo'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Notificar al regulador por cada comentario registrado
|
|
|
+ if (!empty($regulatorAudience)) {
|
|
|
+ $notificationTitle = "Visita Técnica No Programada #$idVisit";
|
|
|
+ $notificationMessage = "El usuario $operatorName ($idUser) registró comentario de finalización de la visita #$idVisit.";
|
|
|
+
|
|
|
+ $this->notificationsController->emitNotification(
|
|
|
+ 'S002V01M10GMPR',
|
|
|
+ $notificationTitle,
|
|
|
+ $notificationMessage,
|
|
|
+ [[
|
|
|
+ 'BOTON' => 'Ver detalles',
|
|
|
+ 'FUNCION' => 'openPreventiveWorkOrderDetails',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt($idVisit)])
|
|
|
+ ], [
|
|
|
+ 'BOTON' => 'Ir al módulo',
|
|
|
+ 'FUNCION' => 'openModule',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt('GMPR/AOTR/RVTP')])
|
|
|
+ ]],
|
|
|
+ $regulatorAudience,
|
|
|
+ $idUser,
|
|
|
+ $form['linea'],
|
|
|
+ $this->getSocketClient(),
|
|
|
+ $idVisit,
|
|
|
+ 'Preventivo'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Si todos los comentarios están completos, enviar notificación final
|
|
|
+ if ($isComplete && !empty($regulatorAudience)) {
|
|
|
+ $finalNotificationTitle = "Visita Técnica No Programada #$idVisit";
|
|
|
+ $finalNotificationMessage = "La visita #$idVisit ya puede ser cerrada. Todos los operarios han registrado sus comentarios de finalización.";
|
|
|
+
|
|
|
+ $this->notificationsController->emitNotification(
|
|
|
+ 'S002V01M10GMPR',
|
|
|
+ $finalNotificationTitle,
|
|
|
+ $finalNotificationMessage,
|
|
|
+ [[
|
|
|
+ 'BOTON' => 'Cerrar visita',
|
|
|
+ 'FUNCION' => 'closePreventiveVisit',
|
|
|
+ 'PARAMETROS' => json_encode([
|
|
|
+ $this->encryptionController->encrypt($idVisit),
|
|
|
+ $this->encryptionController->encrypt($form['linea']),
|
|
|
+ $this->encryptionController->encrypt($regulatorId)
|
|
|
+ ])
|
|
|
+ ], [
|
|
|
+ 'BOTON' => 'Ver detalles',
|
|
|
+ 'FUNCION' => 'openPreventiveWorkOrderDetails',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt($idVisit)])
|
|
|
+ ], [
|
|
|
+ 'BOTON' => 'Ir al módulo',
|
|
|
+ 'FUNCION' => 'openModule',
|
|
|
+ 'PARAMETROS' => json_encode([$this->encryptionController->encrypt('GMPR/AOTR/RVTP')])
|
|
|
+ ]],
|
|
|
+ $regulatorAudience,
|
|
|
+ $idUser,
|
|
|
+ $form['linea'],
|
|
|
+ $this->getSocketClient(),
|
|
|
+ $idVisit,
|
|
|
+ 'Preventivo'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Confirmar transacción
|
|
|
+ DB::commit();
|
|
|
+
|
|
|
+ $actions = DB::getQueryLog();
|
|
|
+ $name = $this->functionsController->joinName($usr->USUA_NOMB, $usr->USUA_APPA, $usr->USUA_APMA);
|
|
|
+
|
|
|
+ $idac = $this->functionsController->registerActivity(
|
|
|
+ $form['linea'],
|
|
|
+ 'S002V01M10GMPR',
|
|
|
+ 'S002V01F11RVTP',
|
|
|
+ 'S002V01P01REVI',
|
|
|
+ 'Actualización',
|
|
|
+ "El usuario $name (" . $usr->USUA_IDUS . ") registró comentario de finalización para la visita no programada #$idVisit.",
|
|
|
+ $idUser,
|
|
|
+ $nowStr,
|
|
|
+ 'S002V01S02AOTR'
|
|
|
+ );
|
|
|
+
|
|
|
+ $this->functionsController->registerLog($actions, $idUser, $nowStr, $idac, $form['linea']);
|
|
|
+
|
|
|
+ return $this->responseController->makeResponse(false, 'EXITO.', [
|
|
|
+ 'comments_registered' => $commentsRegistered,
|
|
|
+ 'total_operators' => $totalOperators,
|
|
|
+ 'is_complete' => $isComplete
|
|
|
+ ]);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ // Revertir transacción en caso de error
|
|
|
+ DB::rollBack();
|
|
|
+
|
|
|
+ Log::error('Error en registerOperatorClosingComment: ' . $e->getMessage());
|
|
|
+ return $this->responseController->makeResponse(
|
|
|
+ true,
|
|
|
+ 'Ocurrió un error al registrar el comentario de finalización.',
|
|
|
+ ['error' => $e->getMessage()],
|
|
|
+ 500
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Visitas técnicas no programadas (Preventivas)
|
|
|
public function startPreventiveVisit(Request $request)
|
|
|
{
|
|
|
@@ -2846,6 +3353,15 @@ class PreventiveMaintenanceController extends Controller
|
|
|
|
|
|
$statusHistoryStr = json_encode($statusHistoryArr);
|
|
|
|
|
|
+ /*
|
|
|
+ $commentsArr = json_decode($visit->RVTN_COME, true);
|
|
|
+ if (!is_array($commentsArr)) {
|
|
|
+ $commentsArr = [];
|
|
|
+ }
|
|
|
+ $commentsArr['COMENTARIO_INICIO'] = $form['comments'];
|
|
|
+ $commentsStr = json_encode($commentsArr);
|
|
|
+ */
|
|
|
+
|
|
|
DB::table('S002V01TRVTN')->where([
|
|
|
['RVTN_IDVI', '=', $idVisit],
|
|
|
['RVTN_NULI', '=', $form['linea']]
|
|
|
@@ -2858,8 +3374,8 @@ class PreventiveMaintenanceController extends Controller
|
|
|
|
|
|
$this->notificationsController->emitNotification(
|
|
|
'S002V01M10GMPR',
|
|
|
- "Visita de mantenimiento preventivo #$idVisit",
|
|
|
- "Inicio de la ejecución de la visita de mantenimiento preventivo #$idVisit.",
|
|
|
+ "Visita Técnica No Programada #$idVisit",
|
|
|
+ "Inicio de la ejecución de la visita técnica no programada #$idVisit.",
|
|
|
[[
|
|
|
'BOTON' => 'Ver detalles',
|
|
|
'FUNCION' => 'openPreventiveWorkOrderDetails',
|
|
|
@@ -2886,7 +3402,7 @@ class PreventiveMaintenanceController extends Controller
|
|
|
'S002V01F11RVTP',
|
|
|
'S002V01P01REVI',
|
|
|
'Actualización',
|
|
|
- "El usuario $name (" . $usr->USUA_IDUS . ") inició la visita preventiva #$idVisit.",
|
|
|
+ "El usuario $name (" . $usr->USUA_IDUS . ") inició la visita técnica no programada #$idVisit.",
|
|
|
$idUser,
|
|
|
$nowStr,
|
|
|
'S002V01S02AOTR'
|