import { Component, OnInit, ViewChild } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { UnprogrammedVisit, UnprogrammedVisitsResponse, } from '../../../interfaces/unprogrammed-visits.interface'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { EncService } from '../../../services/enc.service'; import { PreventiveMaintenanceService } from '../../../services/preventive-maintenance.service'; import { lastValueFrom } from 'rxjs'; import { Router } from '@angular/router'; import { PriorityInterface } from '../../system-admin/system-params/system-params.component'; import { SystemAdminService } from '../../../services/system-admin.service'; import { FunctionsService } from '../../../services/functions.service'; import { MatDialog } from '@angular/material/dialog'; import { PreventiveOrderDetailsComponent } from '../preventive-order-details/preventive-order-details.component'; import { ResourcesService } from '../../../services/resources.service'; import { AlertComponent } from '../../resources/dialogs/alert/alert.component'; import { CommnetsDialogComponent } from '../../corrective-maintenance/operations-management/commnets-dialog/commnets-dialog.component'; @Component({ selector: 'app-unprogrammed-visits', templateUrl: './unprogrammed-visits.component.html', styleUrl: './unprogrammed-visits.component.css', standalone: false, }) export class UnprogrammedVisitsComponent implements OnInit { btnSmall: boolean; txtBuscador: string; dataSource?: MatTableDataSource; displayedColumns = [ 'numeracion', 'equipamiento', 'descripcion', 'estado', 'prioridad', 'tipoActivacion', 'fechaRegistro', 'acciones', ]; @ViewChild(MatPaginator) paginator?: MatPaginator; @ViewChild(MatSort) sort?: MatSort; isLoading: boolean; hasError: boolean; errorStr: string; priorityMap: Map; private readonly activationTypeLabels: Record = { A: 'Automática', M: 'Manual', }; private readonly statusLabels: Record = { VA: 'Validado', EP: 'En proceso', CP: 'Cerrado pendiente', CE: 'Cerrado', P: 'Pendiente', C: 'Cancelado', R: 'Rechazado', A: 'Aprobado', F: 'Finalizado', }; constructor( private _encService: EncService, private _prevMaintService: PreventiveMaintenanceService, private _router: Router, private _sysAdminService: SystemAdminService, private _functionsService: FunctionsService, private _dialog: MatDialog, private _resourcesService: ResourcesService ) { this.btnSmall = window.innerWidth <= 1530; this.txtBuscador = ''; this.isLoading = true; this.hasError = false; this.errorStr = ''; this.dataSource = new MatTableDataSource(); this.priorityMap = new Map(); } ngOnInit(): void { this.getOrderPriorities(); } async getOrderPriorities() { try { let idUser = localStorage.getItem('idusuario')!; let priorities = await lastValueFrom( this._sysAdminService.getOrderPriorities(idUser, 1) ); if (!priorities.error) { this.priorityMap.clear(); const prioritiesArr = priorities.response?.order_priorities as | PriorityInterface[] | undefined; if (prioritiesArr?.length) { for (const item of prioritiesArr) { const valueKey = `${item.value}`.trim(); const formattedPriority: PriorityInterface = { ...item, value: valueKey, label: `${item.label} (${item.value})`, }; this.priorityMap.set(valueKey, formattedPriority); } } } } catch (error) { console.error('Error loading order priorities', error); } finally { this.getUnprogrammedVisits(); } } async getUnprogrammedVisits() { try { this.isLoading = true; this.hasError = false; this.errorStr = ''; let idUser = localStorage.getItem('idusuario')!; let visits: UnprogrammedVisitsResponse = await lastValueFrom( this._prevMaintService.getUnprogrammedVisits(idUser, 1) ); this.hasError = visits.error; this.errorStr = visits.msg; if (!this.hasError) { let visitsArr: UnprogrammedVisit[] = []; for (const visit of visits.response) { visit.IDVISITA = await this._encService.decrypt(visit.IDVISITA); let equipmentCodeDec = await this._encService.decrypt( visit.EQUIPAMIENTO ); visit.TIPO_EQUIPAMIENTO = `${equipmentCodeDec} - ${visit.TIPO_EQUIPAMIENTO}`; let equipmentIDDec = await this._encService.decrypt( visit.ID_EQUIPAMIENTO ); visit.MODELO_EQUIPAMIENTO = `${visit.MODELO_EQUIPAMIENTO} (${equipmentIDDec})`; if (visit.PRIORIDAD) { const priorityValue = await this.decryptWithFallback( visit.PRIORIDAD ); visit.PRIORIDAD = priorityValue; const priorityInfo = this.priorityMap.get(priorityValue.trim()); if (priorityInfo) { visit.PRIORIDAD_OBJ = priorityInfo; } } const activationKey = (visit.TIPO_ACTIVACION || '').toUpperCase(); visit.TIPO_ACTIVACION_LABEL = this.activationTypeLabels[activationKey] || visit.TIPO_ACTIVACION || 'N/A'; const statusKey = (visit.ESTADO || '').toUpperCase(); visit.ESTADO_LABEL = this.statusLabels[statusKey] || visit.ESTADO || 'N/A'; if (visit.FECREG) { visit.FECREG_FMT = this._functionsService.orderDate(visit.FECREG); if (!visit.FECREG_FMT) { visit.FECREG_FMT = visit.FECREG; } } visitsArr.push(visit); } this.dataSource = new MatTableDataSource(visitsArr); this.dataSource.paginator = this.paginator!; this.dataSource.sort = this.sort!; } this.isLoading = false; } catch (error: any) { if (error.error == undefined) { this.errorStr = 'Ocurrió un error inesperado.'; } else if (error.error.msg == undefined) { this.errorStr = 'Ocurrió un error inesperado.'; } else { this.errorStr = error.error.msg; } this.isLoading = false; this.hasError = true; } } public onResize(): void { this.btnSmall = window.innerWidth <= 1530; } goBack(steps: number) { window.history.go(steps * -1); } applyFilter(event: any, type: string) { let filterValue: string; if (type === 'INP') { filterValue = (event.target as HTMLInputElement).value; } else { this.txtBuscador = event; filterValue = event; } this.dataSource!.filter = filterValue.trim().toLowerCase(); if (this.dataSource?.paginator) { this.dataSource.paginator.firstPage(); } } registerVisit() { this._router.navigate(['sam/GMPR/AOTR/RVTP/register']); } async openVisitDetails(idVisit: string) { try { const idVisitEnc = await this._encService.encrypt(idVisit); this._dialog.open(PreventiveOrderDetailsComponent, { width: '480px', maxWidth: '480px', data: { idOrder: idVisitEnc, }, }); } catch (error) { console.error('Error opening visit details dialog', error); } } startVisitExecution(visit: UnprogrammedVisit) { const visitId = `${visit.IDVISITA ?? ''}`.trim(); if (!visitId) { console.warn('startVisitExecution: missing visit ID', visit); this._resourcesService.openSnackBar('No se pudo identificar la visita.'); return; } const statusKey = (visit.ESTADO || '').toUpperCase(); const allowedStatuses = ['A', 'VA']; if (statusKey && !allowedStatuses.includes(statusKey)) { this._resourcesService.openSnackBar( 'La visita debe estar aprobada para iniciar la ejecución.' ); return; } const dialogRef = this._dialog.open(AlertComponent, { width: '420px', maxWidth: '420px', disableClose: true, data: { title: 'Confirmación', icon: 'warning', description: `¿Está seguro de iniciar la ejecución de la visita #${visitId}?`, }, }); dialogRef.afterClosed().subscribe((res) => { if (res === true) { this.verifyVisitStatus(visitId); } }); } private async verifyVisitStatus(idVisit: string) { try { this._resourcesService.openSnackBar('Verificando visita...'); const idVisitEnc = await this._encService.encrypt(idVisit); const idUser = localStorage.getItem('idusuario')!; const attendanceResp = await lastValueFrom( this._prevMaintService.getVisitAttendance(idVisitEnc, idUser, 1) ); if (attendanceResp?.error) { this._resourcesService.openSnackBar( attendanceResp.msg || 'No fue posible obtener la asistencia.' ); return; } const attendanceList = Array.isArray(attendanceResp?.response) ? attendanceResp.response : []; if (!attendanceList.length) { this._resourcesService.openSnackBar( 'Ninguno de los operarios involucrados ha respondido a la solicitud.' ); return; } const staffResp = await lastValueFrom( this._prevMaintService.getVisitStaff(idVisitEnc, idUser, 1) ); if (staffResp?.error) { this._resourcesService.openSnackBar( staffResp.msg || 'No fue posible obtener el personal asignado.' ); return; } const staffList = Array.isArray(staffResp?.response) ? staffResp.response : []; const requiredUsers = staffList.reduce((acc: number, item: any) => { const amount = Number(item?.CANT ?? item?.cant ?? 0); return acc + (isNaN(amount) ? 0 : amount); }, 0); const startedUsers = attendanceList.reduce((acc: number, item: any) => { const response = (item?.RESPUESTA || item?.respuesta || '').toString(); return acc + (response.toUpperCase() === 'A' ? 1 : 0); }, 0); if (requiredUsers > startedUsers) { this._resourcesService.openSnackBar( 'Algunos operarios involucrados no han respondido a la solicitud.' ); return; } await this.startVisit(idVisit); } catch (error: any) { console.error('verifyVisitStatus error', error); this._resourcesService.openSnackBar( error?.error?.msg || 'No fue posible verificar la visita.' ); } } private async startVisit(idVisit: string) { try { const idUser = localStorage.getItem('idusuario')!; const idVisitEnc = await this._encService.encrypt(idVisit); const formData = new FormData(); formData.append('id_user', idUser); formData.append('linea', '1'); formData.append('id_visit', idVisitEnc); const response = await lastValueFrom( this._prevMaintService.startVisit(formData) ); if (response?.error) { this._resourcesService.openSnackBar( response.msg || 'Ocurrió un error al iniciar la ejecución.' ); } else { this._resourcesService.openSnackBar( response?.msg || 'La ejecución de la visita se inició correctamente.' ); this.getUnprogrammedVisits(); } } catch (error: any) { console.error('startVisit error', error); const message = error?.error?.msg || 'Ocurrió un error inesperado al iniciar la visita.'; this._resourcesService.openSnackBar(message); this.getUnprogrammedVisits(); } } private async decryptWithFallback( value: string | null | undefined ): Promise { if (!value) { return ''; } try { const decrypted = await this._encService.decrypt(value); return decrypted.trim(); } catch (error) { return `${value}`.trim(); } } openCloseVisitDialog(visit: UnprogrammedVisit) { const visitId = `${visit.IDVISITA ?? ''}`.trim(); if (!visitId) { this._resourcesService.openSnackBar('No se pudo identificar la visita.'); return; } const dialogRef = this._dialog.open(CommnetsDialogComponent, { width: '480px', maxWidth: '480px', disableClose: true, data: { idOrder: visitId, status: 'Cerrar', }, }); dialogRef.afterClosed().subscribe((res) => { if (res != undefined && res != null && res != '') { if (res.length < 15) { this._resourcesService.openSnackBar( 'Los comentarios deben tener al menos 15 caracteres.' ); return; } this.closeVisit(visitId, res); } }); } openFinalCloseDialog(visit: UnprogrammedVisit) { const visitId = `${visit.IDVISITA ?? ''}`.trim(); if (!visitId) { this._resourcesService.openSnackBar('No se pudo identificar la visita.'); return; } // Primera confirmación const confirmDialogRef = this._dialog.open(AlertComponent, { width: '420px', maxWidth: '420px', disableClose: true, data: { title: 'Confirmación', icon: 'warning', description: `¿Está seguro de realizar el cierre final de la visita #${visitId}?`, }, }); confirmDialogRef.afterClosed().subscribe((res) => { if (res === true) { this.finalCloseVisit(visitId); } }); } private async closeVisit(idVisit: string, comment: string) { try { const idUser = localStorage.getItem('idusuario')!; const idVisitEnc = await this._encService.encrypt(idVisit); const formData = new FormData(); formData.append('id_user', idUser); formData.append('linea', '1'); formData.append('id_visit', idVisitEnc); formData.append('comment', comment); const response = await lastValueFrom( this._prevMaintService.registerOperatorClosingComment(formData) ); if (response?.error) { this._resourcesService.openSnackBar( response.msg || 'Ocurrió un error al cerrar la visita.' ); } else { this._resourcesService.openSnackBar( response?.msg || 'La visita se cerró correctamente.' ); } this.getUnprogrammedVisits(); } catch (error: any) { if (error.error == undefined) { this._resourcesService.openSnackBar('Ocurrió un error inesperado.'); } else if (error.error.msg == undefined) { this._resourcesService.openSnackBar('Ocurrió un error inesperado.'); } else { this._resourcesService.openSnackBar(error.error.msg); } this.getUnprogrammedVisits(); } } private async finalCloseVisit(idVisit: string) { try { //Se recupera encriptado const idUser = localStorage.getItem('idusuario')!; const idVisitEnc = await this._encService.encrypt(idVisit); const formData = new FormData(); formData.append('id_user', idUser); formData.append('linea', '1'); formData.append('id_visit', idVisitEnc); formData.append('status', 'CE'); const response = await lastValueFrom( this._prevMaintService.updateVisitStatus(formData) ); if (response?.error) { this._resourcesService.openSnackBar( response.msg || 'Ocurrió un error al realizar el cierre final.' ); } else { this._resourcesService.openSnackBar( response?.msg || 'El cierre final se realizó correctamente.' ); } this.getUnprogrammedVisits(); } catch (error: any) { if (error.error == undefined) { this._resourcesService.openSnackBar('Ocurrió un error inesperado.'); } else if (error.error.msg == undefined) { this._resourcesService.openSnackBar('Ocurrió un error inesperado.'); } else { this._resourcesService.openSnackBar(error.error.msg); } this.getUnprogrammedVisits(); } } getRowIndex(index: number): number { const pageIndex = this.paginator?.pageIndex ?? 0; const pageSize = this.paginator?.pageSize ?? 10; return pageIndex * pageSize + index + 1; } }