Jelajahi Sumber

Avances project

Jose Brito 2 tahun lalu
induk
melakukan
92fadfb7a8

+ 1 - 1
sistema-mantenimiento-front/src/app/components/preventive-maintenance/extract-maintenance-plan/extract-maintenance-plan.component.html

@@ -95,7 +95,7 @@
                 <mat-icon>picture_as_pdf</mat-icon>
                 <span>Extraer PDF</span>
               </button>
-              <button mat-menu-item>
+              <button mat-menu-item (click)="getFileToMSProject(row.IDORDEN)">
                 <mat-icon>exit_to_app</mat-icon>
                 <span>Extraer MS Project</span>
               </button>

+ 3 - 1
sistema-mantenimiento-front/src/app/components/preventive-maintenance/extract-maintenance-plan/extract-maintenance-plan.component.ts

@@ -219,7 +219,9 @@ export class ExtractMaintenancePlanComponent implements OnInit {
     try{
       let idUser = localStorage.getItem('idusuario');
       let shortEnc = await lastValueFrom(this._encService.shortEncrypt(idUser!));
-      console.log(shortEnc);
+      let idOrderEnc = await this._encService.encrypt(`${idOrder}`);
+      let idOrderShort = await lastValueFrom(this._encService.shortEncrypt(idOrderEnc));
+      console.log(idOrderShort);
     }catch(error: any){
       if(error.error == undefined){
         this.openSnackBar('Ocurrió un error inesperado.');

+ 28 - 9
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/budget-analysis/budget-analysis.component.html

@@ -24,16 +24,33 @@
 
       <div class="form-order-container" *ngIf="!isLoading && !hasError">
         <div class="analysis-column">
-          <div class="analysis-item" *ngFor="let team of teamsConf">
+          <div class="analysis-item">
+            <div class="analysis-item-header mb-8">
+              Instrucciones del trabajo:
+            </div>
+            <div class="analysis-item-content">
+              <div class="content-row" *ngFor="let instruction of instructions; let i = index">
+                <span class="mr-8 mb-20">{{ i + 1 }}.- {{ instruction.INSTRUCCION }}</span>
+                <span class="mr-8 mb-20">-</span>
+                <mat-form-field appearance="outline" style="width: 240px;">
+                  <mat-label>Costo de la actividad</mat-label>
+                  <input matInput type="number" class="right-align" [disabled]="instruction.ISFROMFILE" [id]="instruction.ID" [(ngModel)]="instructionsCosts[i]" 
+                  (input)="updateActivityCost(instruction.ID, ins.value)" #ins>
+                  <span matTextPrefix>$&nbsp;</span>
+                </mat-form-field>
+              </div>
+            </div>
+          </div>
+          <div class="analysis-item" *ngFor="let team of teamsConf; let i = index">
             <div class="analysis-item-header mb-8">
               {{ team.NOMB }} - <span style="font-weight: 500;">{{ team.ESP }}</span>. Empleados requeridos: {{ team.CANT }}
             </div>
             <div class="analysis-item-content">
-              <div class="content-row" *ngFor="let conf of team.CONF;let i = index">
-                <span class="mr-8 mb-20">{{ i + 1 }}.-</span>
+              <div class="content-row" *ngFor="let conf of team.CONF;let j = index">
+                <span class="mr-8 mb-20">{{ j + 1 }}.-</span>
                 <mat-form-field appearance="outline" style="width: 420px;">
                   <mat-label>Nombre del empleado</mat-label>
-                  <mat-select #worker (valueChange)="checkSelected(worker.value, conf)">
+                  <mat-select #worker (valueChange)="checkSelected(worker.value, conf)" [(ngModel)]="teamsModels[i][j]">
                     <mat-optgroup label="Empleados">
                       <mat-option *ngFor="let worker of workersArr" [value]="worker.ID" [disabled]="shouldDisabled(worker.ID)">
                         {{ worker.NOMB }} ({{ worker.ID }})
@@ -50,13 +67,13 @@
                 <span class="mr-8 mb-20 ml-8">-</span>
                 <mat-form-field appearance="outline" style="width: 360px;">
                   <mat-label>Costo por hora</mat-label>
-                  <input matInput type="number" class="right-align" [id]="'cost-' + conf">
+                  <input matInput type="number" class="right-align" [id]="'cost-' + conf" [(ngModel)]="teamsCostsModels[i][j]">
                   <span matTextPrefix>$&nbsp;</span>
                 </mat-form-field>
                 <span class="mr-8 mb-20 ml-8">-</span>
                 <mat-form-field appearance="outline" style="width: 240px;">
                   <mat-label>Horas de contrato</mat-label>
-                  <input matInput type="number" [id]="'hour-' + conf">
+                  <input matInput type="number" [id]="'hour-' + conf" [(ngModel)]="teamsHoursModels[i][j]">
                 </mat-form-field>
               </div>
             </div>
@@ -71,7 +88,8 @@
                 <span class="mr-8 mb-20 ml-8">-</span>
                 <mat-form-field appearance="outline" style="width: 240px;">
                   <mat-label>Precio unitario</mat-label>
-                  <input matInput type="number" class="right-align" [id]="'tool-cost-' + tool.ID" #precUnit (input)="updateTotalCost(tool.ID, tool.TYPE, precUnit.value)">
+                  <input matInput type="number" class="right-align" [id]="'tool-cost-' + tool.ID" #precUnit [(ngModel)]="toolsUnitPrices[i]" 
+                  (input)="updateTotalCost(tool.ID, tool.TYPE, precUnit.value)">
                   <span matTextPrefix>$&nbsp;</span>
                 </mat-form-field>
                 <span class="mr-8 mb-20 ml-8">-</span>
@@ -86,10 +104,11 @@
             <div class="analysis-item-content" *ngIf="spareParts.length > 0">
               <div class="content-row" *ngFor="let part of spareParts; let i = index">
                 <span class="mr-8 mb-20">{{ i + 1 }}.- {{ part.NOM }}, {{ part.REQ }} {{ part.UNIT }}(s) requerida(s)</span>
-                <span class="mr-8 mb-20 ml-8">-</span>
+                <span class="mr-8 mb-20">-</span>
                 <mat-form-field appearance="outline" style="width: 240px;">
                   <mat-label>Precio unitario</mat-label>
-                  <input matInput type="number" class="right-align" [id]="'tool-cost-' + part.ID" #precUnit (input)="updateTotalCost(part.ID, part.TYPE, precUnit.value)">
+                  <input matInput type="number" class="right-align" [id]="'tool-cost-' + part.ID" #precUnit [(ngModel)]="sparePartsUnitPrices[i]" 
+                  (input)="updateTotalCost(part.ID, part.TYPE, precUnit.value)">
                   <span matTextPrefix>$&nbsp;</span>
                 </mat-form-field>
                 <span class="mr-8 mb-20 ml-8">-</span>

+ 262 - 84
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/budget-analysis/budget-analysis.component.ts

@@ -9,6 +9,7 @@ import { PreventiveMaintenanceService } from 'src/app/services/preventive-mainte
 import { OrderDetailsComponent } from '../order-details/order-details.component';
 import { DOCUMENT } from '@angular/common';
 import { FormControl } from '@angular/forms';
+import { Instruction } from '../new-work-order/new-work-order.component';
 
 interface TeamsConfig{
   ID: string;
@@ -129,6 +130,14 @@ export class BudgetAnalysisComponent implements OnInit {
   spareParts: ResourcesConfig[];
   toolsArr: ToolInfo[];
   sparePartsArr: ToolInfo[];
+  instructions: Instruction[];
+
+  teamsModels: Array<Array<string>>;
+  teamsCostsModels: Array<Array<number>>;
+  teamsHoursModels: Array<Array<number>>;
+  toolsUnitPrices: Array<number>;
+  sparePartsUnitPrices: Array<number>;
+  instructionsCosts: Array<number>;
 
   constructor(
     @Inject(DOCUMENT) private _document: Document,
@@ -152,6 +161,13 @@ export class BudgetAnalysisComponent implements OnInit {
     this.spareParts = [];
     this.toolsArr = TOOLS_TMP;
     this.sparePartsArr = SPARE_PARTS_TMP;
+    this.instructions = [];
+    this.teamsModels = [];
+    this.teamsCostsModels = [];
+    this.teamsHoursModels = [];
+    this.toolsUnitPrices = [];
+    this.sparePartsUnitPrices = [];
+    this.instructionsCosts = [];
   }
 
   ngOnInit(): void {
@@ -193,9 +209,13 @@ export class BudgetAnalysisComponent implements OnInit {
 
       if(!this.hasError){
         this.workOrder = order.response;
+        
         this.teamsConf = this.getTeams(this.workOrder.PERSONAL, this.workOrder.OPERARIOS);
         this.tools = this.getResources(this.workOrder.RECURSOS, 'T');
         this.spareParts = this.getResources(this.workOrder.RECURSOS, 'S');
+        this.instructions = JSON.parse(this.workOrder.INSTRUCCIONES);
+
+        this.initAnalysis(this.workOrder.ANALISIS);
       }
       
       this.isLoading = false;
@@ -213,6 +233,135 @@ export class BudgetAnalysisComponent implements OnInit {
     }
   }
 
+  initAnalysis(analysisStr: string | null){
+    if(analysisStr != null){
+      let analysisObj = JSON.parse(analysisStr);
+      let teamsConf = analysisObj.teamsConf;
+      let teams = Object.keys(teamsConf);
+      let teamsModels: Array<Array<string>> = [];
+      let teamsCostsModels: Array<Array<number>> = [];
+      let teamsHoursModels: Array<Array<number>> = [];
+  
+      teams.forEach(key => {
+        let team = teamsConf[key];
+        let teamCont = 0;
+        let models: Array<string> = [];
+        let costs: Array<number> = [];
+        let hours: Array<number> = [];
+  
+        team.forEach((item: any) => {
+          let empArr = item.USER.split('(');
+          let empID = empArr[1].replace(')', '');
+          let cost = parseFloat(item.COST);
+          let hour = parseFloat(item.HOURS);
+          
+          costs.push(cost);
+          models.push(empID);
+          hours.push(hour);
+  
+          teamCont++;
+        });
+  
+        teamsModels.push(models);
+        teamsCostsModels.push(costs);
+        teamsHoursModels.push(hours);
+      });
+  
+      this.teamsModels = teamsModels;
+      this.teamsCostsModels = teamsCostsModels;
+      this.teamsHoursModels = teamsHoursModels;
+  
+      let toolsConf = analysisObj.toolsConf;
+      toolsConf.forEach((tool: any) => {
+        let toolConf = this.tools.filter(item => item.ID == tool.ID)[0];
+        this.toolsUnitPrices.push(tool.COSTUNIT);
+
+        toolConf.COSTUNIT = tool.COSTUNIT;
+        toolConf.COSTTOTAL = tool.COSTTOTAL;
+      });
+
+      let sparePartsConf = analysisObj.sparePartsConf;
+      sparePartsConf.forEach((part: any) => {
+        let partConf = this.spareParts.filter(item => item.ID == part.ID)[0];
+        this.sparePartsUnitPrices.push(part.COSTUNIT);
+
+        partConf.COSTUNIT = part.COSTUNIT;
+        partConf.COSTTOTAL = part.COSTTOTAL;
+      });
+
+      let instructionsConf = analysisObj.instructionsConf;
+      let insKeys = Object.keys(instructionsConf);
+      insKeys.forEach(key => {
+        let insConf = instructionsConf[key];
+        this.instructionsCosts.push(insConf);
+
+        let inst = this.instructions.filter(item => item.ID == key)[0];
+        inst.COSTO = insConf;
+      });
+
+      this.asyncInputInitialization(teamsConf);
+    }else{
+      let teamsModels: Array<Array<string>> = [];
+      let teamsCostsModels: Array<Array<number>> = [];
+      let teamsHoursModels: Array<Array<number>> = [];
+
+      this.teamsConf.forEach(team => {
+        let models: Array<string> = [];
+        let costs: Array<number> = [];
+        let hours: Array<number> = [];
+
+        team.CONF.forEach((_) => {
+          models.push('');
+          costs.push(0);
+          hours.push(0);
+        });
+
+        teamsModels.push(models);
+        teamsCostsModels.push(costs);
+        teamsHoursModels.push(hours);
+      });
+  
+      this.teamsModels = teamsModels;
+      this.teamsCostsModels = teamsCostsModels;
+      this.teamsHoursModels = teamsHoursModels;
+      
+      this.tools.forEach(tool => {
+        let unitPrice = tool.COSTUNIT;
+        this.toolsUnitPrices.push(unitPrice);
+      });
+      
+      this.spareParts.forEach(part => {
+        let unitPrice = part.COSTUNIT;
+        this.sparePartsUnitPrices.push(unitPrice);
+      });
+
+      this.instructions.forEach(instruction => {
+        let cost = instruction.COSTO;
+        this.instructionsCosts.push(cost);
+      });
+    }
+  }
+
+  asyncInputInitialization(teamsConf: any){
+    setTimeout(() => {
+      let teamsKeys = Object.keys(teamsConf);
+      teamsKeys.forEach(key => {
+        let config = teamsConf[key];
+        let cont = 0;
+
+        config.forEach((user: any) => {
+          let userIDArr = user.USER.split('(');
+          let userID = userIDArr[1].replace(')', '');
+
+          let persInput = this._document.getElementById(`${key}-PERS-${cont}`) as HTMLInputElement;
+          persInput.value = userID;
+          
+          cont++;
+        });
+      });
+    }, 1000);
+  }
+
   getTeams(teamsStr: string, teamsConfStr: string): TeamsConfig[]{
     let teamsArr = JSON.parse(teamsStr);
     let teamsConfObj = JSON.parse(teamsConfStr);
@@ -332,82 +481,85 @@ export class BudgetAnalysisComponent implements OnInit {
     try{
       let idUser = localStorage.getItem('idusuario');
       let analysisObj = {};
+      let instructionsObj = {};
       let shouldContinue = true;
+      
+      this.instructions.every(ins => {
+        if(!ins.ISFROMFILE && ins.COSTO <= 0){
+          this.openSnackBar(`Aún no se ha configurado un costo para la actividad ${ins.INSTRUCCION}.`);
+          shouldContinue = false;
+          return false;
+        }else{
+          let id = ins.ID as never;
+          instructionsObj[id] = ins.COSTO as never;
+          shouldContinue = true;
+          return true;
+        }
+      });
 
-      this.teamsConf.every(team => {
-        let cont = 1;
-        let teamRes = team.CONF.every(conf => {
-          let userInput = this._document.getElementById(conf) as HTMLInputElement;
-          let userVal = userInput.value;
-
-          if(userVal == null || userVal == undefined || userVal == ''){
-            this.openSnackBar(`Aún no se ha seleccionado un empleado para el puesto ${cont} del ${team.NOMB}`);
-            shouldContinue = false;
-            return false;
-          }else{
-            let userInfo = this.workers.filter(item => item.ID == userVal)[0];
-            let userName = `${userInfo.NOMB} (${userInfo.ID})`;
-            let costInput = this._document.getElementById(`cost-${conf}`) as HTMLInputElement;
-            let costVal = costInput.value;
+      if(shouldContinue){
+        this.teamsConf.every(team => {
+          let cont = 1;
+          let teamRes = team.CONF.every(conf => {
+            let userInput = this._document.getElementById(conf) as HTMLInputElement;
+            let userVal = userInput.value;
   
-            if(costVal == null || costVal == undefined || costVal == ''){
-              this.openSnackBar(`Aún no se ha asignado el costo por hora para el empleado ${userName}`);
+            if(userVal == null || userVal == undefined || userVal == ''){
+              this.openSnackBar(`Aún no se ha seleccionado un empleado para el puesto ${cont} del ${team.NOMB}`);
               shouldContinue = false;
               return false;
             }else{
-              let hoursInput = this._document.getElementById(`hour-${conf}`) as HTMLInputElement;
-              let hoursVal = hoursInput.value;
-              let hoursNum = parseFloat(hoursVal);
-
-              if(hoursVal == null || hoursVal == undefined || hoursVal == ''){
-                this.openSnackBar(`Aún no se han asignado las horas de contrato para el empleado ${userName}`);
-                shouldContinue = false;
-                return false;
-              }else if(hoursNum <= 0){
-                this.openSnackBar(`Las horas de contrato asignadas para el empleado ${userName} deben ser mayor a 0`);
+              let userInfo = this.workers.filter(item => item.ID == userVal)[0];
+              let userName = `${userInfo.NOMB} (${userInfo.ID})`;
+              let costInput = this._document.getElementById(`cost-${conf}`) as HTMLInputElement;
+              let costVal = costInput.value;
+    
+              if(costVal == null || costVal == undefined || costVal == ''){
+                this.openSnackBar(`Aún no se ha asignado el costo por hora para el empleado ${userName}`);
                 shouldContinue = false;
                 return false;
               }else{
-                let id = team.ID as never;
-                let usrConf = analysisObj[id];
-                
-                if(usrConf == undefined){
-                  analysisObj[id] = {} as never;
+                let hoursInput = this._document.getElementById(`hour-${conf}`) as HTMLInputElement;
+                let hoursVal = hoursInput.value;
+                let hoursNum = parseFloat(hoursVal);
+  
+                if(hoursVal == null || hoursVal == undefined || hoursVal == ''){
+                  this.openSnackBar(`Aún no se han asignado las horas de contrato para el empleado ${userName}`);
+                  shouldContinue = false;
+                  return false;
+                }else if(hoursNum <= 0){
+                  this.openSnackBar(`Las horas de contrato asignadas para el empleado ${userName} deben ser mayor a 0`);
+                  shouldContinue = false;
+                  return false;
+                }else{
+                  let id = team.ID as never;
+                  let usrConf = analysisObj[id];
+                  
+                  if(usrConf == undefined){
+                    analysisObj[id] = {} as never;
+                  }
+  
+                  let emp = cont - 1 as never;
+                  analysisObj[id][emp] = {
+                    USER: userInfo.ID,
+                    COST: costVal,
+                    HOURS: hoursVal,
+                  } as never;
+                  
+                  cont++;
+                  return true;
                 }
-
-                let emp = cont - 1 as never;
-                analysisObj[id][emp] = {
-                  USER: userInfo.ID,
-                  COST: costVal,
-                  HOURS: hoursVal,
-                } as never;
-                
-                cont++;
-                return true;
               }
             }
-          }
-        });
-
-        return teamRes;
-      });
-
-      if(shouldContinue){
-        this.tools.every(tool => {
-          if(tool.COSTUNIT <= 0){
-            this.openSnackBar(`El costo unitario de la herramienta '${tool.NOM}' no es válido.`);
-            shouldContinue = false;
-            return false;
-          }else{
-            shouldContinue = true;
-            return true;
-          }
+          });
+  
+          return teamRes;
         });
-
+  
         if(shouldContinue){
-          this.spareParts.every(part => {
-            if(part.COSTUNIT <= 0){
-              this.openSnackBar(`El costo unitario de la herramienta '${part.NOM}' no es válido.`);
+          this.tools.every(tool => {
+            if(tool.COSTUNIT <= 0){
+              this.openSnackBar(`El costo unitario de la herramienta '${tool.NOM}' no es válido.`);
               shouldContinue = false;
               return false;
             }else{
@@ -415,28 +567,41 @@ export class BudgetAnalysisComponent implements OnInit {
               return true;
             }
           });
-
+  
           if(shouldContinue){
-            let finalObj = {
-              teamsConf: analysisObj,
-              toolsConf: this.tools,
-              sparePartsConf: this.spareParts,
-              extraComments: this.extraComments.value,
-            };
-            console.log(finalObj);
-    
-            let analysisStr = JSON.stringify(finalObj);
-            let idOrder = await this._encService.encrypt(`${this.idOrder}`);
-            let formData = new FormData();
-    
-            formData.append('id_user', idUser!);
-            formData.append('linea', '1');
-            formData.append('id_order', idOrder!);
-            formData.append('analysis', analysisStr);
-    
-            await lastValueFrom(this._prevMaintService.setBudgetAnalysis(formData));
-            this.openSnackBar('El análisis presupuestario se asignó correctamente.');
-            this.goBack(1);
+            this.spareParts.every(part => {
+              if(part.COSTUNIT <= 0){
+                this.openSnackBar(`El costo unitario de la herramienta '${part.NOM}' no es válido.`);
+                shouldContinue = false;
+                return false;
+              }else{
+                shouldContinue = true;
+                return true;
+              }
+            });
+  
+            if(shouldContinue){
+              let finalObj = {
+                instructionsConf: instructionsObj,
+                teamsConf: analysisObj,
+                toolsConf: this.tools,
+                sparePartsConf: this.spareParts,
+                extraComments: this.extraComments.value,
+              };
+      
+              let analysisStr = JSON.stringify(finalObj);
+              let idOrder = await this._encService.encrypt(`${this.idOrder}`);
+              let formData = new FormData();
+      
+              formData.append('id_user', idUser!);
+              formData.append('linea', '1');
+              formData.append('id_order', idOrder!);
+              formData.append('analysis', analysisStr);
+      
+              await lastValueFrom(this._prevMaintService.setBudgetAnalysis(formData));
+              this.openSnackBar('El análisis presupuestario se asignó correctamente.');
+              this.goBack(1);
+            }
           }
         }
       }
@@ -463,7 +628,20 @@ export class BudgetAnalysisComponent implements OnInit {
     if(!isNaN(unitPriceNum)){
       let totalPrice = res.REQ * unitPriceNum;
       res.COSTTOTAL = totalPrice;
-      res.COSTUNIT = unitPriceNum
+      res.COSTUNIT = unitPriceNum;
+    }else{
+      res.COSTUNIT = 0;
+      res.COSTUNIT = 0;
+    }
+  }
+
+  updateActivityCost(id: string, cost: string){
+    let ins = this.instructions.filter(inst => inst.ID == id)[0];
+    let insCost = parseFloat(cost);
+    if(isNaN(insCost)){
+      ins.COSTO = 0;
+    }else{
+      ins.COSTO = insCost;
     }
   }
 }

+ 1 - 1
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/new-work-order/new-work-order.component.ts

@@ -157,7 +157,7 @@ const SPARE_PARTS_TMP: ToolInfo[] = [
   {ID: 'S19', NOMB: 'Teclado para PC', MODE: '5413', CANTDISP: 24, TYPE: 'Refaccción', UNIT: 'Pieza'},
   {ID: 'S20', NOMB: 'Cable HDMI 2m', MODE: 'ASD-181', CANTDISP: 6, TYPE: 'Refaccción', UNIT: 'Pieza'},
 ];
-interface Instruction{
+export interface Instruction{
   ID: string,
   INSTRUCCION: string,
   DURACION: number,

+ 5 - 2
sistema-mantenimiento-front/src/app/components/preventive-maintenance/work-orders/order-details/order-details.component.ts

@@ -275,9 +275,12 @@ export class OrderDetailsComponent implements OnInit {
   getInstructionsArr(instructionsStr: string): string[]{
     let instructions = JSON.parse(instructionsStr);
     let instructionsArr: string[] = [];
+    let analysisObj = JSON.parse(this.workOrder?.ANALISIS!);
+    let instructionsConf = analysisObj.instructionsConf;
 
     instructions.forEach((item: any) => {
-      instructionsArr.push(item.INSTRUCCION)
+      let price = instructionsConf[item.ID];
+      instructionsArr.push(`${item.INSTRUCCION}. Costo: $${price}.`)
     });
     
     return instructionsArr;
@@ -563,7 +566,7 @@ export class OrderDetailsComponent implements OnInit {
     analysisObj.sparePartsConf.forEach((part: any) => {
       toolsTmp.push(`${part.NOM}, ${part.REQ} ${part.UNIT}(s) requerida(s) - Costo unitario: $${part.COSTUNIT.toFixed(2)}, Costo total: $${part.COSTTOTAL.toFixed(2)}.`);
     });
-
+    
     arrFn.push(sparePartsTmp);
     return arrFn;
   }