Parcourir la source

Finalización de la función de producción de informes

Jose Brito il y a 2 ans
Parent
commit
20c9445c12

+ 140 - 1
sistema-mantenimiento-front/src/app/components/corrective-maintenance/reports-production/reports-production.component.html

@@ -1 +1,140 @@
-<p>reports-production works!</p>
+<main class="main-container animated fadeIn prevent-select" (window:resize)="onResize()">
+
+  <header id="navigation" class="btn-navigate mb-8">
+    <div class="prev-page prevent-select indigo_primary_background mat-elevation-z8" [routerLink]="['/sam/GMCO']" matRipple>
+      <mat-icon style="color: white;">arrow_back</mat-icon>
+      <div class="page-name ml-4">Gestión de mantenimiento correctivo</div>
+    </div>
+  </header>
+  
+  <mat-card class="override-card override-elevation-z8">
+    <section class="override-section">
+      <nav class="override-nav ph-10">
+        <mat-card-title class="mat-card-title centre">Producción de informes</mat-card-title>
+        <div class="form-row">
+          <div class="form-cell C02">
+            <mat-form-field class="w-100" appearance="outline">
+              <mat-label>Acción</mat-label>
+              <mat-select #action [formControl]="actionControl">
+                <mat-option value="register">Registro</mat-option>
+                <mat-option value="search">Búsqueda</mat-option>
+              </mat-select>
+            </mat-form-field>
+          </div>
+          <div class="form-cell C03">
+            <mat-form-field class="w-100" appearance="outline">
+              <mat-label>Tipo de informe</mat-label>
+              <mat-select [formControl]="reportTypeControl">
+                <mat-option value="TODAS">Todas las órdenes de trabajo</mat-option>
+                <mat-option value="MANUA">Órdenes de trabajo manuales</mat-option>
+                <mat-option value="AUTOM">Órdenes de trabajo automáticas</mat-option>
+                <mat-option value="ESTAD">Órdenes de trabajo por estado</mat-option>
+              </mat-select>
+            </mat-form-field>
+          </div>
+          <div class="form-cell C02">
+            <mat-form-field class="w-100" appearance="outline">
+              <mat-label>Fecha de inicio</mat-label>
+              <input matInput [matDatepicker]="startDatePicker" [formControl]="startDateControl" [max]="endDate">
+              <mat-datepicker-toggle matIconSuffix [for]="startDatePicker">
+                <mat-icon matDatepickerToggleIcon>arrow_drop_down</mat-icon>
+              </mat-datepicker-toggle>
+              <mat-datepicker #startDatePicker></mat-datepicker>
+            </mat-form-field>
+          </div>
+          <div class="form-cell C02">
+            <mat-form-field class="w-100" appearance="outline">
+              <mat-label>Fecha final</mat-label>
+              <input matInput [matDatepicker]="endDatePicker" [formControl]="endDateControl" [min]="startDate">
+              <mat-datepicker-toggle matIconSuffix [for]="endDatePicker">
+                <mat-icon matDatepickerToggleIcon>arrow_drop_down</mat-icon>
+              </mat-datepicker-toggle>
+              <mat-datepicker #endDatePicker></mat-datepicker>
+            </mat-form-field>
+          </div>
+          <div class="form-cell C03">
+            <mat-form-field class="w-100" appearance="outline">
+              <mat-label>Estado de la orden</mat-label>
+              <mat-select [formControl]="orderStateControl">
+                <mat-option value="PE">Pendiente</mat-option>
+                <mat-option value="VA">Validado</mat-option>
+                <mat-option value="RE">Rechazado</mat-option>
+                <mat-option value="EP">En progreso</mat-option>
+                <mat-option value="CE">Cerrado</mat-option>
+                <mat-option value="CP">Cerrado pendiente</mat-option>
+                <mat-option value="CA">Cancelado</mat-option>
+                <mat-option value="EL">Eliminado</mat-option>
+              </mat-select>
+            </mat-form-field>
+          </div>
+        </div>
+        <div class="form-row">
+          <button mat-raised-button class="override_no_shadow mr-10" color="warn" (click)="clearFilters()" 
+          [disabled]="reportTypeControl.value == '' && startDateControl.value == null && endDateControl.value == null && orderStateControl.value == ''">
+            <mat-icon>close</mat-icon> Limpiar
+          </button>
+          <button mat-raised-button class="override_no_shadow mr-10" color="primary" (click)="executeAction()"
+          [disabled]="(reportTypeControl.value == 'ESTAD' && orderStateControl.value == '') || 
+          (reportTypeControl.value == '' && startDateControl.value == null && endDateControl.value == null)">
+            <mat-icon>{{ action.value == 'search' ? 'search' : 'note_add' }}</mat-icon>
+            <span>{{ action.value == 'search' ? 'Buscar' : 'Generar informe' }}</span>
+          </button>
+          <a class="hidden" id="download"></a>
+        </div>
+      </nav>
+
+      <div class="is-loading animated fadeIn fast" *ngIf="isLoading">
+        <mat-spinner align="center"></mat-spinner>
+        <h3>Cargando datos ...</h3>
+      </div>
+
+      <div class="is-loading animated fadeIn fast" *ngIf="!isLoading && hasError">
+        <mat-icon style="transform: scale(4.5);margin: 45px 0;" class="red_primary_font">error</mat-icon>
+        <h3>{{ errorStr }}</h3>
+      </div>
+
+      <div class="override-table animated fadeIn" [ngClass]="{ hidden: isLoading || hasError }">
+        <table mat-table [dataSource]="dataSource!" matSort 
+        [style.display]="!isLoading && !hasError ? 'revert' : 'none'">
+          <ng-container matColumnDef="ID">
+            <th mat-header-cell *matHeaderCellDef mat-sort-header>#</th>
+            <td mat-cell *matCellDef="let row">{{ row.ID_INFORME }}</td>
+          </ng-container>
+          
+          <ng-container matColumnDef="NOMBRE">
+            <th mat-header-cell *matHeaderCellDef mat-sort-header>Nombre del informe</th>
+            <td mat-cell *matCellDef="let row">{{ row.DOCUMENTO }}</td>
+          </ng-container>
+          
+          <ng-container matColumnDef="FECHA">
+            <th mat-header-cell *matHeaderCellDef mat-sort-header>Fecha de generación</th>
+            <td mat-cell *matCellDef="let row">{{ row.FECREG }}</td>
+          </ng-container>
+          
+          <ng-container matColumnDef="ACCIONES">
+            <th mat-header-cell *matHeaderCellDef mat-sort-header>Acciones</th>
+            <td mat-cell *matCellDef="let row">
+              <button mat-mini-fab class="override_no_shadow amber_primary_background white_font" (click)="downloadReport(row.DOCUMENTO)">
+                <mat-icon>download</mat-icon>
+              </button>
+            </td>
+          </ng-container>
+
+          <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+          <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+
+          <tr class="mat-row" *matNoDataRow>
+            <td class="mat-cell p-80 centre" colspan="100%" *ngIf="!hasSearched">
+              <b>Seleccione algún filtro para comenzar.</b>
+            </td>
+            <td class="mat-cell p-80 centre" colspan="100%" *ngIf="hasSearched">
+              <object data="assets/img/empty_data.svg" width="300"></object>
+              <h2>Sin datos</h2>
+            </td>
+          </tr>
+        </table>
+      </div>
+    </section>
+    <mat-paginator [pageSizeOptions]="[10, 50, 100]" class="override-paginator"></mat-paginator>
+  </mat-card>
+</main>

+ 251 - 2
sistema-mantenimiento-front/src/app/components/corrective-maintenance/reports-production/reports-production.component.ts

@@ -1,10 +1,259 @@
-import { Component } from '@angular/core';
+import { DOCUMENT } from '@angular/common';
+import { Component, Inject, OnInit, ViewChild } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { MatPaginator } from '@angular/material/paginator';
+import { MatSort } from '@angular/material/sort';
+import { MatTableDataSource } from '@angular/material/table';
+import { lastValueFrom } from 'rxjs';
+import { ReportsListItem, ReportsListResponse } from 'src/app/interfaces/corrective-maintenance.interface';
+import { CorrectiveMaintenanceService } from 'src/app/services/corrective-maintenance.service';
+import { GdelService } from 'src/app/services/document-management/gdel.service';
+import { EncService } from 'src/app/services/enc/enc.service';
+import { FunctionsService } from 'src/app/services/functions.service';
+import { ResourcesService } from 'src/app/services/resources/resources.service';
 
 @Component({
   selector: 'app-reports-production',
   templateUrl: './reports-production.component.html',
   styleUrls: ['./reports-production.component.css']
 })
-export class ReportsProductionComponent {
+export class ReportsProductionComponent implements OnInit {
+  public btnSmall: boolean = false;
 
+  isLoading: boolean;
+  hasError: boolean;
+  errorStr: string;
+  hasSearched: boolean;
+
+  dataSource: MatTableDataSource<any>;
+  displayedColumns = ['ID', 'NOMBRE', 'FECHA', 'ACCIONES'];
+
+  startDate: Date | null;
+  endDate: Date | null;
+
+  actionControl: FormControl;
+  reportTypeControl: FormControl;
+  startDateControl: FormControl;
+  endDateControl: FormControl;
+  orderStateControl: FormControl;
+
+  @ViewChild(MatPaginator) paginator?: MatPaginator;
+  @ViewChild(MatSort) sort?: MatSort;
+
+  constructor(
+    @Inject(DOCUMENT) private _document: Document,
+    private _resourcesService: ResourcesService,
+    private _correctiveMaintenanceService: CorrectiveMaintenanceService,
+    private _gdelService: GdelService,
+    private _encService: EncService,
+    private _functionsService: FunctionsService,
+  ) {
+    this.btnSmall = window.innerWidth <= 1405;
+    
+    this.isLoading = false;
+    this.hasError = false;
+    this.errorStr = '';
+    this.hasSearched = false;
+
+    this.dataSource = new MatTableDataSource();
+
+    this.startDate = null;
+    this.endDate = null;
+
+    this.actionControl = new FormControl('register');
+    this.reportTypeControl = new FormControl('');
+    this.startDateControl = new FormControl({value: this.startDate, disabled: true});
+    this.endDateControl = new FormControl({value: this.endDate, disabled: true});
+    this.orderStateControl = new FormControl({value: '', disabled: true});
+  }
+  
+  ngOnInit(): void {
+    this.reportTypeControl.valueChanges.subscribe(value => {
+      if(value == 'ESTAD'){
+        this.orderStateControl.enable();
+      }else{
+        this.orderStateControl.disable();
+      }
+
+      this.startDateControl.enable();
+      this.endDateControl.enable();
+    });
+
+    this.startDateControl.valueChanges.subscribe((startDate: Date) => {
+      this.startDate = startDate;
+    });
+
+    this.endDateControl.valueChanges.subscribe((endDate: Date) => {
+      this.endDate = endDate;
+    });
+  }
+
+  public onResize():void {
+    this.btnSmall = window.innerWidth <= 1405;
+  }
+
+  clearFilters(){
+    this.startDate = null;
+    this.endDate = null;
+
+    this.reportTypeControl.setValue('');
+    this.startDateControl.setValue(null);
+    this.endDateControl.setValue(null);
+    this.orderStateControl.setValue('');
+
+    this.startDateControl.disable();
+    this.endDateControl.disable();
+    this.orderStateControl.disable();
+
+    this.dataSource = new MatTableDataSource();
+    this.dataSource.paginator = this.paginator!;
+    this.dataSource.sort = this.sort!;
+  }
+
+  executeAction(){
+    let action = this.actionControl.value;
+    if(action == 'register'){
+      this.generateReport();
+    }else if(action == 'search'){
+      this.searchReports();
+    }
+  }
+
+  private async generateReport(){
+    try{
+      this._resourcesService.openSnackBar('Generando informe...');
+
+      let idUser = localStorage.getItem('idusuario')!;
+      let formData = new FormData();
+
+      formData.append('id_user', idUser);
+      formData.append('linea', '1');
+      formData.append('report_type', this.reportTypeControl.value);
+
+      if(this.startDate != null){
+        let startDateStr = `${this.startDate.getFullYear()}-${this.startDate.getMonth() + 1}-${this.startDate.getDate()}`;
+        formData.append('start_date', startDateStr);
+      }
+
+      if(this.endDate != null){
+        let endDateStr = `${this.endDate.getFullYear()}-${this.endDate.getMonth() + 1}-${this.endDate.getDate()}`;
+        formData.append('end_date', endDateStr);
+      }
+
+      let orderState = this.orderStateControl.value;
+      if(orderState != null && orderState != undefined && orderState != ''){
+        formData.append('order_state', orderState);
+      }
+
+      let response = await lastValueFrom(this._correctiveMaintenanceService.generateReport(formData));
+      let idFile = await this._encService.decrypt(response.response.report);
+      let downloadToken = await lastValueFrom(this._gdelService.getDownloadToken(response.response.report, idUser, 1));
+      let download = this._document.getElementById(`download`) as HTMLAnchorElement;
+  
+      download.href = `http://git.ittec.mx/sam/public/api/download-file/${downloadToken.response.TOKEN}/${idUser}/1`;
+      download.download = idFile;
+      download.click();
+
+      this._resourcesService.openSnackBar('Descarga realizada.');
+    }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);
+      }
+    }
+  }
+
+  private async searchReports(){
+    try{
+      this.hasSearched = true;
+      this.isLoading = true;
+      this.hasError = false,
+      this.errorStr = '';
+
+      let idUser = localStorage.getItem('idusuario')!;
+      let reportType = '-';
+      let startDate = '-';
+      let endDate = '-';
+
+      if(this.reportTypeControl.value != null && this.reportTypeControl.value != undefined && this.reportTypeControl.value != ''){
+        reportType = this.reportTypeControl.value;
+      }
+
+      if(this.startDate != null){
+        let startYear = this.startDate.getFullYear();
+        let startMonth = this.startDate.getMonth() + 1 < 10 ? `0${this.startDate.getMonth() + 1}` : `${this.startDate.getMonth() + 1}`;
+        let startDay = this.startDate.getDate() < 10 ? `0${this.startDate.getDate()}` : `${this.startDate.getDate()}`;
+
+        startDate = `${startYear}-${startMonth}-${startDay}`;
+      }
+
+      if(this.endDate != null){
+        let endYear = this.endDate.getFullYear();
+        let endMonth = this.endDate.getMonth() + 1 < 10 ? `0${this.endDate.getMonth() + 1}` : `${this.endDate.getMonth() + 1}`;
+        let endDay = this.endDate.getDate() < 10 ? `0${this.endDate.getDate()}` : `${this.endDate.getDate()}`;
+
+        endDate = `${endYear}-${endMonth}-${endDay}`;
+      }
+
+      let reports: ReportsListResponse = await lastValueFrom(this._correctiveMaintenanceService.getReports(reportType, startDate, endDate, idUser, 1));
+
+      this.hasError = reports.error;
+      this.errorStr = reports.msg;
+
+      if(!this.hasError){
+        let reportsArr: ReportsListItem[] = [];
+        for(const report of reports.response){
+          report.ID_INFORME = await this._encService.decrypt(report.ID_INFORME);
+          report.DOCUMENTO = await this._encService.decrypt(report.DOCUMENTO);
+          report.FECREG = this._functionsService.orderDate(report.FECREG);
+
+          reportsArr.push(report);
+        }
+
+        this.dataSource = new MatTableDataSource(reportsArr);
+        this.dataSource.paginator = this.paginator!;
+        this.dataSource.sort = this.sort!;
+      }
+
+      this.isLoading = false;
+    }catch(error: any){
+      console.log(error);
+      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.hasError = true;
+      this.isLoading = false;
+    }
+  }
+
+  async downloadReport(document: string){
+    try{
+      this._resourcesService.openSnackBar('Descargando informe...');
+
+      let idUser = localStorage.getItem('idusuario')!;
+      let documentEnc = await this._encService.encrypt(document);
+      let downloadToken = await lastValueFrom(this._gdelService.getDownloadToken(documentEnc, idUser, 1));
+      let download = this._document.getElementById(`download`) as HTMLAnchorElement;
+  
+      download.href = `http://git.ittec.mx/sam/public/api/download-file/${downloadToken.response.TOKEN}/${idUser}/1`;
+      download.download = documentEnc;
+      download.click();
+    }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);
+      }
+    }
+  }
 }

+ 14 - 0
sistema-mantenimiento-front/src/app/interfaces/corrective-maintenance.interface.ts

@@ -130,4 +130,18 @@ export interface WorkOrderStatusHistoryListItem{
   FECHA: string;
   ESTADO: string;
   USUARIO: string;
+}
+
+export interface ReportsListResponse{
+  error: boolean;
+  msg: string;
+  response: ReportsListItem[];
+}
+
+export interface ReportsListItem{
+  ID_INFORME: string;
+  TIPO_INFORME: string;
+  DOCUMENTO: string;
+  USUREG: string;
+  FECREG: string;
 }

+ 8 - 0
sistema-mantenimiento-front/src/app/services/corrective-maintenance.service.ts

@@ -42,6 +42,10 @@ export class CorrectiveMaintenanceService {
     return this.getQuery(`corrective-maintenance/get-work-order-status-history/${idOrder}/${idUser}/${line}`).pipe(map((data: any) => data))
   }
 
+  getReports(type: string, startDate: string, endDate: string, idUser: string, line: number){
+    return this.getQuery(`corrective-maintenance/get-reports/${type}/${startDate}/${endDate}/${idUser}/${line}`).pipe(map((data: any) => data))
+  }
+
   registerWorkOrder(body: any){
     return this.postQuery("corrective-maintenance/register-work-order", body).pipe(map((data: any) => data))
   }
@@ -89,6 +93,10 @@ export class CorrectiveMaintenanceService {
   unblockRegister(body: any){
     return this.postQuery("corrective-maintenance/unblock-register", body).pipe(map((data: any) => data))
   }
+
+  generateReport(body: any){
+    return this.postQuery("corrective-maintenance/generate-report", body).pipe(map((data: any) => data))
+  }
   
   getQuery(query: string, tk?: string){
     const URL = `${apiTemp}${query}`;