2 İşlemeler e44e95d2ef ... 3e43997286

Yazar SHA1 Mesaj Tarih
  EmilianoOrtiz 3e43997286 boton para registro de cierre final con condicion para las visitas con estado CP ya se consume el servicio y se completa el cierre. 4 gün önce
  EmilianoOrtiz ca5fe5d6be agregue el componente de comentarios para iniciar el proceso de cierre con los comentarios de los operarios, se consume el endpoint registerOperatorClosingComment pero no se ha prbado 6 gün önce

+ 29 - 6
src/app/components/preventive-maintenance/unprogrammed-visits/comments-dialog.html

@@ -1,14 +1,37 @@
-<h1 mat-dialog-title class="prevent-select">Comentarios</h1>
+<h1 mat-dialog-title class="prevent-select">
+  @if (data?.action && data?.idVisit) {
+    {{ data.action }} visita #{{ data.idVisit }}
+  } @else {
+    Comentarios
+  }
+</h1>
 <div mat-dialog-content class="prevent-select">
+  <p>Ingrese los comentarios para continuar con la acción solicitada.</p>
   <mat-form-field class="mt-8 w-100" appearance="outline">
     <mat-label>Comentarios</mat-label>
-    <textarea matInput placeholder="Ingrese sus comentarios aquí..." #commentsBox required></textarea>
-    @if (commentsBox.value.length < 35) {
-      <mat-hint>Debe ingresar por lo menos 35 caracteres en los comentarios.</mat-hint>
+    <textarea
+      matInput
+      rows="5"
+      style="resize: none;"
+      [formControl]="formControl"
+      (input)="formControl.markAsTouched()"
+      placeholder="Ingrese sus comentarios aquí..."
+    ></textarea>
+    @if (formControl.hasError('required')) {
+      <mat-error>Este campo es requerido.</mat-error>
+    }
+    @if (formControl.hasError('minlength')) {
+      <mat-error>La longitud mínima de este campo es de 35 caracteres.</mat-error>
     }
   </mat-form-field>
 </div>
 <div mat-dialog-actions align="end">
-  <button mat-button mat-dialog-close>Cerrar</button>
-  <button mat-button [mat-dialog-close]="commentsBox.value" [disabled]="commentsBox.value.length < 35">Continuar</button>
+  <button mat-button mat-dialog-close>Cancelar</button>
+  <button
+    mat-button
+    [mat-dialog-close]="formControl.value"
+    [disabled]="formControl.invalid"
+  >
+    Continuar
+  </button>
 </div>

+ 10 - 0
src/app/components/preventive-maintenance/unprogrammed-visits/unprogrammed-visits.component.html

@@ -186,6 +186,16 @@
                   <mat-icon>play_arrow</mat-icon>
                   <span>Iniciar ejecución</span>
                 </button>
+                } @if (row.ESTADO === 'EP') {
+                <button mat-menu-item (click)="openCloseVisitDialog(row)">
+                  <mat-icon>done</mat-icon>
+                  <span>Cerrar visita</span>
+                </button>
+                } @if (row.ESTADO === 'CP') {
+                <button mat-menu-item (click)="openFinalCloseDialog(row)">
+                  <mat-icon>check_circle</mat-icon>
+                  <span>Cierre final</span>
+                </button>
                 }
               </mat-menu>
             </td>

+ 133 - 2
src/app/components/preventive-maintenance/unprogrammed-visits/unprogrammed-visits.component.ts

@@ -17,6 +17,7 @@ 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',
@@ -335,10 +336,10 @@ export class UnprogrammedVisitsComponent implements OnInit {
       }
 
       await this.startVisit(idVisit);
-    } catch (error) {
+    } catch (error: any) {
       console.error('verifyVisitStatus error', error);
       this._resourcesService.openSnackBar(
-        'No fue posible verificar la visita.'
+        error?.error?.msg || 'No fue posible verificar la visita.'
       );
     }
   }
@@ -392,6 +393,136 @@ export class UnprogrammedVisitsComponent implements OnInit {
     }
   }
 
+  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;

+ 6 - 0
src/app/services/preventive-maintenance.service.ts

@@ -240,6 +240,12 @@ export class PreventiveMaintenanceService {
     );
   }
 
+  registerOperatorClosingComment(body: any) {
+    return this.postQuery('register-operator-closing-comment', body).pipe(
+      map((data: any) => data)
+    );
+  }
+
   updateOrderStatus(body: any) {
     return this.postQuery('update-order-status', body).pipe(
       map((data: any) => data)