Selaa lähdekoodia

Merge branch 'development' of onunez/frontend-inversiones into master

Oscar José Nuñez Chávez 5 vuotta sitten
vanhempi
commit
ec29992033
100 muutettua tiedostoa jossa 13204 lisäystä ja 1538 poistoa
  1. 18 0
      Dockerfile
  2. 13 19
      angular.json
  3. 49 0
      nginx/nginx.conf
  4. 37 10
      package-lock.json
  5. 5 1
      package.json
  6. 6 5
      src/app/app-routing.module.ts
  7. 17 16
      src/app/app.component.spec.ts
  8. 1 7
      src/app/app.module.ts
  9. 29 7
      src/app/components/arbitrations/arbitrations.component.spec.ts
  10. 0 115
      src/app/components/confirm-account/confirm-account.component.html
  11. 0 113
      src/app/components/confirm-account/confirm-account.component.scss
  12. 0 25
      src/app/components/confirm-account/confirm-account.component.spec.ts
  13. 0 139
      src/app/components/confirm-account/confirm-account.component.ts
  14. 1 7
      src/app/components/dashboard/dashboard.component.html
  15. 11 7
      src/app/components/dashboard/dashboard.component.spec.ts
  16. 8 19
      src/app/components/dashboard/dashboard.component.ts
  17. 174 0
      src/app/components/instruments/anc/anc.component.html
  18. 87 0
      src/app/components/instruments/anc/anc.component.ts
  19. 174 0
      src/app/components/instruments/apn/apn.component.html
  20. 89 0
      src/app/components/instruments/apn/apn.component.ts
  21. 289 0
      src/app/components/instruments/bonos/bonos.component.html
  22. 93 0
      src/app/components/instruments/bonos/bonos.component.ts
  23. 654 0
      src/app/components/instruments/cete/cete.component.html
  24. 361 0
      src/app/components/instruments/cete/cete.component.ts
  25. 522 0
      src/app/components/instruments/dap/dap.component.html
  26. 302 0
      src/app/components/instruments/dap/dap.component.ts
  27. 456 0
      src/app/components/instruments/lete/lete.component.html
  28. 310 0
      src/app/components/instruments/lete/lete.component.ts
  29. 754 0
      src/app/components/instruments/pbur/pbur.component.html
  30. 400 0
      src/app/components/instruments/pbur/pbur.component.ts
  31. 756 0
      src/app/components/instruments/vcn/vcn.component.html
  32. 402 0
      src/app/components/instruments/vcn/vcn.component.ts
  33. 189 0
      src/app/components/investment-proposals/approve/approve.component.html
  34. 6 0
      src/app/components/investment-proposals/approve/approve.component.scss
  35. 429 0
      src/app/components/investment-proposals/approve/approve.component.ts
  36. 155 0
      src/app/components/investment-proposals/change-history/change-history.component.html
  37. 17 0
      src/app/components/investment-proposals/change-history/change-history.component.scss
  38. 95 0
      src/app/components/investment-proposals/change-history/change-history.component.ts
  39. 411 0
      src/app/components/investment-proposals/complement-info/complement-info.component.html
  40. 191 0
      src/app/components/investment-proposals/complement-info/complement-info.component.ts
  41. 367 0
      src/app/components/investment-proposals/general-info/general-info.component.html
  42. 1 0
      src/app/components/investment-proposals/general-info/general-info.component.scss
  43. 67 0
      src/app/components/investment-proposals/general-info/general-info.component.spec.ts
  44. 347 0
      src/app/components/investment-proposals/general-info/general-info.component.ts
  45. 51 0
      src/app/components/investment-proposals/instrument-work/instrument-work.component.html
  46. 105 0
      src/app/components/investment-proposals/instrument-work/instrument-work.component.ts
  47. 5 0
      src/app/components/investment-proposals/instrument/instrument.component.ts
  48. 8 0
      src/app/components/investment-proposals/instrument/instrument.directive.ts
  49. 222 3
      src/app/components/investment-proposals/investment-proposals.component.html
  50. 10 0
      src/app/components/investment-proposals/investment-proposals.component.scss
  51. 66 8
      src/app/components/investment-proposals/investment-proposals.component.spec.ts
  52. 322 3
      src/app/components/investment-proposals/investment-proposals.component.ts
  53. 188 0
      src/app/components/investment-proposals/payment-info/payment-info.component.html
  54. 208 0
      src/app/components/investment-proposals/payment-info/payment-info.component.ts
  55. 173 0
      src/app/components/investment-proposals/payment-requirement/payment-requirement.component.html
  56. 27 0
      src/app/components/investment-proposals/payment-requirement/payment-requirement.component.scss
  57. 6 6
      src/app/components/investment-proposals/payment-requirement/payment-requirement.component.spec.ts
  58. 207 0
      src/app/components/investment-proposals/payment-requirement/payment-requirement.component.ts
  59. 172 0
      src/app/components/investment-proposals/proposal-detail/proposal-detail.component.html
  60. 6 0
      src/app/components/investment-proposals/proposal-detail/proposal-detail.component.scss
  61. 325 0
      src/app/components/investment-proposals/proposal-detail/proposal-detail.component.ts
  62. 243 0
      src/app/components/investment-proposals/result/result.component.html
  63. 8 0
      src/app/components/investment-proposals/result/result.component.scss
  64. 477 0
      src/app/components/investment-proposals/result/result.component.ts
  65. 189 0
      src/app/components/investment-proposals/review/review.component.html
  66. 6 0
      src/app/components/investment-proposals/review/review.component.scss
  67. 429 0
      src/app/components/investment-proposals/review/review.component.ts
  68. 100 5
      src/app/components/investments/investments.component.html
  69. 10 0
      src/app/components/investments/investments.component.scss
  70. 29 7
      src/app/components/investments/investments.component.spec.ts
  71. 148 5
      src/app/components/investments/investments.component.ts
  72. 31 15
      src/app/components/login/login.component.html
  73. 1 1
      src/app/components/login/login.component.scss
  74. 20 8
      src/app/components/login/login.component.spec.ts
  75. 46 124
      src/app/components/login/login.component.ts
  76. 29 7
      src/app/components/performances/performances.component.spec.ts
  77. 68 0
      src/app/components/plugins/dynamic-component-loader/dynamic-component-loader.module.ts
  78. 172 0
      src/app/components/plugins/dynamic-component-loader/dynamic-component-loader.service.ts
  79. 20 0
      src/app/components/plugins/dynamic-component-loader/dynamic-component-manifest.ts
  80. 58 0
      src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.html
  81. 212 0
      src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.scss
  82. 70 0
      src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.ts
  83. 6 8
      src/app/components/plugins/plugins.module.ts
  84. 9 5
      src/app/components/shared/footer/footer.component.html
  85. 33 7
      src/app/components/shared/navbar/navbar.component.spec.ts
  86. 175 164
      src/app/components/shared/navbar/navbar.component.ts
  87. 22 9
      src/app/components/shared/sidebar/sidebar.component.html
  88. 2 2
      src/app/components/shared/sidebar/sidebar.component.scss
  89. 33 7
      src/app/components/shared/sidebar/sidebar.component.spec.ts
  90. 16 21
      src/app/components/shared/sidebar/sidebar.component.ts
  91. 0 171
      src/app/components/users/new-user/new-user.component.html
  92. 0 3
      src/app/components/users/new-user/new-user.component.scss
  93. 0 95
      src/app/components/users/new-user/new-user.component.ts
  94. 0 80
      src/app/components/users/users.component.html
  95. 0 0
      src/app/components/users/users.component.scss
  96. 0 25
      src/app/components/users/users.component.spec.ts
  97. 0 76
      src/app/components/users/users.component.ts
  98. 9 53
      src/app/layouts/admin/admin.component.html
  99. 20 7
      src/app/layouts/admin/admin.component.spec.ts
  100. 119 123
      src/app/layouts/admin/admin.component.ts

+ 18 - 0
Dockerfile

@@ -0,0 +1,18 @@
+# Step 1: Build the app in image "builder"
+FROM node:lts-alpine AS builder
+
+COPY package.json package-lock.json ./
+RUN npm i && mkdir /app && mv ./node_modules ./app
+WORKDIR /app
+COPY . .
+RUN node --max-old-space-size=4096 ./node_modules/@angular/cli/bin/ng build --prod
+
+# Step 2: Use build output from 'builder'
+
+FROM nginx:stable-alpine
+LABEL version="1.0"
+
+COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
+
+WORKDIR /usr/share/nginx/html
+COPY --from=builder /app/dist/frontend-inversiones/ .

+ 13 - 19
angular.json

@@ -23,16 +23,14 @@
             "polyfills": "src/polyfills.ts",
             "tsConfig": "tsconfig.app.json",
             "aot": false,
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
+            "assets": ["src/favicon.ico", "src/assets"],
             "styles": [
               "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
               "node_modules/perfect-scrollbar/css/perfect-scrollbar.css",
               "src/assets/scss/material-dashboard.scss",
-              "src/styles.scss",
-              "node_modules/bootstrap-select/dist/css/bootstrap-select.css"
+              "node_modules/bootstrap-select/dist/css/bootstrap-select.css",
+              "node_modules/angular-archwizard/archwizard.css",
+              "src/styles.scss"
             ],
             "scripts": [
               "node_modules/jquery/dist/jquery.js",
@@ -60,7 +58,7 @@
               "aot": true,
               "extractLicenses": true,
               "vendorChunk": false,
-              "buildOptimizer": true,
+              "buildOptimizer": false,
               "budgets": [
                 {
                   "type": "initial",
@@ -100,17 +98,14 @@
             "polyfills": "src/polyfills.ts",
             "tsConfig": "tsconfig.spec.json",
             "karmaConfig": "karma.conf.js",
-            "assets": [
-              "src/favicon.ico",
-              "src/assets"
-            ],
+            "assets": ["src/favicon.ico", "src/assets"],
             "styles": [
               "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
-              "node_modules/font-awesome/scss/font-awesome.scss",
               "node_modules/perfect-scrollbar/css/perfect-scrollbar.css",
               "src/assets/scss/material-dashboard.scss",
-              "src/styles.scss",
-              "node_modules/bootstrap-select/dist/css/bootstrap-select.css"
+              "node_modules/bootstrap-select/dist/css/bootstrap-select.css",
+              "node_modules/angular-archwizard/archwizard.css",
+              "src/styles.scss"
             ],
             "scripts": [
               "node_modules/jquery/dist/jquery.js",
@@ -131,9 +126,7 @@
               "tsconfig.spec.json",
               "e2e/tsconfig.json"
             ],
-            "exclude": [
-              "**/node_modules/**"
-            ]
+            "exclude": ["**/node_modules/**"]
           }
         },
         "e2e": {
@@ -149,6 +142,7 @@
           }
         }
       }
-    }},
+    }
+  },
   "defaultProject": "frontend-inversiones"
-}
+}

+ 49 - 0
nginx/nginx.conf

@@ -0,0 +1,49 @@
+worker_processes  1;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    upstream api {
+        server backend:8000;
+    }
+    server {
+        listen 80;
+        server_name  localhost;
+
+        root   /usr/share/nginx/html;
+        index  index.html index.htm;
+        include /etc/nginx/mime.types;
+
+        location /api/ {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection 'upgrade';
+            proxy_set_header Host $host;
+            proxy_set_header X-Real-IP $remote_addr;
+            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+            proxy_set_header X-NginX-Proxy true;
+            proxy_cache_bypass $http_upgrade;
+        }
+
+        location /assets/ {
+            access_log off;
+            expires 1d;
+        }
+        location ~ \.(css|js|svg|ico)$ {
+            access_log off;
+            expires 1d;
+        }
+        
+        gzip on;
+        gzip_min_length 1000;
+        gzip_proxied expired no-cache no-store private auth;
+        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
+
+        location / {
+            try_files $uri $uri/ /index.html;
+        }
+    }
+}

+ 37 - 10
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "frontend-inversiones",
-  "version": "0.0.0",
+  "version": "1.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1065,6 +1065,14 @@
         "tslib": "^1.9.0"
       }
     },
+    "@auth0/angular-jwt": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@auth0/angular-jwt/-/angular-jwt-4.0.0.tgz",
+      "integrity": "sha512-CHvk1zJ9jpQupl0f5y7EmTvYAwugyFvC4ztLsZKr7ZC7anNVaDd1+pDFJYS+ZEU9jLWzE74+AfVKfigImADJuw==",
+      "requires": {
+        "url": "^0.11.0"
+      }
+    },
     "@babel/code-frame": {
       "version": "7.5.5",
       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
@@ -2329,6 +2337,14 @@
       "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
       "dev": true
     },
+    "angular-archwizard": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/angular-archwizard/-/angular-archwizard-5.0.0.tgz",
+      "integrity": "sha512-bj+cshnEHKghGXgjiSdyG+Qs3+gp+5/GMzXm3F2QzIESC7kd8KxaXASwTdo4mbXx8UthT43m3gfWrKUD+GPXOQ==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "angular-bootstrap-md": {
       "version": "8.8.1",
       "resolved": "https://registry.npmjs.org/angular-bootstrap-md/-/angular-bootstrap-md-8.8.1.tgz",
@@ -4128,9 +4144,9 @@
       }
     },
     "date-fns": {
-      "version": "1.30.1",
-      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
-      "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw=="
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.10.0.tgz",
+      "integrity": "sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA=="
     },
     "date-format": {
       "version": "2.1.0",
@@ -8149,6 +8165,14 @@
       "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
       "dev": true
     },
+    "ng2-file-upload": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/ng2-file-upload/-/ng2-file-upload-1.4.0.tgz",
+      "integrity": "sha512-3J/KPU/tyh/ad6TFeUbrxX+SihUj0iOEt2Zsg4EX7mB3GFiQscXOfcUOxCkBtPWWWaqt3azrYbVGzsYa3/7NzQ==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "ngx-animating-datepicker": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/ngx-animating-datepicker/-/ngx-animating-datepicker-1.2.1.tgz",
@@ -8237,6 +8261,11 @@
             "readdirp": "^2.0.0"
           }
         },
+        "date-fns": {
+          "version": "1.30.1",
+          "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
+          "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw=="
+        },
         "debug": {
           "version": "2.6.9",
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -8483,7 +8512,8 @@
             },
             "minimist": {
               "version": "0.0.8",
-              "bundled": true
+              "bundled": true,
+              "optional": true
             },
             "minipass": {
               "version": "2.9.0",
@@ -10314,8 +10344,7 @@
     "querystring": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
-      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
-      "dev": true
+      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
     },
     "querystring-es3": {
       "version": "0.2.1",
@@ -12372,7 +12401,6 @@
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
       "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
-      "dev": true,
       "requires": {
         "punycode": "1.3.2",
         "querystring": "0.2.0"
@@ -12381,8 +12409,7 @@
         "punycode": {
           "version": "1.3.2",
           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
-          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
-          "dev": true
+          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
         }
       }
     },

+ 5 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "frontend-inversiones",
-  "version": "0.0.0",
+  "version": "1.0.0",
   "scripts": {
     "ng": "ng",
     "start": "ng serve",
@@ -22,10 +22,12 @@
     "@angular/platform-browser": "~8.2.14",
     "@angular/platform-browser-dynamic": "~8.2.14",
     "@angular/router": "~8.2.14",
+    "@auth0/angular-jwt": "^4.0.0",
     "@fortawesome/angular-fontawesome": "^0.5.0",
     "@fortawesome/fontawesome-free": "^5.12.0",
     "@fortawesome/fontawesome-svg-core": "^1.2.26",
     "@types/crypto-js": "^3.1.43",
+    "angular-archwizard": "^5.0.0",
     "angular-bootstrap-md": "^8.8.1",
     "angular-datatables": "^8.0.0",
     "angular-mydatepicker": "^0.3.4",
@@ -36,10 +38,12 @@
     "chart.js": "^2.9.3",
     "classlist.js": "^1.1.20150312",
     "crypto-js": "^3.1.9-1",
+    "date-fns": "^2.0.1",
     "hammerjs": "^2.0.8",
     "jquery": "^3.4.1",
     "mat-table-exporter": "^1.2.2",
     "moment": "^2.24.0",
+    "ng2-file-upload": "^1.4.0",
     "ngx-animating-datepicker": "^1.2.1",
     "ngx-bootstrap": "^5.1.1",
     "ngx-daterangepicker": "^1.1.1",

+ 6 - 5
src/app/app-routing.module.ts

@@ -8,12 +8,13 @@ import { AdminComponent } from "./layouts/admin/admin.component";
 import { LoginComponent } from "./components/login/login.component";
 import { AuthGuard } from "./services/auth.guard";
 import { Role } from "./models/role";
-import { ConfirmAccountComponent } from "./components/confirm-account/confirm-account.component";
+import { WorkflowGuard } from "./services/investment-proposal-workflow.guard";
 
 const routes: Routes = [
   {
     path: "",
-    redirectTo: "dashboard",
+    // redirectTo: "dashboard",
+    redirectTo: "investment-proposals",
     pathMatch: "full"
   },
   {
@@ -28,7 +29,6 @@ const routes: Routes = [
     ]
   },
   { path: "login", component: LoginComponent },
-  { path: "confirm-account", component: ConfirmAccountComponent },
   { path: "**", redirectTo: "" }
 ];
 
@@ -37,10 +37,11 @@ const routes: Routes = [
     CommonModule,
     BrowserModule,
     RouterModule.forRoot(routes, {
-      useHash: true,
-      onSameUrlNavigation: "reload"
+      useHash: true
+      //onSameUrlNavigation: "reload"
     })
   ],
   exports: []
+  //providers: [WorkflowGuard]
 })
 export class AppRoutingModule {}

+ 17 - 16
src/app/app.component.spec.ts

@@ -1,20 +1,20 @@
-import { TestBed, async } from '@angular/core/testing';
-import { RouterTestingModule } from '@angular/router/testing';
-import { AppComponent } from './app.component';
+import { TestBed, async } from "@angular/core/testing";
+import { RouterTestingModule } from "@angular/router/testing";
+import { AppComponent } from "./app.component";
+import { By } from "@angular/platform-browser";
+import { RouterOutlet, RouterLinkWithHref } from "@angular/router";
+import { NO_ERRORS_SCHEMA } from "@angular/core";
 
-describe('AppComponent', () => {
+describe("AppComponent", () => {
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      imports: [
-        RouterTestingModule
-      ],
-      declarations: [
-        AppComponent
-      ],
+      declarations: [AppComponent],
+      imports: [RouterTestingModule.withRoutes([])],
+      schemas: [NO_ERRORS_SCHEMA]
     }).compileComponents();
   }));
 
-  it('should create the app', () => {
+  it("should create the app", () => {
     const fixture = TestBed.createComponent(AppComponent);
     const app = fixture.debugElement.componentInstance;
     expect(app).toBeTruthy();
@@ -23,13 +23,14 @@ describe('AppComponent', () => {
   it(`should have as title 'frontend-inversiones'`, () => {
     const fixture = TestBed.createComponent(AppComponent);
     const app = fixture.debugElement.componentInstance;
-    expect(app.title).toEqual('frontend-inversiones');
+    expect(app.title).toEqual("frontend-inversiones");
   });
 
-  it('should render title', () => {
+  it("Debe de tener un router-outlet", () => {
     const fixture = TestBed.createComponent(AppComponent);
-    fixture.detectChanges();
-    const compiled = fixture.debugElement.nativeElement;
-    expect(compiled.querySelector('.content span').textContent).toContain('frontend-inversiones app is running!');
+
+    const debugElement = fixture.debugElement.query(By.directive(RouterOutlet));
+
+    expect(debugElement).not.toBeNull();
   });
 });

+ 1 - 7
src/app/app.module.ts

@@ -27,16 +27,10 @@ import { PluginsModule } from "./components/plugins/plugins.module";
 import { LoginComponent } from "./components/login/login.component";
 
 import { TokenInterceptor } from "@app/services/token.interceptor";
-import { ConfirmAccountComponent } from "./components/confirm-account/confirm-account.component";
 import { MatPasswordStrengthModule } from "@angular-material-extensions/password-strength";
 
 @NgModule({
-  declarations: [
-    AppComponent,
-    AdminComponent,
-    LoginComponent,
-    ConfirmAccountComponent
-  ],
+  declarations: [AppComponent, AdminComponent, LoginComponent],
   imports: [
     BrowserModule,
     BrowserAnimationsModule,

+ 29 - 7
src/app/components/arbitrations/arbitrations.component.spec.ts

@@ -1,16 +1,19 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { ArbitrationsComponent } from './arbitrations.component';
+import { ArbitrationsComponent } from "./arbitrations.component";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
 
-describe('ArbitrationsComponent', () => {
+describe("ArbitrationsComponent", () => {
   let component: ArbitrationsComponent;
   let fixture: ComponentFixture<ArbitrationsComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ ArbitrationsComponent ]
-    })
-    .compileComponents();
+      declarations: [ArbitrationsComponent],
+      imports: [RouterTestingModule]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +22,26 @@ describe('ArbitrationsComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      if (elem.attributes["ng-reflect-router-link"] === "/") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 0 - 115
src/app/components/confirm-account/confirm-account.component.html

@@ -1,115 +0,0 @@
-<div id="wrapper">
-  <div class="vertical-align-wrap">
-    <div class="vertical-align-middle auth-main">
-      <div class="auth-box">
-        <div class="top">
-          <img alt="Inverlec" src="./assets/img/inverlec_logo.png">
-        </div>
-
-        <div class="card">
-          <div class="header">
-            <h1 class="lead">Confirmación de cuenta</h1>
-          </div>
-          <div class="body" *ngIf="validToken">
-            <form [formGroup]="activateForm" (ngSubmit)="activateAccount()">
-
-              <div class="form-group">
-                <label for="email">Correo electrónico</label>
-                <input type="text" class="form-control"
-                formControlName="email" required email readonly />
-              </div>
-
-              <div class="form-group">
-                <label for="name">Nombre</label>
-                <input type="text" class="form-control"
-                formControlName="first_name" [ngClass]="{ 'is-invalid': submitted && f.first_name.errors }"/>
-                <div *ngIf="submitted && f.first_name.errors" class="invalid-feedback">
-                  <div *ngIf="f.first_name.errors.required">Campo requerido</div>
-                </div>
-              </div>
-              
-              <div class="form-group">
-                <label for="name">Apellido</label>
-                <input type="text" class="form-control"
-                formControlName="last_name" [ngClass]="{ 'is-invalid': submitted && f.last_name.errors }"/>
-                <div *ngIf="submitted && f.last_name.errors" class="invalid-feedback">
-                  <div *ngIf="f.last_name.errors.required">Campo requerido</div>
-                  
-                </div>
-              </div>
-
-              <div class="form-group">
-                <div class="hint-wrapper">
-                  <small class="hint">
-                    <i class="fas fa-exclamation-circle"></i>
-                    La contraseña debe contener letras mayusculas, minusculas, al menos un número y un símbolo.
-                  </small>
-                </div>
-                
-                <label for="password">Contraseña</label>
-                <input type="password" class="form-control"
-                formControlName="password" [ngClass]="{ 'is-invalid': submitted && f.password.errors }"/>
-                <div *ngIf="submitted && f.password.errors" class="invalid-feedback">
-                  <div *ngIf="f.password.errors.required">Campo requerido</div>
-                  <div *ngIf="f.password.errors.minlength">La contraseña debe contener al menos 8 caracteres</div>
-                  <div *ngIf="f.password.hasError('passwordStrength')" style="white-space: pre;">
-                    {{f.password.errors['passwordStrength']}}
-                  </div>
-                </div>
-              </div>
-
-              <div class="form-group">
-                <label for="confirm_password">Confirmar contraseña</label>
-                <input type="password" class="form-control"
-                formControlName="confirm_password" [ngClass]="{ 'is-invalid': submitted && f.confirm_password.errors }"/>
-                <div *ngIf="submitted && f.confirm_password.errors" class="invalid-feedback">
-                  <div *ngIf="f.confirm_password.errors.required">Campo requerido</div>
-                  <div *ngIf="f.confirm_password.errors.mustMatch">Las contraseñas deben coincidir</div>
-                </div>
-              </div>
-    
-              <br>
-
-              <div class="div-center">
-                <button class="btn btn-primary" type="submit"> 
-                  Confirmar cuenta
-                </button>
-              </div>
-
-            </form>
-          </div>
-
-          <div class="body" *ngIf="invalidToken">
-            <div class="tokenError">
-              <h3>
-                {{errorMessage}}
-              </h3>
-
-              <div *ngIf="userActivated">
-                <a class="btn btn-primary" [routerLink]="['/login']">
-                  Ir a inicio de sesion
-                </a>
-              </div>
-
-            </div>
-          </div>
-
-          <div class="body" *ngIf="successActivation">
-            <div class="tokenSuccess">
-              <h3>
-                {{activateMessage}}
-              </h3>
-
-              <a class="btn btn-primary" [routerLink]="['/login']">
-                Ir a inicio de sesion
-              </a>
-
-            </div>
-          </div>
-
-
-        </div>
-      </div>
-    </div>
-  </div>
-</div>

+ 0 - 113
src/app/components/confirm-account/confirm-account.component.scss

@@ -1,113 +0,0 @@
-.hint-wrapper {
-  background: #eee;
-  border: 1px solid #aaa;
-  padding: 5px;
-  margin-bottom: 5px;
-}
-
-.vertical-align-wrap {
-  //position: absolute;
-  width: 100%;
-  height: 100%;
-  //display: table;
-}
-
-.vertical-align-middle {
-  //display: table-cell;
-  vertical-align: middle;
-}
-
-.auth-box {
-  width: 800px;
-  height: auto;
-  margin: 20px auto;
-
-  .top {
-    margin: 0 auto;
-    text-align: center;
-  }
-
-  .card {
-    padding: 25px;
-
-    .lead {
-      text-align: center;
-      font-size: 1.5rem;
-      color: #223d7d;
-    }
-  }
-
-  .div-center {
-    text-align: center;
-    margin: 0 auto;
-  }
-}
-
-.auth-main::before {
-  content: '';
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 200px;
-  height: 100%;
-  z-index: -1;
-  background: #223d7d; //#f0f0f0;
-}
-
-.auth-main:after {
-  content: '';
-  position: absolute;
-  right: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  z-index: -2;
-  //background: #223d7d;
-  //background: url(../../assets/images/auth_bg.jpg) no-repeat top left fixed;
-}
-
-.card {
-  background: #fff;
-  transition: .5s;
-  border: 0;
-  margin-bottom: 30px;
-  border-radius: .55rem;
-  position: relative;
-  width: 100%;
-  box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1);
-}
-
-.tokenError,
-.tokenSuccess {
-  padding: 40px 20px;
-  text-align: center;
-  margin-bottom: 20px;
-  font-weight: bold;
-}
-
-.tokenError {
-  color: #f44336;
-}
-
-.tokenSuccess {
-  color: #4caf50;
-}
-
-h3 {
-  font-size: 1.6rem;
-  margin-bottom: 30px;
-}
-
-@media screen and (max-width: 640px) {
-  .auth-box {
-      width: 90%;
-  }
-}
-
-@media screen and (max-width: 992px) {
-  .auth-box {
-      width: 80%;
-      margin: 0 auto;
-  }
-}
-

+ 0 - 25
src/app/components/confirm-account/confirm-account.component.spec.ts

@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { ConfirmAccountComponent } from './confirm-account.component';
-
-describe('ConfirmAccountComponent', () => {
-  let component: ConfirmAccountComponent;
-  let fixture: ComponentFixture<ConfirmAccountComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [ ConfirmAccountComponent ]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(ConfirmAccountComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 139
src/app/components/confirm-account/confirm-account.component.ts

@@ -1,139 +0,0 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
-import { FormGroup, FormBuilder, Validators } from '@angular/forms';
-import { UserService } from '@app/services/user.service';
-import Swal from 'sweetalert2';
-import { ValidatorComponent, PasswordStrengthValidator } from '../plugins/validator/validator.component';
-
-
-@Component({
-  selector: 'app-confirm-account',
-  templateUrl: './confirm-account.component.html',
-  styleUrls: ['./confirm-account.component.scss']
-})
-export class ConfirmAccountComponent implements OnInit {
-  token:string;
-  validToken:boolean;
-  activateForm: FormGroup;
-  errorMessage: string;
-  userActivated: boolean;
-  successActivation: boolean;
-  activateMessage: string;
-  invalidToken: boolean;
-  submitted: boolean = false;
-  showDetails: boolean;
-
-  constructor(private formBuilder: FormBuilder, private route: ActivatedRoute, private userService: UserService) {
-    this.route.queryParams.subscribe(params => {
-      this.token = params['token'];
-    });
-  }
-
-  ngOnInit() {
-    if (this.token !== null){
-      
-      this.userService.validateUserToken(
-        {
-          token: this.token
-        }
-      ).subscribe(res => {
-        
-        let userData = res["data"].user;
-
-        this.validToken = true;
-        this.activateForm = this.formBuilder.group({
-          // Load information
-          email: [(userData.email)],
-          first_name: [(userData.first_name),Validators.required],
-          last_name: [(userData.last_name),Validators.required],
-          password: ['',[Validators.required, Validators.minLength(8), PasswordStrengthValidator]],
-          confirm_password: ['',Validators.required]
-        },{
-          
-            validator: ValidatorComponent('password', 'confirm_password')
-        });
-      }, (err) => {
-       
-        this.userActivated = true;
-        this.invalidToken = true;
-        this.errorMessage = err.message;
-      });
-    
-    }
-    else {
-      this.invalidToken = true;
-      this.errorMessage = "No existe el token";
-    }
-  }
-
-  get f() { return this.activateForm.controls; }
-
-
-  activateAccount(){
-
-    this.submitted = true;
-
-    // stop here if form is invalid
-    if (this.activateForm.invalid) {
-      return;
-    }
-
-    this.userService.activateUser(
-      {
-        email: this.f.email.value,
-        first_name: this.f.first_name.value,
-        last_name: this.f.last_name.value,
-        password: this.f.password.value,
-        confirm_password: this.f.confirm_password.value,
-      }
-    ).subscribe(res => {
-      this.successActivation = true;
-      this.validToken = false;
-      this.activateMessage = "Usuario registrado con exito";
-
-    }, (err) => {
-      this.validToken = false;
-      this.errorMessage = err.message;
-    });
-    //
-
-  }
-
-}
-
-
-/*
-
-Swal.fire({
-      allowOutsideClick: false,
-      type: 'info',
-      text: 'Espere por favor...'
-    });
-    Swal.showLoading();
-
-    this.authService.login(
-      {
-        email: this.f.email.value,
-        password: this.f.password.value
-      }
-    )
-    .subscribe(success => {
-      if (success) {
-        window.location.href="#/dashboard";
-      }
-      else {
-        Swal.fire({
-          type: 'error',
-          title: 'No se pudo auntenticar',
-          text: "Email o contraseña incorrecta"
-        })  
-      }
-    },(err) => {
-      Swal.fire({
-        type: 'error',
-        title: 'Error en el servidor',
-        text: "No su pudo obtener la informacion"
-      });
-    });
-
-    */

+ 1 - 7
src/app/components/dashboard/dashboard.component.html

@@ -1,7 +1 @@
-<h2 class="floating-title">{{title}}</h2>
-
-<div class="main-content">
-  <div class="container-fluid">
-    Content
-  </div>
-</div>
+<h2 class="floating-title">{{ title }}</h2>

+ 11 - 7
src/app/components/dashboard/dashboard.component.spec.ts

@@ -1,16 +1,20 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { DashboardComponent } from './dashboard.component';
+import { DashboardComponent } from "./dashboard.component";
+import { RouterTestingModule } from "@angular/router/testing";
+import { NO_ERRORS_SCHEMA } from "@angular/core";
+import { RouterLinkWithHref } from "@angular/router";
 
-describe('DashboardComponent', () => {
+describe("DashboardComponent", () => {
   let component: DashboardComponent;
   let fixture: ComponentFixture<DashboardComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ DashboardComponent ]
-    })
-    .compileComponents();
+      imports: [RouterTestingModule],
+      declarations: [DashboardComponent],
+      schemas: [NO_ERRORS_SCHEMA]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +23,7 @@ describe('DashboardComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
 });

+ 8 - 19
src/app/components/dashboard/dashboard.component.ts

@@ -1,29 +1,18 @@
-import { ActivatedRoute, Router } from '@angular/router';
-import { Component, OnInit, Input, Output, EventEmitter, OnDestroy, NgZone, ViewChild } from '@angular/core';
-import {MatPaginator} from '@angular/material/paginator';
-import {MatSort} from '@angular/material/sort';
-import {MatTableDataSource} from '@angular/material/table';
-
-import { of as observableOf, Observable, throwError, from } from 'rxjs';
-
-import * as moment from 'moment';
-import Swal from 'sweetalert2';
-
+import { ActivatedRoute, Router } from "@angular/router";
+import { Component, OnInit } from "@angular/core";
+import Swal from "sweetalert2";
 
 @Component({
-  selector: 'app-dashboard',
-  templateUrl: './dashboard.component.html',
-  styleUrls: ['./dashboard.component.scss']
+  selector: "app-dashboard",
+  templateUrl: "./dashboard.component.html",
+  styleUrls: ["./dashboard.component.scss"]
 })
 export class DashboardComponent implements OnInit {
-
   title = "Dashboard";
 
-
-  constructor() {  }
+  constructor() {}
 
   ngOnInit(): void {
-    Swal.close()
+    Swal.close();
   }
-
 }

+ 174 - 0
src/app/components/instruments/anc/anc.component.html

@@ -0,0 +1,174 @@
+<h4 class="card-title">
+  ACCIONES NACIONALES
+</h4>
+<!--
+<form
+  class="form-auth-small ng-untouched ng-pristine ng-valid"
+  [formGroup]="investmentProposalForm"
+>
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="precio_limpio">Precio Limpio: </label>
+        <input
+          type="text"
+          formControlName="precio_limpio"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.precio_limpio.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.precio_limpio.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.precio_limpio.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="unidades">Unidades: </label>
+        <input
+          type="text"
+          formControlName="unidades"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.unidades.errors
+          }"
+        />
+        <div *ngIf="submitted && f.unidades.errors" class="invalid-feedback">
+          <div *ngIf="f.unidades.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="comision_casa">Comisión Casa: </label>
+        <input
+          type="text"
+          formControlName="comision_casa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_casa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_casa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_casa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="comision_bolsa">Comisión Bolsa: </label>
+        <input
+          type="text"
+          formControlName="comision_bolsa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_bolsa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_bolsa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_bolsa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <br />
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_operacion">Fecha Operación: </label>
+        <div class="input-box-container">
+          <p>
+            <i class="far fa-calendar" aria-hidden="true"></i>
+          </p>
+          <input
+            class="input-box form-control"
+            placeholder="Seleccione una fecha"
+            angular-mydatepicker
+            name="fecha_operacion"
+            (click)="dp.toggleCalendar()"
+            [options]="myDpOptions"
+            (dateChanged)="onDateChanged($event)"
+            #dp="angular-mydatepicker"
+            [ngClass]="{
+              'is-invalid': submitted && f.fecha_operacion.errors
+            }"
+          />
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_operacion.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_liquidacion.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_vencimiento">Fecha Vencimiento: </label>
+
+        <div class="input-box-container">
+          <div>
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              name="fecha_vencimiento"
+              (click)="dp1.toggleCalendar()"
+              [options]="myDpOptions"
+              (dateChanged)="onDateChanged($event)"
+              #dp1="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_vencimiento.errors
+              }"
+            />
+          </div>
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_vencimiento.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_vencimiento.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <br />
+  <div class="form-group text-center space-20">
+    <button
+      class="btn btn-primary center-component margin-right"
+      (click)="goToNext(investmentProposalForm)"
+    >
+      Siguiente
+    </button>
+  </div>
+
+
+</form>
+-->

+ 87 - 0
src/app/components/instruments/anc/anc.component.ts

@@ -0,0 +1,87 @@
+import { Component, OnInit, Input } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+
+@Component({
+  selector: "app-anc",
+  templateUrl: "./anc.component.html"
+})
+export class ANCComponent implements InstrumentComponent {
+  title: string = "Acciones nacionales comunes";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService
+  ) {
+    console.log("init");
+
+    this.investmentProposalForm = this.formBuilder.group({
+      precio_limpio: ["", Validators.required],
+      unidades: ["", Validators.required],
+      comision_casa: ["", Validators.required],
+      comision_bolsa: ["", Validators.required],
+      fecha_operacion: ["", Validators.required],
+      fecha_vencimiento: ["", Validators.required]
+    });
+  }
+
+  save(form: any): boolean {
+    /*if (!form.valid) {
+      return false;
+    }*/
+    this.formDataService.setWork(this.investmentProposalForm.value);
+    return true;
+  }
+
+  goToNext(form: any) {
+    if (this.save(form)) {
+      console.log("all good");
+      // Navigate to the work page
+      this.router.navigate(["/address"]);
+    }
+  }
+}

+ 174 - 0
src/app/components/instruments/apn/apn.component.html

@@ -0,0 +1,174 @@
+<h4 class="card-title">
+  ACCIONES PREFERENTES NACIONALES
+</h4>
+
+<!--
+<form
+  class="form-auth-small ng-untouched ng-pristine ng-valid"
+  [formGroup]="investmentProposalForm"
+>
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="precio_limpio">Precio Limpio: </label>
+        <input
+          type="text"
+          formControlName="precio_limpio"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.precio_limpio.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.precio_limpio.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.precio_limpio.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="unidades">Unidades: </label>
+        <input
+          type="text"
+          formControlName="unidades"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.unidades.errors
+          }"
+        />
+        <div *ngIf="submitted && f.unidades.errors" class="invalid-feedback">
+          <div *ngIf="f.unidades.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="comision_casa">Comisión Casa: </label>
+        <input
+          type="text"
+          formControlName="comision_casa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_casa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_casa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_casa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="comision_bolsa">Comisión Bolsa: </label>
+        <input
+          type="text"
+          formControlName="comision_bolsa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_bolsa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_bolsa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_bolsa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <br />
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_operacion">Fecha Operación: </label>
+        <div class="input-box-container">
+          <p>
+            <i class="far fa-calendar" aria-hidden="true"></i>
+          </p>
+          <input
+            class="input-box form-control"
+            placeholder="Seleccione una fecha"
+            angular-mydatepicker
+            name="fecha_operacion"
+            (click)="dp.toggleCalendar()"
+            [options]="myDpOptions"
+            (dateChanged)="onDateChanged($event)"
+            #dp="angular-mydatepicker"
+            [ngClass]="{
+              'is-invalid': submitted && f.fecha_operacion.errors
+            }"
+          />
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_operacion.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_liquidacion.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_vencimiento">Fecha Vencimiento: </label>
+
+        <div class="input-box-container">
+          <div>
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              name="fecha_vencimiento"
+              (click)="dp1.toggleCalendar()"
+              [options]="myDpOptions"
+              (dateChanged)="onDateChanged($event)"
+              #dp1="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_vencimiento.errors
+              }"
+            />
+          </div>
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_vencimiento.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_vencimiento.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <br />
+  <div class="form-group text-center space-20">
+    <button
+      class="btn btn-primary center-component margin-right"
+      (click)="goToNext(investmentProposalForm)"
+    >
+      Siguiente
+    </button>
+  </div>
+
+</form>
+-->

+ 89 - 0
src/app/components/instruments/apn/apn.component.ts

@@ -0,0 +1,89 @@
+import { Component, OnInit, Input } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+
+@Component({
+  selector: "app-apn",
+  templateUrl: "./apn.component.html"
+})
+export class APNComponent implements InstrumentComponent {
+  title: string = "Acciones preferentes nacionales";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService
+  ) {
+    console.log("init");
+
+    this.investmentProposalForm = this.formBuilder.group({
+      precio_limpio: ["", Validators.required],
+      unidades: ["", Validators.required],
+      comision_casa: ["", Validators.required],
+      comision_bolsa: ["", Validators.required],
+      fecha_operacion: ["", Validators.required],
+      fecha_vencimiento: ["", Validators.required]
+    });
+  }
+
+  save(form: any): boolean {
+    /*if (!form.valid) {
+      return false;
+    }*/
+    console.log(this.investmentProposalForm.value);
+    this.formDataService.setWork(this.investmentProposalForm.value);
+    return true;
+  }
+
+  goToNext(form: any) {
+    if (this.save(form)) {
+      console.log("all good");
+      // Navigate to the work page
+      console.log(this.formDataService.getWork());
+      this.router.navigate(["/address"]);
+    }
+  }
+}

+ 289 - 0
src/app/components/instruments/bonos/bonos.component.html

@@ -0,0 +1,289 @@
+BONOS FORM
+<h4 class="card-title">
+  BONO
+</h4>
+<!--
+<form
+  class="form-auth-small ng-untouched ng-pristine ng-valid"
+  [formGroup]="investmentProposalForm"
+>
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="valor_nominal">Valor nominal: </label>
+        <input
+          type="text"
+          formControlName="valor_nominal"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.valor_nominal.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.valor_nominal.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.valor_nominal.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="ytm_vencimiento">YTM al vencimiento: </label>
+        <input
+          type="text"
+          formControlName="ytm_vencimiento"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.ytm_vencimiento.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.ytm_vencimiento.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.ytm_vencimiento.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="precio_c_v">Precio Compra/Venta: </label>
+        <input
+          type="text"
+          formControlName="precio_c_v"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.precio_c_v.errors
+          }"
+        />
+        <div *ngIf="submitted && f.precio_c_v.errors" class="invalid-feedback">
+          <div *ngIf="f.precio_c_v.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="precio_vencimiento">Precio al vencimiento: </label>
+        <input
+          type="text"
+          formControlName="precio_vencimiento"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.precio_vencimiento.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.precio_vencimiento.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.precio_vencimiento.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <br />
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_liquidacion">Fecha Liquidación: </label>
+        <div class="input-box-container">
+          <p>
+            <i class="far fa-calendar" aria-hidden="true"></i>
+          </p>
+          <input
+            class="input-box form-control"
+            placeholder="Seleccione una fecha"
+            angular-mydatepicker
+            name="fecha_liquidacion"
+            (click)="dp.toggleCalendar()"
+            [options]="myDpOptions"
+            (dateChanged)="onDateChanged($event)"
+            #dp="angular-mydatepicker"
+            [ngClass]="{
+              'is-invalid': submitted && f.fecha_liquidacion.errors
+            }"
+          />
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_liquidacion.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_liquidacion.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="fecha_vencimiento">Fecha Vencimiento: </label>
+
+        <div class="input-box-container">
+          <div>
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              name="fecha_vencimiento"
+              (click)="dp1.toggleCalendar()"
+              [options]="myDpOptions"
+              (dateChanged)="onDateChanged($event)"
+              #dp1="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_vencimiento.errors
+              }"
+            />
+          </div>
+        </div>
+
+        <div
+          *ngIf="submitted && f.fecha_vencimiento.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.fecha_vencimiento.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="fecha_cupon">Última Fecha Cupón: </label>
+
+        <div class="input-box-container">
+          <div>
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              name="fecha_cupon"
+              (click)="dp2.toggleCalendar()"
+              [options]="myDpOptions"
+              (dateChanged)="onDateChanged($event)"
+              #dp2="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_cupon.errors
+              }"
+            />
+          </div>
+        </div>
+
+        <div *ngIf="submitted && f.fecha_cupon.errors" class="invalid-feedback">
+          <div *ngIf="f.fecha_cupon.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+
+  <div class="row">
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="comision_casa">Comisión Casa: </label>
+        <input
+          type="text"
+          formControlName="comision_casa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_casa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_casa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_casa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="comision_bolsa">Comisión Bolsa: </label>
+        <input
+          type="text"
+          formControlName="comision_bolsa"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.comision_bolsa.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.comision_bolsa.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.comision_bolsa.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="col-lg-6 col-sm-12 pr-xl-5">
+      <div class="form-group">
+        <label for="cupon">Cupón: </label>
+        <input
+          type="text"
+          formControlName="cupon"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.cupon.errors
+          }"
+        />
+        <div *ngIf="submitted && f.cupon.errors" class="invalid-feedback">
+          <div *ngIf="f.cupon.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+
+      <div class="form-group">
+        <label for="costos_transferencia">Costos de Transferencia: </label>
+        <input
+          type="text"
+          formControlName="costos_transferencia"
+          class="form-control"
+          [ngClass]="{
+            'is-invalid': submitted && f.costos_transferencia.errors
+          }"
+        />
+        <div
+          *ngIf="submitted && f.costos_transferencia.errors"
+          class="invalid-feedback"
+        >
+          <div *ngIf="f.costos_transferencia.errors.required">
+            Campo requerido
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <br />
+  <div class="form-group text-center space-20">
+    <button
+      class="btn btn-primary center-component margin-right"
+      (click)="goToNext(investmentProposalForm)"
+    >
+      Siguiente
+    </button>
+  </div>
+
+</form>
+-->

+ 93 - 0
src/app/components/instruments/bonos/bonos.component.ts

@@ -0,0 +1,93 @@
+import { Component, OnInit, Input } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+
+@Component({
+  selector: "app-bonos",
+  templateUrl: "./bonos.component.html"
+})
+export class BonosComponent implements InstrumentComponent {
+  title: string = "Bonos";
+  @Input() summary: boolean;
+
+  @Input() data: any;
+  @Input() investmentID: string;
+
+  form: any;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService
+  ) {
+    console.log("init");
+
+    this.investmentProposalForm = this.formBuilder.group({
+      valor_nominal: ["", Validators.required],
+      ytm_vencimiento: ["", Validators.required],
+      precio_c_v: ["", Validators.required],
+      precio_vencimiento: ["", Validators.required],
+      fecha_liquidacion: ["", Validators.required],
+      fecha_cupon: ["", Validators.required],
+      fecha_vencimiento: ["", Validators.required],
+      comision_casa: ["", Validators.required],
+      comision_bolsa: ["", Validators.required],
+      cupon: ["", Validators.required],
+      costos_transferencia: ["", Validators.required]
+    });
+  }
+
+  save(form: any): boolean {
+    /*if (!form.valid) {
+      return false;
+    }*/
+    this.formDataService.setWork(this.investmentProposalForm.value);
+    return true;
+  }
+
+  goToNext(form: any) {
+    if (this.save(form)) {
+      console.log("all good");
+      // Navigate to the work page
+      this.router.navigate(["/address"]);
+    }
+  }
+}

+ 654 - 0
src/app/components/instruments/cete/cete.component.html

@@ -0,0 +1,654 @@
+<div *ngIf="!summary">
+  <h4 class="card-title">
+    Cete
+  </h4>
+  <form
+    class="form-auth-small ng-untouched ng-pristine ng-valid"
+    [formGroup]="investmentProposalForm"
+  >
+    <div class="row">
+      <!-- Valor nominal -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Valor nominal: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="valor_nominal"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.valor_nominal.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.valor_nominal.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.valor_nominal.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.valor_nominal.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Plazo inversión -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="plazo">Plazo inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-business-time"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="plazo"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.plazo.errors
+              }"
+            />
+            <div *ngIf="submitted && f.plazo.errors" class="invalid-feedback">
+              <div *ngIf="f.plazo.errors.required">
+                Campo requerido
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Comisión casa -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_casa_porcentaje">Comisión casa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_casa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_casa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_casa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_casa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_casa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Comisión bolsa -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_bolsa_porcentaje">Comisión bolsa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_bolsa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_bolsa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_bolsa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Rendimiento bruto -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="rendimiento_bruto">Rendimiento bruto: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="rendimiento_bruto"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.rendimiento_bruto.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.rendimiento_bruto.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.rendimiento_bruto.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.rendimiento_bruto.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Otros Costos -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="otros_costos">Otros costos: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="otros_costos"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.otros_costos.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.otros_costos.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.otros_costos.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.otros_costos.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Fecha operación -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_operacion">Fecha operación: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              formControlName="fecha_operacion"
+              (click)="dp.toggleCalendar()"
+              [options]="myDpOptions"
+              #dp="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_operacion.errors
+              }"
+            />
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_operacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_operacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Fecha liquidación -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_liquidacion">Fecha liquidación: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_liquidacion"
+                (click)="dp1.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp1="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_liquidacion.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_liquidacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_liquidacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Fecha vencimiento -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_vencimiento">Fecha vencimiento: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_vencimiento"
+                (click)="dp2.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp2="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_vencimiento.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_vencimiento.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_vencimiento.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Ultima fecha cupón -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_ultima_cupon">Ultima fecha cupón: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_ultima_cupon"
+                (click)="dp3.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp3="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_ultima_cupon.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_ultima_cupon.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_ultima_cupon.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-12 col-sm-12 pr-xl-12">
+        <div class="form-group text-right">
+          <br />
+          <button
+            type="button"
+            class="btn btn-success center-component"
+            (click)="getCalculations(investmentProposalForm, false)"
+          >
+            Realizar cálculos
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <!-- Calculos del instrumento-->
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Cálculos del instrumento</span
+          >
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Ingreso bruto:</h4>
+          <div class="field">$USD {{ ingreso_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso neto:</h4>
+          <div class="field">$USD {{ ingreso_neto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Valor transado:</h4>
+          <div class="field">$USD {{ valor_transado | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Precio porcentaje:</h4>
+          <div class="field">{{ precio_porcentaje | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Rendimiento neto:</h4>
+          <div class="field">
+            {{ rendimiento_neto | number: "1.2-4" }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Total a pagar:</h4>
+          <div class="field">$USD {{ total_pagar | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision bolsa:</h4>
+          <div class="field">$USD {{ comision_bolsa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision casa:</h4>
+          <div class="field">$USD {{ comision_casa | number: "1.2-4" }}</div>
+        </div>
+      </div>
+    </div>
+    <br />
+    <!-- Tabla de proyecciones del instrumento-->
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource" class="example-table">
+            <!-- Name Column -->
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <!-- Country Column -->
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <!-- Country Column -->
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <!-- Country Column -->
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : row.ingreso_neto
+                }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="form-group text-center space-20">
+      <button
+        type="button"
+        class="btn btn-default center-component margin-right"
+        (click)="goToPrevious()"
+      >
+        Anterior
+      </button>
+      <button
+        type="submit"
+        class="btn btn-primary center-component margin-right"
+        (click)="goToNext(investmentProposalForm)"
+      >
+        Siguiente
+      </button>
+    </div>
+  </form>
+</div>
+
+<div *ngIf="summary">
+  <div class="timeline-body">
+    <div class="row">
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor nominal:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_nominal | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_neto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor transado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_transado | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Total a pagar:</h4>
+        <div class="field">
+          $USD {{ instrument_work.total_pagar | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Precio porcentaje:</h4>
+        <div class="field">
+          {{ instrument_work.precio_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Plazo en días:</h4>
+        <div class="field">
+          {{ instrument_work.plazo }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa (%):</h4>
+        <div class="field">
+          {{ instrument_work.comision_casa_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa (%):</h4>
+        <div class="field">
+          {{ instrument_work.comision_bolsa_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa:</h4>
+        <div class="field">
+          $USD {{ instrument_work.comision_casa | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa:</h4>
+        <div class="field">
+          $USD {{ instrument_work.comision_bolsa | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento bruto:</h4>
+        <div class="field">
+          {{ instrument_work.rendimiento_bruto | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento neto:</h4>
+        <div class="field">
+          {{ instrument_work.rendimiento_neto | number: "1.2-4" }} %
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Otros costos:</h4>
+        <div class="field">
+          $USD {{ instrument_work.otros_costos | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de operación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_operacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de liquidación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_liquidacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha vencimiento:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_vencimiento }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ultima fecha de cupón:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_ultima_cupon }}
+        </div>
+      </div>
+    </div>
+    <br />
+    <div *ngIf="hasProjections" class="instrument-calcs-summary">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge-warning badge-custom-instrument"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource2" class="example-table">
+            <!-- Name Column -->
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <!-- Country Column -->
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <!-- Country Column -->
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <!-- Country Column -->
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : row.ingreso_neto
+                }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 361 - 0
src/app/components/instruments/cete/cete.component.ts

@@ -0,0 +1,361 @@
+import { Component, OnInit, Input, ViewChild } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InstrumentCalculations } from "@app/services/instrument-calculations.service";
+import Swal from "sweetalert2";
+import { GeneralInfo } from "@app/models/investment-proposal-form";
+import { parse } from "date-fns";
+import { MatPaginator } from "@angular/material/paginator";
+import { MatSort } from "@angular/material/sort";
+import { MatTableDataSource } from "@angular/material/table";
+
+@Component({
+  selector: "app-cete",
+  templateUrl: "./cete.component.html"
+})
+export class CETE implements InstrumentComponent {
+  title: string = "Cetes";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  displayedColumns: string[] = [
+    "posicion",
+    "plazo",
+    "fecha_pago",
+    "ingreso_neto"
+  ];
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  form: any;
+  general: GeneralInfo;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  m_fecha_operacion: IMyDateModel;
+  m_fecha_liquidacion: IMyDateModel;
+  m_fecha_rendencion: IMyDateModel;
+
+  submitted: boolean = false;
+  instrument_exists: boolean;
+  instrument_work: any = [];
+  financials: any;
+  base_types: any;
+
+  ingreso_bruto: number = 0.0;
+  ingreso_neto: number = 0.0;
+  valor_transado: number = 0.0;
+  precio_porcentaje: number = 0.0;
+  rendimiento_neto: number = 0.0;
+  total_pagar: number = 0.0;
+  comision_bolsa: number = 0.0;
+  comision_casa: number = 0.0;
+  proyecciones: any;
+
+  ceteObject: {};
+  dataSource = new MatTableDataSource(this.proyecciones);
+  dataSource2 = new MatTableDataSource(this.proyecciones);
+  hasProjections: boolean;
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private instrumentCalcService: InstrumentCalculations,
+    public datepipe: DatePipe
+  ) {
+    this.instrument_work = this.formDataService.getWork();
+    this.instrument_exists = this.instrument_work == undefined;
+    this.general = this.formDataService.getGeneralInfo();
+
+    if (
+      this.instrument_work != undefined &&
+      (this.instrument_work.proyecciones != "" ||
+        this.instrument_work != undefined)
+    ) {
+      this.hasProjections = true;
+      this.dataSource2.data = this.instrument_work.proyecciones;
+      this.dataSource2.paginator = this.paginator;
+      this.dataSource2.sort = this.sort;
+    } else {
+      this.hasProjections = false;
+    }
+
+    this.investmentProposalForm = this.formBuilder.group({
+      valor_nominal: [
+        this.instrument_exists ? "" : this.instrument_work.valor_nominal,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+
+      plazo: [
+        this.instrument_exists ? "" : this.instrument_work.plazo,
+        [Validators.required, Validators.pattern(/^[+]?([0-9]+)$/)]
+      ],
+      comision_casa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_casa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      comision_bolsa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_bolsa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      rendimiento_bruto: [
+        this.instrument_exists ? "" : this.instrument_work.rendimiento_bruto,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      otros_costos: [
+        this.instrument_exists ? 0 : this.instrument_work.rendimiento_bruto,
+        [Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)]
+      ],
+      fecha_liquidacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_liquidacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_liquidacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_vencimiento: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_vencimiento,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_vencimiento
+              }
+            },
+        Validators.required
+      ],
+      fecha_operacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_operacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_operacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_ultima_cupon: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_ultima_cupon,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_ultima_cupon
+              }
+            }
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+
+    this.formDataService.setWork(this.ceteObject);
+    return true;
+  }
+
+  getCalculations(form: any, saveForm: boolean) {
+    this.submitted = true;
+    if (!form.valid) {
+      return false;
+    }
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    this.instrumentCalcService
+      .ceteCalc(
+        "CETE", // Codigo del instrumento
+        {
+          id_tipo_base: this.general.base_anual,
+          id_formato_ingreso: this.general.formato_ingreso,
+          id_periodicidad: this.general.periodicidad
+        },
+        {
+          valor_nominal: +this.f.valor_nominal.value,
+          comision_casa_porcentaje: this.f.comision_casa_porcentaje.value,
+          comision_bolsa_porcentaje: this.f.comision_bolsa_porcentaje.value,
+          plazo: +this.f.plazo.value,
+          rendimiento_bruto: this.f.rendimiento_bruto.value,
+          otros_costos: this.f.otros_costos.value,
+          fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+          fecha_liquidacion: this.f.fecha_liquidacion.value.singleDate
+            .formatted,
+          fecha_ultima_cupon: this.f.fecha_ultima_cupon.value.singleDate
+            .formatted,
+          fecha_vencimiento: this.f.fecha_vencimiento.value.singleDate.formatted
+        }
+      )
+      .subscribe(
+        ans => {
+          console.log(ans);
+          this.ingreso_bruto = ans["result"]["ingreso_bruto"];
+          this.ingreso_neto = ans["result"]["ingreso_neto"];
+          this.valor_transado = ans["result"]["valor_transado"];
+          this.precio_porcentaje = ans["result"]["precio_porcentaje"];
+          this.rendimiento_neto = ans["result"]["rendimiento_neto"];
+          this.total_pagar = ans["result"]["total_pagar"];
+          this.comision_bolsa = ans["result"]["comision_bolsa"];
+          this.comision_casa = ans["result"]["comision_casa"];
+          this.proyecciones = ans["result"]["proyecciones"];
+
+          this.dataSource.data = this.proyecciones;
+          this.dataSource.paginator = this.paginator;
+          this.dataSource.sort = this.sort;
+
+          this.ceteObject = {
+            valor_nominal: this.investmentProposalForm.value.valor_nominal,
+            plazo: this.investmentProposalForm.value.plazo,
+            comision_casa_porcentaje: this.investmentProposalForm.value
+              .comision_casa_porcentaje,
+            comision_bolsa_porcentaje: this.investmentProposalForm.value
+              .comision_bolsa_porcentaje,
+            rendimiento_bruto: this.investmentProposalForm.value
+              .rendimiento_bruto,
+            otros_costos: this.f.otros_costos.value,
+            //renta_porcentaje: this.f.renta_porcentaje.value,
+            //id_formato_ingreso: this.f.formato_ingreso.value,
+            fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+            fecha_liquidacion: this.f.fecha_liquidacion.value.singleDate
+              .formatted,
+            fecha_ultima_cupon: this.f.fecha_ultima_cupon.value.singleDate
+              .formatted,
+            fecha_vencimiento: this.f.fecha_vencimiento.value.singleDate
+              .formatted,
+            ingreso_bruto: this.ingreso_bruto,
+            ingreso_neto: this.ingreso_neto,
+            valor_transado: this.valor_transado,
+            precio_porcentaje: this.precio_porcentaje,
+            rendimiento_neto: this.rendimiento_neto,
+            total_pagar: this.total_pagar,
+            comision_bolsa: this.comision_bolsa,
+            comision_casa: this.comision_casa,
+            proyecciones: this.proyecciones
+          };
+
+          this.formDataService.setWork(this.ceteObject);
+          Swal.close();
+          if (saveForm == true) {
+            if (this.investmentID != undefined) {
+              this.router.navigate(["/investment-proposal/complement-info"], {
+                queryParams: { id: this.investmentID }
+              });
+            } else {
+              this.router.navigate(["/investment-proposal/complement-info"]);
+            }
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: "No su pudo obtener la informacion"
+          });
+          return false;
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentID != undefined) {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: this.investmentID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.getCalculations(form, true);
+  }
+}

+ 522 - 0
src/app/components/instruments/dap/dap.component.html

@@ -0,0 +1,522 @@
+<div *ngIf="!summary">
+  <h4 class="card-title">
+    Depósitos a plazo
+  </h4>
+  <form
+    class="form-auth-small ng-untouched ng-pristine ng-valid"
+    [formGroup]="investmentProposalForm"
+  >
+    <div class="row">
+      <!-- Monto inversion -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="monto_inversion">Monto inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="monto_inversion"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.monto_inversion.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.monto_inversion.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.monto_inversion.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.monto_inversion.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Plazo inversión -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="plazo">Plazo inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-business-time"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="plazo"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.plazo.errors
+              }"
+            />
+            <div *ngIf="submitted && f.plazo.errors" class="invalid-feedback">
+              <div *ngIf="f.plazo.errors.required">
+                Campo requerido
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Tasa -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="tasa_porcentaje">Tasa porcentaje: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="tasa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.tasa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.tasa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.tasa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.tasa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Renta porcentaje -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="renta_porcentaje">Renta porcentaje: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="renta_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.renta_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.renta_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.renta_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.renta_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Fecha operación -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_operacion">Fecha operación: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              formControlName="fecha_operacion"
+              (click)="dp.toggleCalendar()"
+              [options]="myDpOptions"
+              #dp="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_operacion.errors
+              }"
+            />
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_operacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_operacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <!-- Fecha vencimiento -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_vencimiento">Fecha vencimiento: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_vencimiento"
+                (click)="dp2.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp2="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_vencimiento.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_vencimiento.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_vencimiento.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-12 col-sm-12 pr-xl-12">
+        <div class="form-group text-right">
+          <br />
+          <button
+            type="button"
+            class="btn btn-success center-component"
+            (click)="getCalculations(investmentProposalForm, false)"
+          >
+            Realizar cálculos
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <!-- Calculos del instrumento-->
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Cálculos del instrumento</span
+          >
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Monto inversión:</h4>
+          <div class="field">$USD {{ monto_inversion | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Plazo:</h4>
+          <div class="field">{{ plazo }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso bruto:</h4>
+          <div class="field">$USD {{ ingreso_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso neto:</h4>
+          <div class="field">$USD {{ ingreso_neto | number: "1.2-4" }}</div>
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Rendimiento bruto:</h4>
+          <div class="field">{{ rendimiento_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Rendimiento neto:</h4>
+          <div class="field">
+            {{ rendimiento_neto | number: "1.2-4" }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Renta:</h4>
+          <div class="field">$USD {{ renta | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Fecha inicio de vigencia:</h4>
+          <div class="field">{{ fecha_inicio_vigencia }}</div>
+        </div>
+      </div>
+    </div>
+    <br />
+    <!-- Tabla de proyecciones del instrumento-->
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_bruto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso bruto</th>
+              <td mat-cell *matCellDef="let row">
+                $USD
+                {{
+                  row.ingreso_bruto == "" || row.ingreso_bruto == undefined
+                    ? "-"
+                    : (row.ingreso_bruto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.renta == "" || row.renta == undefined
+                    ? "-"
+                    : (row.renta | number: "1.2-4")
+                }}%
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                $USD
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="form-group text-center space-20">
+      <button
+        type="button"
+        class="btn btn-default center-component margin-right"
+        (click)="goToPrevious()"
+      >
+        Anterior
+      </button>
+      <button
+        type="submit"
+        class="btn btn-primary center-component margin-right"
+        (click)="goToNext(investmentProposalForm)"
+      >
+        Siguiente
+      </button>
+    </div>
+
+    <!-- [disabled]="!investmentProposalForm.valid"
+                      <div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
+  </form>
+</div>
+
+<div *ngIf="summary">
+  <div class="timeline-body">
+    <div class="row">
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Monto inversión:</h4>
+        <div class="field">
+          $USD {{ instrument_work.monto_inversion | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Plazo en días:</h4>
+        <div class="field">
+          {{ instrument_work.plazo }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Tasa porcentaje:</h4>
+        <div class="field">
+          {{ instrument_work.tasa_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Renta porcentaje:</h4>
+        <div class="field">
+          {{ instrument_work.renta_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Renta:</h4>
+        <div class="field">
+          $USD {{ instrument_work.renta | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_neto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_neto | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de operación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_operacion }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha vencimiento:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_vencimiento }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha inicio de vigencia:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_inicio_vigencia }}
+        </div>
+      </div>
+    </div>
+    <br />
+    <!-- Tabla de proyecciones del instrumento-->
+    <div class="instrument-calcs-summary">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-warning badge-custom-instrument"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource2" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_bruto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso bruto</th>
+              <td mat-cell *matCellDef="let row">
+                $USD
+                {{
+                  row.ingreso_bruto == "" || row.ingreso_bruto == undefined
+                    ? "-"
+                    : (row.ingreso_bruto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.renta == "" || row.renta == undefined
+                    ? "-"
+                    : (row.renta | number: "1.2-4")
+                }}%
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                $USD
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 302 - 0
src/app/components/instruments/dap/dap.component.ts

@@ -0,0 +1,302 @@
+import { Component, OnInit, Input, ViewChild } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InstrumentCalculations } from "@app/services/instrument-calculations.service";
+import Swal from "sweetalert2";
+import { GeneralInfo } from "@app/models/investment-proposal-form";
+import { parse } from "date-fns";
+import { MatPaginator } from "@angular/material/paginator";
+import { MatSort } from "@angular/material/sort";
+import { MatTableDataSource } from "@angular/material/table";
+
+@Component({
+  selector: "app-dap",
+  templateUrl: "./dap.component.html"
+})
+export class DAP implements InstrumentComponent {
+  title: string = "Depósitos a plazo";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+  general: GeneralInfo;
+
+  displayedColumns: string[] = [
+    "posicion",
+    "plazo",
+    "fecha_pago",
+    "ingreso_bruto",
+    "renta",
+    "ingreso_neto"
+  ];
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  instrument_exists: boolean;
+  instrument_work: any = [];
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  submitted: boolean;
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+  ingreso_bruto: number = 0.0;
+  ingreso_neto: number = 0.0;
+  valor_transado: number = 0.0;
+  precio_porcentaje: number = 0.0;
+  rendimiento_neto: number = 0.0;
+  plazo: number = 0;
+  fecha_inicio_vigencia: string;
+  rendimiento_bruto: number = 0;
+  monto_inversion: number = 0;
+  proyecciones: any;
+  dataSource = new MatTableDataSource(this.proyecciones);
+  dataSource2 = new MatTableDataSource(this.proyecciones);
+
+  dapObject: {};
+  renta: any;
+  hasProjections: boolean;
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private instrumentCalcService: InstrumentCalculations,
+    public datepipe: DatePipe
+  ) {
+    this.instrument_work = this.formDataService.getWork();
+    this.instrument_exists = this.instrument_work == undefined;
+    this.general = this.formDataService.getGeneralInfo();
+
+    if (
+      this.instrument_work != undefined &&
+      (this.instrument_work.proyecciones != "" ||
+        this.instrument_work != undefined)
+    ) {
+      this.hasProjections = true;
+      this.dataSource2.data = this.instrument_work.proyecciones;
+      this.dataSource2.paginator = this.paginator;
+      this.dataSource2.sort = this.sort;
+    } else {
+      this.hasProjections = false;
+    }
+
+    this.investmentProposalForm = this.formBuilder.group({
+      monto_inversion: [
+        this.instrument_exists ? "" : this.instrument_work.monto_inversion,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+
+      renta_porcentaje: [
+        this.instrument_exists ? "" : this.instrument_work.renta_porcentaje,
+        [Validators.required]
+      ],
+      tasa_porcentaje: [
+        this.instrument_exists ? "" : this.instrument_work.tasa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      plazo: [
+        this.instrument_exists ? "" : this.instrument_work.plazo,
+        [Validators.required]
+      ],
+
+      /*formato_ingreso: [
+        this.instrument_exists ? "" : this.instrument_work.formato_ingreso,
+        [Validators.required]
+      ],*/
+
+      fecha_vencimiento: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_vencimiento,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_vencimiento
+              }
+            },
+        Validators.required
+      ],
+      fecha_operacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_operacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_operacion
+              }
+            },
+        Validators.required
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+
+    return true;
+  }
+
+  getCalculations(form: any, saveForm: boolean) {
+    this.submitted = true;
+    if (!form.valid) {
+      return false;
+    }
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    this.instrumentCalcService
+      .dapCalc(
+        "DAP", // Codigo del instrumento
+        {
+          id_tipo_base: this.general.base_anual,
+          id_periodicidad: this.general.periodicidad,
+          id_formato_ingreso: this.general.formato_ingreso
+        },
+        {
+          monto_inversion: +this.f.monto_inversion.value,
+          tasa_porcentaje: +this.f.tasa_porcentaje.value,
+          renta_porcentaje: +this.f.renta_porcentaje.value,
+          plazo: +this.f.plazo.value,
+          //id_formato_ingreso: this.f.formato_ingreso.value,
+          fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+          fecha_vencimiento: this.f.fecha_vencimiento.value.singleDate.formatted
+        }
+      )
+      .subscribe(
+        ans => {
+          this.monto_inversion = ans["result"]["monto_inversion"];
+          this.ingreso_bruto = ans["result"]["ingreso_bruto"];
+          this.ingreso_neto = ans["result"]["ingreso_neto"];
+          this.rendimiento_bruto = ans["result"]["rendimiento_bruto"];
+          this.rendimiento_neto = ans["result"]["rendimiento_neto"];
+          this.plazo = ans["result"]["plazo"];
+          this.fecha_inicio_vigencia = ans["result"]["fecha_inicio_vigencia"];
+          this.renta = ans["result"]["renta"];
+          this.proyecciones = ans["result"]["proyecciones"];
+
+          this.dataSource.data = this.proyecciones;
+          this.dataSource.paginator = this.paginator;
+          this.dataSource.sort = this.sort;
+
+          this.dapObject = {
+            monto_inversion: this.investmentProposalForm.value.monto_inversion,
+            renta_porcentaje: this.investmentProposalForm.value
+              .renta_porcentaje,
+            tasa_porcentaje: this.investmentProposalForm.value.tasa_porcentaje,
+            plazo: +this.investmentProposalForm.value.plazo,
+            ingreso_bruto: this.ingreso_bruto,
+            ingreso_neto: this.ingreso_neto,
+            rendimiento_bruto: this.rendimiento_bruto,
+            rendimiento_neto: this.rendimiento_neto,
+            fecha_inicio_vigencia: this.fecha_inicio_vigencia,
+            renta: this.renta,
+            proyecciones: this.proyecciones,
+
+            fecha_operacion: this.investmentProposalForm.value.fecha_operacion
+              .singleDate.formatted,
+            fecha_vencimiento:
+              this.investmentProposalForm.value.fecha_vencimiento != undefined
+                ? this.investmentProposalForm.value.fecha_vencimiento.singleDate
+                    .formatted
+                : ""
+          };
+          this.formDataService.setWork(this.dapObject);
+          Swal.close();
+          if (saveForm == true) {
+            if (this.investmentID != undefined) {
+              this.router.navigate(["/investment-proposal/complement-info"], {
+                queryParams: { id: this.investmentID }
+              });
+            } else {
+              this.router.navigate(["/investment-proposal/complement-info"]);
+            }
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: "No su pudo obtener la informacion"
+          });
+          return false;
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentID != undefined) {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: this.investmentID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.getCalculations(form, true);
+  }
+}

+ 456 - 0
src/app/components/instruments/lete/lete.component.html

@@ -0,0 +1,456 @@
+<div *ngIf="!summary">
+  <h4 class="card-title">
+    Lete
+  </h4>
+  <form
+    class="form-auth-small ng-untouched ng-pristine ng-valid"
+    [formGroup]="investmentProposalForm"
+  >
+    <div class="row">
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Valor nominal: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="valor_nominal"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.valor_nominal.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.valor_nominal.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.valor_nominal.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.valor_nominal.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="plazo">Plazo inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-business-time"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="plazo"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.plazo.errors
+              }"
+            />
+            <div *ngIf="submitted && f.plazo.errors" class="invalid-feedback">
+              <div *ngIf="f.plazo.errors.required">
+                Campo requerido
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_casa_porcentaje">Comisión casa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_casa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_casa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_casa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_casa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_casa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_bolsa_porcentaje_porcentaje"
+            >Comisión bolsa:
+          </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_bolsa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_bolsa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_bolsa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="rendimiento_bruto">Rendimiento bruto: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="rendimiento_bruto"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.rendimiento_bruto.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.rendimiento_bruto.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.rendimiento_bruto.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.rendimiento_bruto.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_operacion">Fecha operación: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              formControlName="fecha_operacion"
+              (click)="dp.toggleCalendar()"
+              [options]="myDpOptions"
+              #dp="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_operacion.errors
+              }"
+            />
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_operacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_operacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_liquidacion">Fecha liquidación: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_liquidacion"
+                (click)="dp1.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp1="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_liquidacion.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_liquidacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_liquidacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_redencion">Fecha redención: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_redencion"
+                (click)="dp2.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp2="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_redencion.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_redencion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_redencion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+
+        <div class="form-group text-right">
+          <br />
+          <button
+            type="button"
+            class="btn btn-success center-component"
+            (click)="getCalculations(investmentProposalForm, false)"
+          >
+            Realizar cálculos
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Cálculos del instrumento</span
+          >
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Ingreso bruto:</h4>
+          <div class="field">$USD {{ ingreso_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso neto:</h4>
+          <div class="field">$USD {{ ingreso_neto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Valor transado:</h4>
+          <div class="field">$USD {{ valor_transado | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Precio porcentaje:</h4>
+          <div class="field">{{ precio_porcentaje | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Rendimiento neto:</h4>
+          <div class="field">{{ rendimiento_neto | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Total a pagar:</h4>
+          <div class="field">$USD {{ total_pagar | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision bolsa:</h4>
+          <div class="field">$USD {{ comision_bolsa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision casa:</h4>
+          <div class="field">$USD {{ comision_casa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Fecha de vencimiento:</h4>
+          <div class="field">{{ fecha_vencimiento }}</div>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="form-group text-center space-20">
+      <button
+        type="button"
+        class="btn btn-default center-component margin-right"
+        (click)="goToPrevious()"
+      >
+        Anterior
+      </button>
+      <button
+        type="submit"
+        class="btn btn-primary center-component margin-right"
+        (click)="goToNext(investmentProposalForm)"
+      >
+        Siguiente
+      </button>
+    </div>
+
+    <!-- [disabled]="!investmentProposalForm.valid"
+                      <div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
+  </form>
+</div>
+
+<div *ngIf="summary">
+  <div class="timeline-body">
+    <div class="row">
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor nominal:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_nominal | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_neto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor transado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_transado | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ingreso neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.ingreso_neto | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Total a pagar:</h4>
+        <div class="field">
+          $USD {{ instrument_work.total_pagar | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Plazo en días:</h4>
+        <div class="field">
+          {{ instrument_work.plazo }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa (%):</h4>
+        <div class="field">
+          {{ instrument_work.comision_casa_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa (%):</h4>
+        <div class="field">
+          {{ instrument_work.comision_bolsa_porcentaje | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa:</h4>
+        <div class="field">
+          $USD {{ instrument_work.comision_casa | number: "1.2-4" }}
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa:</h4>
+        <div class="field">
+          $USD {{ instrument_work.comision_bolsa | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento bruto:</h4>
+        <div class="field">
+          {{ instrument_work.rendimiento_bruto | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento neto:</h4>
+        <div class="field">
+          {{ instrument_work.rendimiento_neto | number: "1.2-4" }} %
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de operación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_operacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de liquidación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_liquidacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de vencimiento:</h4>
+        <div class="field">
+          {{
+            instrument_work.fecha_vencimiento == ""
+              ? ""
+              : instrument_work.fecha_vencimiento
+          }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de redención:</h4>
+        <div class="field">
+          {{
+            instrument_work.fecha_redencion == ""
+              ? ""
+              : instrument_work.fecha_redencion
+          }}
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 310 - 0
src/app/components/instruments/lete/lete.component.ts

@@ -0,0 +1,310 @@
+import { Component, OnInit, Input } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InstrumentCalculations } from "@app/services/instrument-calculations.service";
+import Swal from "sweetalert2";
+import { GeneralInfo } from "@app/models/investment-proposal-form";
+import { parse } from "date-fns";
+
+@Component({
+  selector: "app-lete",
+  templateUrl: "./lete.component.html"
+})
+export class LETE implements InstrumentComponent {
+  title: string = "Letes";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+  general: GeneralInfo;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  m_fecha_operacion: IMyDateModel;
+  m_fecha_liquidacion: IMyDateModel;
+  m_fecha_rendencion: IMyDateModel;
+
+  submitted: boolean = false;
+  instrument_exists: boolean;
+  instrument_work: any = [];
+  financials: any;
+  base_types: any;
+
+  ingreso_bruto: number = 0.0;
+  ingreso_neto: number = 0.0;
+  valor_transado: number = 0.0;
+  precio_porcentaje: number = 0.0;
+  rendimiento_neto: number = 0.0;
+  total_pagar: number = 0.0;
+  comision_bolsa: number = 0.0;
+  comision_casa: number = 0.0;
+
+  leteObject: {};
+  fecha_vencimiento: string = "-";
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private instrumentCalcService: InstrumentCalculations,
+    public datepipe: DatePipe
+  ) {
+    this.instrument_work = this.formDataService.getWork();
+    this.instrument_exists = this.instrument_work == undefined;
+
+    this.general = this.formDataService.getGeneralInfo();
+
+    console.log("intrument cargado:");
+    console.log(this.instrument_work);
+    console.log(this.general);
+
+    this.investmentProposalForm = this.formBuilder.group({
+      valor_nominal: [
+        this.instrument_exists ? "" : this.instrument_work.valor_nominal,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+
+      plazo: [
+        this.instrument_exists ? "" : this.instrument_work.plazo,
+        [Validators.required, Validators.pattern(/^[+]?([0-9]+)$/)]
+      ],
+      comision_casa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_casa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      comision_bolsa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_bolsa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      rendimiento_bruto: [
+        this.instrument_exists ? "" : this.instrument_work.rendimiento_bruto,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+
+      fecha_liquidacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_liquidacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_liquidacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_operacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_operacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_operacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_redencion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_redencion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_redencion
+              }
+            }
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+
+    this.formDataService.setWork(this.leteObject);
+    return true;
+  }
+
+  getCalculations(form: any, saveForm: boolean) {
+    this.submitted = true;
+    if (!form.valid) {
+      return false;
+    }
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    this.instrumentCalcService
+      .leteCalc(
+        "LETE", // Codigo del instrumento
+        { id_tipo_base: this.general.base_anual },
+        {
+          valor_nominal: +this.f.valor_nominal.value,
+          plazo: +this.f.plazo.value,
+          comision_casa_porcentaje: this.f.comision_casa_porcentaje.value,
+          comision_bolsa_porcentaje: this.f.comision_bolsa_porcentaje.value,
+          rendimiento_bruto: this.f.rendimiento_bruto.value,
+          fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+          fecha_liquidacion: this.f.fecha_liquidacion.value.singleDate.formatted
+        }
+      )
+      .subscribe(
+        ans => {
+          this.ingreso_bruto = ans["result"]["ingreso_bruto"];
+          this.ingreso_neto = ans["result"]["ingreso_neto"];
+          this.valor_transado = ans["result"]["valor_transado"];
+          this.precio_porcentaje = ans["result"]["precio_porcentaje"];
+          this.rendimiento_neto = ans["result"]["rendimiento_neto"];
+          this.total_pagar = ans["result"]["total_pagar"];
+          this.comision_bolsa = ans["result"]["comision_bolsa"];
+          this.comision_casa = ans["result"]["comision_casa"];
+          this.fecha_vencimiento = ans["result"]["fecha_vencimiento"];
+          Swal.close();
+
+          this.leteObject = {
+            valor_nominal: this.investmentProposalForm.value.valor_nominal,
+            plazo: this.investmentProposalForm.value.plazo,
+            comision_casa_porcentaje: this.investmentProposalForm.value
+              .comision_casa_porcentaje,
+            comision_bolsa_porcentaje: this.investmentProposalForm.value
+              .comision_bolsa_porcentaje,
+            rendimiento_bruto: this.investmentProposalForm.value
+              .rendimiento_bruto,
+            ingreso_bruto: this.ingreso_bruto,
+            ingreso_neto: this.ingreso_neto,
+            valor_transado: this.valor_transado,
+            precio_porcentaje: this.precio_porcentaje,
+            rendimiento_neto: this.rendimiento_neto,
+            total_pagar: this.total_pagar,
+            comision_bolsa: this.comision_bolsa,
+            comision_casa: this.comision_casa,
+            fecha_vencimiento: this.fecha_vencimiento,
+            fecha_operacion: this.investmentProposalForm.value.fecha_operacion
+              .singleDate.formatted,
+            fecha_liquidacion:
+              this.investmentProposalForm.value.fecha_liquidacion.singleDate
+                .formatted || "",
+            fecha_redencion:
+              this.investmentProposalForm.value.fecha_redencion == undefined
+                ? this.investmentProposalForm.value.fecha_redencion.singleDate
+                    .formatted
+                : ""
+            /*id_inversion_instrumento:
+        this.instrument_work.id_inversion_instrumento == undefined
+          ? ""
+          : this.instrument_work.id_inversion_instrumento*/
+          };
+
+          this.formDataService.setWork(this.leteObject);
+          Swal.close();
+          if (saveForm == true) {
+            if (this.investmentID != undefined) {
+              this.router.navigate(["/investment-proposal/complement-info"], {
+                queryParams: { id: this.investmentID }
+              });
+            } else {
+              this.router.navigate(["/investment-proposal/complement-info"]);
+            }
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: "No su pudo obtener la informacion"
+          });
+          return false;
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentID != undefined) {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: this.investmentID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.getCalculations(form, true);
+  }
+}

+ 754 - 0
src/app/components/instruments/pbur/pbur.component.html

@@ -0,0 +1,754 @@
+<div *ngIf="!summary">
+  <h4 class="card-title">
+    Papel bursátil
+  </h4>
+  <form
+    class="form-auth-small ng-untouched ng-pristine ng-valid"
+    [formGroup]="investmentProposalForm"
+  >
+    <div class="row">
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group form-check">
+          <input
+            type="checkbox"
+            class="form-check-input"
+            id="valor_par"
+            formControlName="valor_par"
+            [checked]="f.valor_par.value"
+          />
+          <label class="form-check-label" for="valor_par">Valor par</label>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Valor nominal: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="valor_nominal"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.valor_nominal.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.valor_nominal.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.valor_nominal.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.valor_nominal.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="renta_porcentaje">Porcentaje renta: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="renta_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.renta_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.renta_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.renta_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.renta_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_casa_porcentaje">Comisión casa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_casa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_casa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_casa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_casa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_casa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Comisión bolsa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_bolsa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_bolsa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_bolsa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="rendimiento_bruto">Rendimiento bruto: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="rendimiento_bruto"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.rendimiento_bruto.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.rendimiento_bruto.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.rendimiento_bruto.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.rendimiento_bruto.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="otros_costos">Otros costos: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="otros_costos"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.otros_costos.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.otros_costos.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.otros_costos.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- Plazo inversión -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="plazo">Plazo inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-business-time"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="plazo"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.plazo.errors
+              }"
+            />
+            <div *ngIf="submitted && f.plazo.errors" class="invalid-feedback">
+              <div *ngIf="f.plazo.errors.required">
+                Campo requerido
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_operacion">Fecha operación: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              formControlName="fecha_operacion"
+              (click)="dp.toggleCalendar()"
+              [options]="myDpOptions"
+              #dp="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_operacion.errors
+              }"
+            />
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_operacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_operacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_liquidacion">Fecha liquidación: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_liquidacion"
+                (click)="dp1.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp1="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_liquidacion.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_liquidacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_liquidacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_vencimiento">Fecha vencimiento: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_vencimiento"
+                (click)="dp2.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp2="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_vencimiento.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_vencimiento.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_vencimiento.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_ultima_cupon">Ultima fecha cupón: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_ultima_cupon"
+                (click)="dp3.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp3="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_ultima_cupon.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_ultima_cupon.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_ultima_cupon.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-12 col-sm-12 pr-xl-12">
+        <div class="form-group text-right">
+          <br />
+          <button
+            type="button"
+            class="btn btn-success center-component"
+            (click)="getCalculations(investmentProposalForm, false)"
+          >
+            Realizar cálculos
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Cálculos del instrumento</span
+          >
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Ingreso bruto:</h4>
+          <div class="field">$USD {{ ingreso_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso neto:</h4>
+          <div class="field">$USD {{ ingreso_neto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Interes acumulado:</h4>
+          <div class="field">
+            $USD {{ interes_acumulado | number: "1.2-4" }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Plazo:</h4>
+          <div class="field">
+            {{ plazo }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Valor transado:</h4>
+          <div class="field">$USD {{ valor_transado | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Precio porcentaje:</h4>
+          <div class="field">{{ precio_porcentaje | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Rendimiento neto:</h4>
+          <div class="field">{{ rendimiento_neto | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Total a pagar:</h4>
+          <div class="field">$USD {{ total_pagar | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision bolsa:</h4>
+          <div class="field">$USD {{ comision_bolsa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision casa:</h4>
+          <div class="field">$USD {{ comision_casa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Fecha de inicio de vigencia:</h4>
+          <div class="field">{{ fecha_inicio_vigencia }}</div>
+        </div>
+      </div>
+    </div>
+
+    <br />
+
+    <!-- Tabla de proyecciones del instrumento-->
+    <div *ngIf="hasProjections" class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="monto">
+              <th mat-header-cell *matHeaderCellDef>Monto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.monto == "" || row.monto == undefined
+                    ? "-"
+                    : (row.monto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_cedeval">
+              <th mat-header-cell *matHeaderCellDef>Costo CEDEVAL</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_cedeval | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.renta | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_transferencia">
+              <th mat-header-cell *matHeaderCellDef>Costo transferencia</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_transferencia | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_banco">
+              <th mat-header-cell *matHeaderCellDef>Costo banco</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_banco | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="otros_costos">
+              <th mat-header-cell *matHeaderCellDef>Otros costos</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.otros_costos | number: "1.2-4" }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="form-group text-center space-20">
+      <button
+        type="button"
+        class="btn btn-default center-component margin-right"
+        (click)="goToPrevious()"
+      >
+        Anterior
+      </button>
+      <button
+        type="submit"
+        class="btn btn-primary center-component margin-right"
+        (click)="goToNext(investmentProposalForm)"
+      >
+        Siguiente
+      </button>
+    </div>
+
+    <!-- [disabled]="!investmentProposalForm.valid"
+                      <div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
+  </form>
+</div>
+
+<div *ngIf="summary">
+  <div class="timeline-body">
+    <div class="row">
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor par:</h4>
+        <div class="field">
+          {{ instrument_work.valor_par == true ? "Si" : "No" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor nominal:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_nominal | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor transado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_transado | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Precio porcentaje:</h4>
+        <div class="field">
+          {{ instrument_work.precio_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Plazo en días:</h4>
+        <div class="field">
+          {{ instrument_work.plazo }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa:</h4>
+        <div class="field">
+          {{ instrument_work.comision_casa_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa:</h4>
+        <div class="field">
+          {{ instrument_work.comision_bolsa_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_neto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Interés acumulado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.interes_acumulado | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Total a pagar:</h4>
+        <div class="field">
+          $USD {{ instrument_work.total_pagar | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de operación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_operacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de liquidación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_liquidacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha vencimiento:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_vencimiento }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ultima fecha de cupón:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_ultima_cupon }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha inicio de vigencia:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_inicio_vigencia }}
+        </div>
+      </div>
+    </div>
+    <br />
+    <!-- Tabla de proyecciones del instrumento-->
+    <div *ngIf="hasProjections" class="instrument-calcs-summary">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-warning badge-custom-instrument"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource2" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="monto">
+              <th mat-header-cell *matHeaderCellDef>Monto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.monto == "" || row.monto == undefined
+                    ? "-"
+                    : (row.monto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_cedeval">
+              <th mat-header-cell *matHeaderCellDef>Costo CEDEVAL</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_cedeval | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.renta | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_transferencia">
+              <th mat-header-cell *matHeaderCellDef>Costo transferencia</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_transferencia | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_banco">
+              <th mat-header-cell *matHeaderCellDef>Costo banco</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_banco | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="otros_costos">
+              <th mat-header-cell *matHeaderCellDef>Otros costos</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.otros_costos | number: "1.2-4" }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[5, 10, 25, dataSource2.data.length]"
+            [length]="dataSource2.data.length"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 400 - 0
src/app/components/instruments/pbur/pbur.component.ts

@@ -0,0 +1,400 @@
+import { Component, OnInit, Input, ViewChild, OnChanges } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InstrumentCalculations } from "@app/services/instrument-calculations.service";
+import Swal from "sweetalert2";
+import { GeneralInfo } from "@app/models/investment-proposal-form";
+import { parse } from "date-fns";
+import { MatPaginator, MatSort, MatTableDataSource } from "@angular/material";
+
+@Component({
+  selector: "app-pbur",
+  templateUrl: "./pbur.component.html"
+})
+export class PBUR implements InstrumentComponent {
+  title: string = "Papel bursátil";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+  general: GeneralInfo;
+
+  displayedColumns: string[] = [
+    "posicion",
+    "plazo",
+    "fecha_pago",
+    "monto",
+    "ingreso_neto",
+    "costo_cedeval",
+    "renta",
+    "costo_transferencia",
+    "costo_banco",
+    "otros_costos"
+  ];
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  instrument_exists: boolean;
+  instrument_work: any = [];
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  submitted: boolean;
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+  pburObject: {};
+  format_incomes: any;
+  ingreso_bruto: number = 0.0;
+  ingreso_neto: number = 0.0;
+  valor_transado: number = 0.0;
+  precio_porcentaje: number = 0.0;
+  rendimiento_neto: number = 0.0;
+  total_pagar: number = 0.0;
+  comision_bolsa: number = 0.0;
+  comision_casa: number = 0.0;
+  plazo: number = 0;
+  interes_acumulado: number = 0;
+  fecha_inicio_vigencia: string;
+  proyecciones: any;
+  hasProjections: boolean;
+
+  dataSource = new MatTableDataSource(this.proyecciones);
+  dataSource2 = new MatTableDataSource(this.proyecciones);
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private instrumentCalcService: InstrumentCalculations,
+    public datepipe: DatePipe
+  ) {
+    this.instrument_work = this.formDataService.getWork();
+    this.instrument_exists = this.instrument_work == undefined;
+    this.general = this.formDataService.getGeneralInfo();
+
+    if (
+      this.instrument_work != undefined &&
+      this.instrument_work.valor_par == true &&
+      this.instrument_work.proyecciones != undefined
+    ) {
+      this.hasProjections = true;
+      this.dataSource2.data = this.instrument_work.proyecciones;
+      this.dataSource2.paginator = this.paginator;
+      this.dataSource2.sort = this.sort;
+    } else {
+      this.hasProjections = false;
+    }
+
+    //getIncomeFormat
+    this.catalogService.getIncomeFormat().subscribe(res => {
+      this.format_incomes = res;
+    });
+
+    this.investmentProposalForm = this.formBuilder.group({
+      valor_par: [
+        this.instrument_exists ? false : this.instrument_work.valor_par
+      ],
+      valor_nominal: [
+        this.instrument_exists ? "" : this.instrument_work.valor_nominal,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      otros_costos: [
+        this.instrument_exists ? 0 : this.instrument_work.otros_costos,
+        [Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)]
+      ],
+      renta_porcentaje: [
+        this.instrument_exists ? "" : this.instrument_work.renta_porcentaje,
+        [Validators.required]
+      ],
+      comision_casa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_casa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      comision_bolsa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_bolsa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      plazo: [
+        this.instrument_exists ? "" : this.instrument_work.plazo,
+        [Validators.required]
+      ],
+      rendimiento_bruto: [
+        this.instrument_exists ? "" : this.instrument_work.rendimiento_bruto,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      /*formato_ingreso: [
+        this.instrument_exists ? "" : this.instrument_work.formato_ingreso,
+        [Validators.required]
+      ],*/
+      fecha_liquidacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_liquidacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_liquidacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_vencimiento: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_vencimiento,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_vencimiento
+              }
+            },
+        Validators.required
+      ],
+      fecha_operacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_operacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_operacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_ultima_cupon: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_ultima_cupon,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_ultima_cupon
+              }
+            },
+        Validators.required
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+    return true;
+  }
+
+  getCalculations(form: any, saveForm: boolean) {
+    this.submitted = true;
+    if (!form.valid) {
+      return false;
+    }
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    this.instrumentCalcService
+      .vcnCalc(
+        "PBUR", // Codigo del instrumento
+        {
+          id_tipo_base: this.general.base_anual,
+          id_periodicidad: this.general.periodicidad,
+          id_formato_ingreso: this.general.formato_ingreso
+        },
+        {
+          valor_par: this.f.valor_par.value,
+          valor_nominal: +this.f.valor_nominal.value,
+          comision_casa_porcentaje: this.f.comision_casa_porcentaje.value,
+          comision_bolsa_porcentaje: this.f.comision_bolsa_porcentaje.value,
+          rendimiento_bruto: this.f.rendimiento_bruto.value,
+          otros_costos: this.f.otros_costos.value,
+          plazo: this.f.plazo.value,
+          renta_porcentaje: this.f.renta_porcentaje.value,
+          //id_formato_ingreso: this.f.formato_ingreso.value,
+          fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+          fecha_liquidacion: this.f.fecha_liquidacion.value.singleDate
+            .formatted,
+          fecha_ultima_cupon: this.f.fecha_ultima_cupon.value.singleDate
+            .formatted,
+          fecha_vencimiento: this.f.fecha_vencimiento.value.singleDate.formatted
+        }
+      )
+      .subscribe(
+        ans => {
+          this.ingreso_bruto = ans["result"]["ingreso_bruto"];
+          this.ingreso_neto = ans["result"]["ingreso_neto"];
+          this.valor_transado = ans["result"]["valor_transado"];
+          this.precio_porcentaje = ans["result"]["precio_porcentaje"];
+          this.rendimiento_neto = ans["result"]["rendimiento_neto"];
+          this.total_pagar = ans["result"]["total_pagar"];
+          this.comision_bolsa = ans["result"]["comision_bolsa"];
+          this.comision_casa = ans["result"]["comision_casa"];
+          this.plazo = ans["result"]["plazo"];
+          this.interes_acumulado = ans["result"]["interes_acumulado"];
+          this.fecha_inicio_vigencia = ans["result"]["fecha_inicio_vigencia"];
+          this.proyecciones = ans["result"]["proyecciones"];
+
+          if (this.f.valor_par.value == true) {
+            this.hasProjections = true;
+          } else {
+            this.hasProjections = false;
+          }
+
+          this.dataSource.data = this.proyecciones;
+          this.dataSource.paginator = this.paginator;
+          this.dataSource.sort = this.sort;
+
+          this.pburObject = {
+            valor_par: this.investmentProposalForm.value.valor_par,
+            valor_nominal: this.investmentProposalForm.value.valor_nominal,
+            renta_porcentaje: this.investmentProposalForm.value
+              .renta_porcentaje,
+            comision_casa_porcentaje: this.investmentProposalForm.value
+              .comision_casa_porcentaje,
+            comision_bolsa_porcentaje: this.investmentProposalForm.value
+              .comision_bolsa_porcentaje,
+            comision_casa: this.comision_casa,
+            comision_bolsa: this.comision_bolsa,
+            rendimiento_bruto: this.investmentProposalForm.value
+              .rendimiento_bruto,
+            otros_costos: this.investmentProposalForm.value.otros_costos,
+            ingreso_bruto: this.ingreso_bruto,
+            ingreso_neto: this.ingreso_neto,
+
+            valor_transado: this.valor_transado,
+            precio_porcentaje: this.precio_porcentaje,
+            rendimiento_neto: this.rendimiento_neto,
+            total_pagar: this.total_pagar,
+            interes_acumulado: this.interes_acumulado,
+            fecha_inicio_vigencia: this.fecha_inicio_vigencia,
+            proyecciones: this.proyecciones,
+            plazo: this.investmentProposalForm.value.plazo,
+            //id_formato_ingreso: this.investmentProposalForm.value.id_formato_ingreso,
+
+            fecha_operacion: this.investmentProposalForm.value.fecha_operacion
+              .singleDate.formatted,
+            fecha_liquidacion:
+              this.investmentProposalForm.value.fecha_liquidacion.singleDate
+                .formatted || "",
+            fecha_ultima_cupon:
+              this.investmentProposalForm.value.fecha_ultima_cupon != undefined
+                ? this.investmentProposalForm.value.fecha_ultima_cupon
+                    .singleDate.formatted
+                : "",
+            fecha_vencimiento:
+              this.investmentProposalForm.value.fecha_vencimiento != undefined
+                ? this.investmentProposalForm.value.fecha_vencimiento.singleDate
+                    .formatted
+                : ""
+          };
+          this.formDataService.setWork(this.pburObject);
+          Swal.close();
+          if (saveForm == true) {
+            if (this.investmentID != undefined) {
+              this.router.navigate(["/investment-proposal/complement-info"], {
+                queryParams: { id: this.investmentID }
+              });
+            } else {
+              this.router.navigate(["/investment-proposal/complement-info"]);
+            }
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: "No su pudo obtener la informacion"
+          });
+          return false;
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentID != undefined) {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: this.investmentID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.getCalculations(form, true);
+  }
+}

+ 756 - 0
src/app/components/instruments/vcn/vcn.component.html

@@ -0,0 +1,756 @@
+<div *ngIf="!summary">
+  <h4 class="card-title">
+    Valor comercial negociable
+  </h4>
+  <form
+    class="form-auth-small ng-untouched ng-pristine ng-valid"
+    [formGroup]="investmentProposalForm"
+  >
+    <div class="row">
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group form-check">
+          <input
+            type="checkbox"
+            class="form-check-input"
+            id="valor_par"
+            formControlName="valor_par"
+            [checked]="f.valor_par.value"
+          />
+          <label class="form-check-label" for="valor_par">Valor par</label>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Valor nominal: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="valor_nominal"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.valor_nominal.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.valor_nominal.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.valor_nominal.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.valor_nominal.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="renta_porcentaje">Porcentaje renta: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="renta_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.renta_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.renta_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.renta_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.renta_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="comision_casa_porcentaje">Comisión casa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_casa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_casa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_casa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_casa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_casa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="valor_nominal">Comisión bolsa: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="comision_bolsa_porcentaje"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.comision_bolsa_porcentaje.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.comision_bolsa_porcentaje.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.comision_bolsa_porcentaje.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="rendimiento_bruto">Rendimiento bruto: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-percent" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="rendimiento_bruto"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.rendimiento_bruto.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.rendimiento_bruto.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.rendimiento_bruto.errors.required">
+                Campo requerido
+              </div>
+              <div *ngIf="f.rendimiento_bruto.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="otros_costos">Otros costos: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-dollar-sign" aria-hidden="true"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="otros_costos"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.otros_costos.errors
+              }"
+            />
+            <div
+              *ngIf="submitted && f.otros_costos.errors"
+              class="invalid-feedback"
+            >
+              <div *ngIf="f.otros_costos.errors.pattern">
+                Debe ingresar una cifra válida
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- Plazo inversión -->
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="plazo">Plazo inversión: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="fas fa-business-time"></i>
+            </p>
+            <input
+              type="text"
+              formControlName="plazo"
+              class="form-control"
+              [ngClass]="{
+                'is-invalid': submitted && f.plazo.errors
+              }"
+            />
+            <div *ngIf="submitted && f.plazo.errors" class="invalid-feedback">
+              <div *ngIf="f.plazo.errors.required">
+                Campo requerido
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_operacion">Fecha operación: </label>
+          <div class="input-box-container">
+            <p>
+              <i class="far fa-calendar" aria-hidden="true"></i>
+            </p>
+            <input
+              class="input-box form-control"
+              placeholder="Seleccione una fecha"
+              angular-mydatepicker
+              formControlName="fecha_operacion"
+              (click)="dp.toggleCalendar()"
+              [options]="myDpOptions"
+              #dp="angular-mydatepicker"
+              [ngClass]="{
+                'is-invalid': submitted && f.fecha_operacion.errors
+              }"
+            />
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_operacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_operacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_liquidacion">Fecha liquidación: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_liquidacion"
+                (click)="dp1.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp1="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_liquidacion.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_liquidacion.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_liquidacion.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_vencimiento">Fecha vencimiento: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_vencimiento"
+                (click)="dp2.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp2="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_vencimiento.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_vencimiento.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_vencimiento.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-6 col-sm-12 pr-xl-3">
+        <div class="form-group">
+          <label for="fecha_ultima_cupon">Ultima fecha cupón: </label>
+
+          <div class="input-box-container">
+            <div>
+              <p>
+                <i class="far fa-calendar" aria-hidden="true"></i>
+              </p>
+              <input
+                class="input-box form-control"
+                placeholder="Seleccione una fecha"
+                angular-mydatepicker
+                formControlName="fecha_ultima_cupon"
+                (click)="dp3.toggleCalendar()"
+                [options]="myDpOptions"
+                #dp3="angular-mydatepicker"
+                [ngClass]="{
+                  'is-invalid': submitted && f.fecha_ultima_cupon.errors
+                }"
+              />
+            </div>
+          </div>
+
+          <div
+            *ngIf="submitted && f.fecha_ultima_cupon.errors"
+            class="invalid-feedback"
+          >
+            <div *ngIf="f.fecha_ultima_cupon.errors.required">
+              Campo requerido
+            </div>
+          </div>
+        </div>
+      </div>
+
+      <div class="col-lg-12 col-sm-12 pr-xl-12">
+        <div class="form-group text-right">
+          <br />
+          <button
+            type="button"
+            class="btn btn-success center-component"
+            (click)="getCalculations(investmentProposalForm, false)"
+          >
+            Realizar cálculos
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Cálculos del instrumento</span
+          >
+        </div>
+
+        <div class="col-sm-6">
+          <h4>Ingreso bruto:</h4>
+          <div class="field">$USD {{ ingreso_bruto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Ingreso neto:</h4>
+          <div class="field">$USD {{ ingreso_neto | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Interes acumulado:</h4>
+          <div class="field">
+            {{ interes_acumulado | number: "1.2-4" }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Plazo:</h4>
+          <div class="field">
+            {{ plazo }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Valor transado:</h4>
+          <div class="field">$USD {{ valor_transado | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Precio porcentaje:</h4>
+          <div class="field">
+            {{ precio_porcentaje | number: "1.2-4" }}
+          </div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Rendimiento neto:</h4>
+          <div class="field">{{ rendimiento_neto | number: "1.2-4" }} %</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Total a pagar:</h4>
+          <div class="field">$USD {{ total_pagar | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision bolsa:</h4>
+          <div class="field">$USD {{ comision_bolsa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Comision casa:</h4>
+          <div class="field">$USD {{ comision_casa | number: "1.2-4" }}</div>
+        </div>
+        <div class="col-sm-6">
+          <h4>Fecha de inicio de vigencia:</h4>
+          <div class="field">{{ fecha_inicio_vigencia }}</div>
+        </div>
+      </div>
+    </div>
+
+    <br />
+
+    <!-- Tabla de proyecciones del instrumento-->
+    <div *ngIf="hasProjections" class="instrument-calcs">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-success badge-custom"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="monto">
+              <th mat-header-cell *matHeaderCellDef>Monto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.monto == "" || row.monto == undefined
+                    ? "-"
+                    : (row.monto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_cedeval">
+              <th mat-header-cell *matHeaderCellDef>Costo CEDEVAL</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_cedeval | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.renta | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_transferencia">
+              <th mat-header-cell *matHeaderCellDef>Costo transferencia</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_transferencia | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_banco">
+              <th mat-header-cell *matHeaderCellDef>Costo banco</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_banco | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="otros_costos">
+              <th mat-header-cell *matHeaderCellDef>Otros costos</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.otros_costos | number: "1.2-4" }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[10, 15, 25]"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+
+    <br />
+    <div class="form-group text-center space-20">
+      <button
+        type="button"
+        class="btn btn-default center-component margin-right"
+        (click)="goToPrevious()"
+      >
+        Anterior
+      </button>
+      <button
+        type="submit"
+        class="btn btn-primary center-component margin-right"
+        (click)="goToNext(investmentProposalForm)"
+      >
+        Siguiente
+      </button>
+    </div>
+
+    <!-- [disabled]="!investmentProposalForm.valid"
+                      <div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
+  </form>
+</div>
+
+<div *ngIf="summary">
+  <div class="timeline-body">
+    <div class="row">
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor par:</h4>
+        <div class="field">
+          {{ instrument_work.valor_par == true ? "Si" : "No" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor nominal:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_nominal | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Valor transado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.valor_transado | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Precio porcentaje:</h4>
+        <div class="field">
+          {{ instrument_work.precio_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Plazo en días:</h4>
+        <div class="field">
+          {{ instrument_work.plazo }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión casa:</h4>
+        <div class="field">
+          {{ instrument_work.comision_casa_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Comisión bolsa:</h4>
+        <div class="field">
+          {{ instrument_work.comision_bolsa_porcentaje | number: "1.2-4" }}%
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento bruto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_bruto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Rendimiento neto:</h4>
+        <div class="field">
+          $USD {{ instrument_work.rendimiento_neto | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Interés acumulado:</h4>
+        <div class="field">
+          $USD {{ instrument_work.interes_acumulado | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Total a pagar:</h4>
+        <div class="field">
+          $USD {{ instrument_work.total_pagar | number: "1.2-4" }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de operación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_operacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha de liquidación:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_liquidacion }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha vencimiento:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_vencimiento }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Ultima fecha de cupón:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_ultima_cupon }}
+        </div>
+      </div>
+      <div class="col-lg-3 col-md-4 col-sm-6">
+        <h4>Fecha inicio de vigencia:</h4>
+        <div class="field">
+          {{ instrument_work.fecha_inicio_vigencia }}
+        </div>
+      </div>
+    </div>
+    <br />
+    <!-- Tabla de proyecciones del instrumento-->
+    <div *ngIf="hasProjections" class="instrument-calcs-summary">
+      <div class="row">
+        <div class="col-12">
+          <span class="badge badge-warning badge-custom-instrument"
+            >Proyecciones del instrumento</span
+          >
+        </div>
+
+        <div class="cete-table-container">
+          <table mat-table [dataSource]="dataSource2" class="example-table">
+            <ng-container matColumnDef="posicion">
+              <th mat-header-cell *matHeaderCellDef>#</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.posicion }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="plazo">
+              <th mat-header-cell *matHeaderCellDef>Plazo</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.plazo }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="fecha_pago">
+              <th mat-header-cell *matHeaderCellDef>Fecha pago</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.fecha_pago == "" || row.fecha_pago == undefined
+                    ? "-"
+                    : row.fecha_pago
+                }}
+              </td>
+            </ng-container>
+
+            <ng-container matColumnDef="monto">
+              <th mat-header-cell *matHeaderCellDef>Monto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.monto == "" || row.monto == undefined
+                    ? "-"
+                    : (row.monto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="ingreso_neto">
+              <th mat-header-cell *matHeaderCellDef>Ingreso neto</th>
+              <td mat-cell *matCellDef="let row">
+                {{
+                  row.ingreso_neto == "" || row.ingreso_neto == undefined
+                    ? "-"
+                    : (row.ingreso_neto | number: "1.2-4")
+                }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_cedeval">
+              <th mat-header-cell *matHeaderCellDef>Costo CEDEVAL</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_cedeval | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="renta">
+              <th mat-header-cell *matHeaderCellDef>Renta</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.renta | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_transferencia">
+              <th mat-header-cell *matHeaderCellDef>Costo transferencia</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_transferencia | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="costo_banco">
+              <th mat-header-cell *matHeaderCellDef>Costo banco</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.costo_banco | number: "1.2-4" }}
+              </td>
+            </ng-container>
+            <ng-container matColumnDef="otros_costos">
+              <th mat-header-cell *matHeaderCellDef>Otros costos</th>
+              <td mat-cell *matCellDef="let row">
+                {{ row.otros_costos | number: "1.2-4" }}
+              </td>
+            </ng-container>
+
+            <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+            <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
+          </table>
+
+          <mat-paginator
+            [pageSizeOptions]="[5, 10, 25, dataSource2.data.length]"
+            [length]="dataSource2.data.length"
+            [pageIndex]="0"
+            [pageSize]="10"
+          ></mat-paginator>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 402 - 0
src/app/components/instruments/vcn/vcn.component.ts

@@ -0,0 +1,402 @@
+import { Component, OnInit, Input, ViewChild } from "@angular/core";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { Router } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InstrumentCalculations } from "@app/services/instrument-calculations.service";
+import Swal from "sweetalert2";
+import { GeneralInfo } from "@app/models/investment-proposal-form";
+import { parse } from "date-fns";
+import { MatTableDataSource, MatPaginator, MatSort } from "@angular/material";
+
+@Component({
+  selector: "app-vcn",
+  templateUrl: "./vcn.component.html"
+})
+export class VCN implements InstrumentComponent {
+  title: string = "Valores comerciales negociables";
+  @Input() data: any;
+  @Input() summary: boolean;
+  @Input() investmentID: string;
+
+  form: any;
+  general: GeneralInfo;
+
+  displayedColumns: string[] = [
+    "posicion",
+    "plazo",
+    "fecha_pago",
+    "monto",
+    "ingreso_neto",
+    "costo_cedeval",
+    "renta",
+    "costo_transferencia",
+    "costo_banco",
+    "otros_costos"
+  ];
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  instrument_exists: boolean;
+  instrument_work: any = [];
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  submitted: boolean;
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+  vcnObject: {};
+  format_incomes: any;
+  ingreso_bruto: number = 0.0;
+  ingreso_neto: number = 0.0;
+  valor_transado: number = 0.0;
+  precio_porcentaje: number = 0.0;
+  rendimiento_neto: number = 0.0;
+  total_pagar: number = 0.0;
+  comision_bolsa: number = 0.0;
+  comision_casa: number = 0.0;
+  plazo: number = 0;
+  interes_acumulado: number = 0;
+  fecha_inicio_vigencia: string;
+  proyecciones: any;
+  hasProjections: boolean;
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+  dataSource = new MatTableDataSource(this.proyecciones);
+  dataSource2 = new MatTableDataSource(this.proyecciones);
+
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private instrumentCalcService: InstrumentCalculations,
+    public datepipe: DatePipe
+  ) {
+    this.instrument_work = this.formDataService.getWork();
+    this.instrument_exists = this.instrument_work == undefined;
+    this.general = this.formDataService.getGeneralInfo();
+
+    if (
+      this.instrument_work != undefined &&
+      this.instrument_work.valor_par == true &&
+      this.instrument_work.proyecciones != undefined
+    ) {
+      this.hasProjections = true;
+      this.dataSource2.data = this.instrument_work.proyecciones;
+      this.dataSource2.paginator = this.paginator;
+      this.dataSource2.sort = this.sort;
+    } else {
+      this.hasProjections = false;
+    }
+    //getIncomeFormat
+    this.catalogService.getIncomeFormat().subscribe(res => {
+      this.format_incomes = res;
+    });
+
+    this.investmentProposalForm = this.formBuilder.group({
+      valor_par: [
+        this.instrument_exists ? false : this.instrument_work.valor_par
+      ],
+      valor_nominal: [
+        this.instrument_exists ? "" : this.instrument_work.valor_nominal,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      otros_costos: [
+        this.instrument_exists ? 0 : this.instrument_work.otros_costos,
+        [Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)]
+      ],
+      plazo: [
+        this.instrument_exists ? "" : this.instrument_work.plazo,
+        [Validators.required]
+      ],
+      renta_porcentaje: [
+        this.instrument_exists ? "" : this.instrument_work.renta_porcentaje,
+        [Validators.required]
+      ],
+      comision_casa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_casa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      comision_bolsa_porcentaje: [
+        this.instrument_exists
+          ? ""
+          : this.instrument_work.comision_bolsa_porcentaje,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      rendimiento_bruto: [
+        this.instrument_exists ? "" : this.instrument_work.rendimiento_bruto,
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      /*formato_ingreso: [
+        this.instrument_exists ? "" : this.instrument_work.formato_ingreso,
+        [Validators.required]
+      ],*/
+      fecha_liquidacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_liquidacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_liquidacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_vencimiento: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_vencimiento,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_vencimiento
+              }
+            },
+        Validators.required
+      ],
+      fecha_operacion: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_operacion,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_operacion
+              }
+            },
+        Validators.required
+      ],
+      fecha_ultima_cupon: [
+        this.instrument_exists
+          ? ""
+          : {
+              isRange: false,
+              singleDate: {
+                jsDate: parse(
+                  this.instrument_work.fecha_ultima_cupon,
+                  "dd/MM/yyyy",
+                  new Date()
+                ),
+                formatted: this.instrument_work.fecha_ultima_cupon
+              }
+            },
+        Validators.required
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+
+    this.formDataService.setWork(this.vcnObject);
+    return true;
+  }
+
+  getCalculations(form: any, saveForm: boolean) {
+    this.submitted = true;
+    if (!form.valid) {
+      return false;
+    }
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    this.instrumentCalcService
+      .vcnCalc(
+        "VCN", // Codigo del instrumento
+        {
+          id_tipo_base: this.general.base_anual,
+          id_periodicidad: this.general.periodicidad,
+          id_formato_ingreso: this.general.formato_ingreso
+        },
+        {
+          valor_par: this.f.valor_par.value,
+          valor_nominal: +this.f.valor_nominal.value,
+          comision_casa_porcentaje: this.f.comision_casa_porcentaje.value,
+          comision_bolsa_porcentaje: this.f.comision_bolsa_porcentaje.value,
+          rendimiento_bruto: this.f.rendimiento_bruto.value,
+          otros_costos: this.f.otros_costos.value,
+          plazo: this.f.plazo.value,
+          renta_porcentaje: this.f.renta_porcentaje.value,
+          //id_formato_ingreso: this.f.formato_ingreso.value,
+          fecha_operacion: this.f.fecha_operacion.value.singleDate.formatted,
+          fecha_liquidacion: this.f.fecha_liquidacion.value.singleDate
+            .formatted,
+          fecha_ultima_cupon: this.f.fecha_ultima_cupon.value.singleDate
+            .formatted,
+          fecha_vencimiento: this.f.fecha_vencimiento.value.singleDate.formatted
+        }
+      )
+      .subscribe(
+        ans => {
+          this.ingreso_bruto = ans["result"]["ingreso_bruto"];
+          this.ingreso_neto = ans["result"]["ingreso_neto"];
+          this.valor_transado = ans["result"]["valor_transado"];
+          this.precio_porcentaje = ans["result"]["precio_porcentaje"];
+          this.rendimiento_neto = ans["result"]["rendimiento_neto"];
+          this.total_pagar = ans["result"]["total_pagar"];
+          this.comision_bolsa = ans["result"]["comision_bolsa"];
+          this.comision_casa = ans["result"]["comision_casa"];
+          this.plazo = ans["result"]["plazo"];
+          this.interes_acumulado = ans["result"]["interes_acumulado"];
+          this.fecha_inicio_vigencia = ans["result"]["fecha_inicio_vigencia"];
+          this.proyecciones = ans["result"]["proyecciones"];
+
+          if (this.f.valor_par.value == true) {
+            this.hasProjections = true;
+          } else {
+            this.hasProjections = false;
+          }
+
+          this.dataSource.data = this.proyecciones;
+          this.dataSource.paginator = this.paginator;
+          this.dataSource.sort = this.sort;
+
+          this.vcnObject = {
+            valor_par: this.investmentProposalForm.value.valor_par,
+            valor_nominal: this.investmentProposalForm.value.valor_nominal,
+            renta_porcentaje: this.investmentProposalForm.value
+              .renta_porcentaje,
+            comision_casa_porcentaje: this.investmentProposalForm.value
+              .comision_casa_porcentaje,
+            comision_bolsa_porcentaje: this.investmentProposalForm.value
+              .comision_bolsa_porcentaje,
+            comision_casa: this.comision_casa,
+            comision_bolsa: this.comision_bolsa,
+            rendimiento_bruto: this.investmentProposalForm.value
+              .rendimiento_bruto,
+            otros_costos: this.investmentProposalForm.value.otros_costos,
+            ingreso_bruto: this.ingreso_bruto,
+            ingreso_neto: this.ingreso_neto,
+
+            valor_transado: this.valor_transado,
+            precio_porcentaje: this.precio_porcentaje,
+            rendimiento_neto: this.rendimiento_neto,
+            total_pagar: this.total_pagar,
+            interes_acumulado: this.interes_acumulado,
+            fecha_inicio_vigencia: this.fecha_inicio_vigencia,
+            proyecciones: this.proyecciones,
+            plazo: this.investmentProposalForm.value.plazo,
+            //id_formato_ingreso: this.investmentProposalForm.value.id_formato_ingreso,
+
+            fecha_operacion: this.investmentProposalForm.value.fecha_operacion
+              .singleDate.formatted,
+            fecha_liquidacion:
+              this.investmentProposalForm.value.fecha_liquidacion.singleDate
+                .formatted || "",
+            fecha_ultima_cupon:
+              this.investmentProposalForm.value.fecha_ultima_cupon != undefined
+                ? this.investmentProposalForm.value.fecha_ultima_cupon
+                    .singleDate.formatted
+                : "",
+            fecha_vencimiento:
+              this.investmentProposalForm.value.fecha_vencimiento != undefined
+                ? this.investmentProposalForm.value.fecha_vencimiento.singleDate
+                    .formatted
+                : ""
+          };
+          this.formDataService.setWork(this.vcnObject);
+          Swal.close();
+          if (saveForm == true) {
+            if (this.investmentID != undefined) {
+              this.router.navigate(["/investment-proposal/complement-info"], {
+                queryParams: { id: this.investmentID }
+              });
+            } else {
+              this.router.navigate(["/investment-proposal/complement-info"]);
+            }
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: "No su pudo obtener la informacion"
+          });
+          return false;
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentID != undefined) {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: this.investmentID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.getCalculations(form, true);
+  }
+}

+ 189 - 0
src/app/components/investment-proposals/approve/approve.component.html

@@ -0,0 +1,189 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Aprobar</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Resumen de la propuesta
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ul class="timeline timeline-simple">
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-success"
+                          >Información general</span
+                        >
+                      </div>
+                      <div class="timeline-body">
+                        <div class="row">
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Asunto:</h4>
+                            <div class="field">
+                              {{ subject }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Orígenes de fondo:</h4>
+                            <div class="field">
+                              {{ funds }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Nombre:</h4>
+                            <div class="field">
+                              {{ investmentName }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Tasa:</h4>
+                            <div class="field">
+                              {{ rates }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Renta:</h4>
+                            <div class="field">
+                              {{ revenues }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Periodicidad:</h4>
+                            <div class="field">
+                              {{ periodicities }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Instrumentos:</h4>
+                            <div class="field">
+                              {{ instrumentTypes }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Casa:</h4>
+                            <div class="field">
+                              {{ financials }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Base:</h4>
+                            <div class="field">
+                              {{ base_types }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo de mercado:</h4>
+                            <div class="field">
+                              {{ markets }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Emisores:</h4>
+                            <div class="field">
+                              {{ emitters }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Empresa:</h4>
+                            <div class="field">
+                              {{ companies }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>País:</h4>
+                            <div class="field">
+                              {{ countries }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Plazo:</h4>
+                            <div class="field">
+                              {{ payment_terms }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipos de operaciones:</h4>
+                            <div class="field">
+                              {{ operations }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Comentarios:</h4>
+                            <div class="field">
+                              {{ comment }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Justificación:</h4>
+                            <div class="field">
+                              {{ justification }}
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </li>
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-warning">Instrumento</span>
+                        <ng-template instrument-host></ng-template>
+                      </div>
+                    </div>
+                  </li>
+                </ul>
+                <div class="review-buttons">
+                  <button
+                    class="btn btn-danger "
+                    (click)="dismiss_proposal()"
+                    type="button"
+                  >
+                    Rechazar propuesta
+                  </button>
+
+                  <button
+                    class="btn btn-success "
+                    (click)="approve_proposal()"
+                    type="button"
+                  >
+                    Aprobar propuesta
+                  </button>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 6 - 0
src/app/components/investment-proposals/approve/approve.component.scss

@@ -0,0 +1,6 @@
+.review-buttons {
+  text-align: center;
+  button {
+    margin: 0 20px;
+  }
+}

+ 429 - 0
src/app/components/investment-proposals/approve/approve.component.ts

@@ -0,0 +1,429 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "../instrument/instrument.directive";
+import { InstrumentComponent } from "../instrument/instrument.component";
+import { InstrumentsService } from "@app/services/instruments.service";
+import Swal from "sweetalert2";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+
+@Component({
+  selector: "app-investment-proposal-approve",
+  templateUrl: "./approve.component.html",
+  styleUrls: ["./approve.component.scss"]
+})
+export class InvestmentProposalApproveComponent implements OnInit {
+  title = "Aprobación de propuesta";
+  @Input() ads: Instrument[];
+  @Input() formData: InvestmentProposalForm;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  isFormValid: boolean = false;
+  general: any;
+  instrument: any;
+  complement: any;
+  final: any;
+  workType: string;
+  form: any;
+  currentAdIndex = -1;
+  interval: any;
+  indexDynamicComponent: number;
+  investmentProposalID: string;
+  investmentExists;
+  state;
+  financials;
+  base_types;
+  countries;
+  companies;
+  rates;
+  revenues;
+  funds;
+  instrumentTypes;
+  markets;
+  emitters;
+  periodicities;
+  format_incomes;
+  payment_terms;
+  operations;
+  gInfo: any;
+  gInstrument: any;
+  gComplement: any;
+  subject: any;
+  investmentName: any;
+  comment: any;
+  justification: any;
+  reviewProposal: {};
+
+  constructor(
+    private router: Router,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService,
+    private catalogService: CatalogsService,
+    private route: ActivatedRoute,
+    private investmentService: InvestmentsService
+  ) {}
+
+  ngOnInit() {
+    //this.formDataService
+    this.ads = this.loadInstrumentsService.getInstruments();
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    if (this.investmentProposalID != undefined) {
+      this.investmentExists = true;
+      this.investmentService
+        .getProposalInvestment(this.investmentProposalID)
+        .subscribe(res => {
+          this.state = res["result"]["id_estado_inversion"]["codigo"];
+
+          this.gInfo = {
+            asunto: res["result"]["asunto"],
+            origenes_fondo:
+              res["result"]["id_origen_fondo"] == null
+                ? ""
+                : res["result"]["id_origen_fondo"]["id_origen_fondo"],
+            name: res["result"]["nombre_inversion"],
+            //date: "",
+            tipo_tasa: res["result"]["id_tipo_tasa"] || "",
+            tipo_renta:
+              res["result"]["id_tipo_renta"] == null
+                ? ""
+                : res["result"]["id_tipo_renta"]["id_tipo_renta"],
+            periodicidad:
+              res["result"]["id_periodicidad"] == null
+                ? ""
+                : res["result"]["id_periodicidad"]["id_periodicidad"],
+
+            instrumentos:
+              res["result"]["id_inversion_instrumento"]["id_tipo_instrumento"][
+                "codigo"
+              ],
+            base_anual:
+              res["result"]["id_tipo_base"] == null
+                ? ""
+                : res["result"]["id_tipo_base"]["id_tipo_base"],
+            casa:
+              res["result"]["id_entidad"] == null
+                ? ""
+                : res["result"]["id_entidad"]["id_entidad_financiera"],
+            formato_ingreso:
+              res["result"]["id_formato_ingreso"] == null
+                ? ""
+                : res["result"]["id_formato_ingreso"]["id_formato_ingreso"]
+          };
+
+          this.gInstrument =
+            res["result"]["id_inversion_instrumento"]["instrumento"];
+
+          this.gInstrument["id_inversion_instrumento"] =
+            res["result"]["id_inversion_instrumento"][
+              "id_inversion_instrumento"
+            ];
+
+          this.gComplement = {
+            tipo_mercado:
+              res["result"]["id_tipo_mercado"] == null
+                ? ""
+                : res["result"]["id_tipo_mercado"]["id_tipo_mercado"],
+            emisores:
+              res["result"]["id_tipo_emisor"] == null
+                ? ""
+                : res["result"]["id_tipo_emisor"]["id_tipo_emisor"],
+            empresa:
+              res["result"]["id_empresa"] == null
+                ? ""
+                : res["result"]["id_empresa"]["id_empresa"],
+            pais:
+              res["result"]["id_pais"] == null
+                ? ""
+                : res["result"]["id_pais"]["id_pais"],
+            plazo:
+              res["result"]["id_plazo"] == null
+                ? ""
+                : res["result"]["id_plazo"]["id_plazo"],
+            operaciones:
+              res["result"]["id_tipo_operacion"] == null
+                ? ""
+                : res["result"]["id_tipo_operacion"]["id_tipo_operacion"],
+            comentarios: res["result"]["comentario"],
+            justificacion: res["result"]["justificacion"]
+          };
+          this.formDataService.setGeneralInfo(this.gInfo);
+
+          this.formDataService.setWork(this.gInstrument);
+
+          this.formDataService.setComplementInfo(this.gComplement);
+
+          this.general = this.formDataService.getGeneralInfo();
+          this.instrument = this.formDataService.getWork();
+          this.complement = this.formDataService.getComplementInfo();
+          this.formData = this.formDataService.getFormData();
+
+          this.formData.instrumentos;
+
+          this.indexDynamicComponent = this.ads.findIndex(
+            x => x.data.key == this.formData.instrumentos
+          );
+          if (this.indexDynamicComponent >= 0) {
+            this.loadComponent();
+          } else {
+            console.log("No existe el componente");
+          }
+          if (this.general != undefined) {
+            this.subject = this.general.asunto;
+            this.investmentName = this.general.name;
+            this.comment = this.complement.comment;
+            this.justification = this.complement.comment;
+
+            this.catalogService.getFinancialEntities().subscribe(res => {
+              this.financials = res.find(
+                e => e.id_entidad_financiera == this.general.casa
+              );
+              this.financials =
+                this.financials != undefined ? this.financials.nombre : "-";
+            });
+
+            this.catalogService.getBaseTypes().subscribe(res => {
+              this.base_types = res.find(
+                e => e.id_tipo_base == this.general.base_anual
+              );
+              this.base_types =
+                this.base_types != undefined
+                  ? ` ${this.base_types.tipo_base} / ${this.base_types.tipo_base_dias}`
+                  : "-";
+            });
+
+            this.catalogService.getCountries().subscribe(res => {
+              this.countries = res.find(e => e.id_pais == this.complement.pais);
+              this.countries =
+                this.countries != undefined ? this.countries.nombre : "-";
+            });
+            this.catalogService.getCompanies().subscribe(res => {
+              this.companies = res.find(
+                e => e.id_empresa == this.complement.empresa
+              );
+              this.companies =
+                this.companies != undefined ? this.companies.nombre : "-";
+            });
+            this.catalogService.getRateTypes().subscribe(res => {
+              this.rates = res.find(
+                e => e.id_tipo_tasa == this.general.tipo_tasa
+              );
+              this.rates = this.rates != undefined ? this.rates.nombre : "-";
+            });
+            this.catalogService.getRevenueTypes().subscribe(res => {
+              this.revenues = res.find(
+                e => e.id_tipo_renta == this.general.tipo_renta
+              );
+              this.revenues =
+                this.revenues != undefined ? this.revenues.nombre : "-";
+            });
+
+            this.catalogService.getFundsOrigins().subscribe(res => {
+              this.funds = res.find(
+                e => e.id_origen_fondo == this.general.origenes_fondo
+              );
+              this.funds = this.funds != undefined ? this.funds.nombre : "-";
+            });
+            this.catalogService.getInstrumentTypes().subscribe(res => {
+              this.instrumentTypes = res.find(
+                e => e.codigo == this.general.instrumentos
+              );
+              this.instrumentTypes =
+                this.instrumentTypes != undefined
+                  ? this.instrumentTypes.nombre
+                  : "-";
+            });
+
+            this.catalogService.getMarketTypes().subscribe(res => {
+              this.markets = res.find(
+                e => e.id_tipo_mercado == this.complement.tipo_mercado
+              );
+              this.markets =
+                this.markets != undefined ? this.markets.nombre : "-";
+            });
+            this.catalogService.getEmitterTypes().subscribe(res => {
+              this.emitters = res.find(
+                e => e.id_tipo_emisor == this.complement.emisores
+              );
+              this.emitters =
+                this.emitters != undefined ? this.emitters.nombre : "-";
+            });
+            this.catalogService.getPeriodicities().subscribe(res => {
+              this.periodicities = res.find(
+                e => e.id_periodicidad == this.general.periodicidad
+              );
+              this.periodicities =
+                this.periodicities != undefined
+                  ? this.periodicities.nombre
+                  : "-";
+            });
+
+            this.catalogService.getPaymentTerms().subscribe(res => {
+              this.payment_terms = res.find(
+                e => e.codigo == this.complement.calificadora_riesgo
+              );
+              this.payment_terms =
+                this.payment_terms != undefined
+                  ? this.payment_terms.nombre
+                  : "-";
+            });
+            this.catalogService.getOperationTypes().subscribe(res => {
+              this.operations = res.find(
+                e => e.codigo == this.complement.operaciones
+              );
+              this.operations =
+                this.operations != undefined ? this.operations.nombre : "-";
+            });
+            //getIncomeFormat
+            this.catalogService.getIncomeFormat().subscribe(res => {
+              this.format_incomes = res.find(
+                e => e.id_formato_ingreso == this.general.formato_ingreso
+              );
+              this.format_incomes =
+                this.format_incomes != undefined
+                  ? this.format_incomes.nombre
+                  : "-";
+            });
+          }
+        });
+    } else {
+      this.investmentExists = false;
+    }
+  }
+
+  loadComponent() {
+    const adItem = this.ads[this.indexDynamicComponent];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = true;
+  }
+
+  approve_proposal() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Aprobación de propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Enviar propuesta",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendProposalInvestmentToNextStep(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido aprobada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  dismiss_proposal() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Aprobación de propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Rechazar propuesta",
+        confirmButtonColor: "#C82333",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "previous",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendProposalInvestmentToNextStep(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "warning",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido rechazada"
+                  }).then(result => {
+                    window.location.href = "#/investment-proposals";
+                    Swal.close();
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error en el servidor",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+}

+ 155 - 0
src/app/components/investment-proposals/change-history/change-history.component.html

@@ -0,0 +1,155 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Histórico</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Histórico de cambios
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ul class="list-unstyled">
+                  <li class="alert secondary-bg">
+                    <div class="media">
+                      <div class="user-icon">
+                        <i class="material-icons">
+                          person
+                        </i>
+                      </div>
+                      <div class="media-body">
+                        <h6 class="mt-0 ">
+                          Sarahi Garcia
+                          <div class="float-right">07/02/2020 18:00</div>
+                        </h6>
+                        <a href="javascript:void(0);">Modificacion</a>
+                        <p class="mt-10">
+                          Adjunto requisicion de pago.
+                        </p>
+                      </div>
+                    </div>
+                    <div class="divider mt-15"></div>
+                  </li>
+                  <li class="alert info-bg">
+                    <div class="media">
+                      <div class="user-icon clearfix">
+                        <i class="material-icons">
+                          person
+                        </i>
+                      </div>
+                      <div class="media-body">
+                        <h6 class="mt-0 ">
+                          Francisco Huezo
+                          <div class="float-right">07/02/2020 15:00</div>
+                        </h6>
+                        <a href="javascript:void(0);">Modificacion</a>
+                        <p class="mt-10">
+                          Lorem ipsum dolor sit amet consectetur adipisicing
+                          elit. Harum odio omnis dolorum voluptatibus
+                          consequatur atque culpa labore quo excepturi, porro
+                          voluptatum vel dolores sunt reprehenderit libero.
+                          Perspiciatis, accusamus! Nemo, ullam.
+                        </p>
+                      </div>
+                    </div>
+                    <div class="divider mt-15"></div>
+                  </li>
+                  <li class="alert secondary-bg">
+                    <div class="media">
+                      <div class="user-icon">
+                        <i class="material-icons">
+                          person
+                        </i>
+                      </div>
+                      <div class="media-body">
+                        <h6 class="mt-0 ">
+                          Carlos Chavez
+                          <div class="float-right">06/02/2020 13:40</div>
+                        </h6>
+                        <a href="javascript:void(0);">Modificacion</a>
+                        <p class="mt-10">
+                          Cambio el estado a Aprobado
+                        </p>
+                      </div>
+                    </div>
+                    <div class="divider mt-15"></div>
+                  </li>
+                  <li class="alert info-bg">
+                    <div class="media">
+                      <div class="user-icon">
+                        <i class="material-icons">
+                          person
+                        </i>
+                      </div>
+                      <div class="media-body">
+                        <h6 class="mt-0 ">
+                          Oscar Nuñez
+                          <div class="float-right">06/02/2020 08:58</div>
+                        </h6>
+                        <a href="javascript:void(0);">Modificacion</a>
+                        <p class="mt-10">
+                          Lorem, ipsum dolor sit amet consectetur adipisicing
+                          elit. Doloribus obcaecati excepturi mollitia eum nulla
+                          eos temporibus, a praesentium expedita animi nemo
+                          assumenda quasi iusto quas maxime amet recusandae ut!
+                          Id.
+                        </p>
+                      </div>
+                    </div>
+                    <div class="divider mt-15"></div>
+                  </li>
+                  <li class="alert secondary-bg">
+                    <div class="media">
+                      <div class="user-icon">
+                        <i class="material-icons">
+                          person
+                        </i>
+                      </div>
+                      <div class="media-body">
+                        <h6 class="mt-0 ">
+                          Angel Hernandez
+                          <div class="float-right">05/02/2020 10:55</div>
+                        </h6>
+                        <a href="javascript:void(0);">Creacion</a>
+                        <p class="mt-10">
+                          Lorem ipsum dolor sit amet consectetur adipisicing
+                          elit.
+                        </p>
+                      </div>
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 17 - 0
src/app/components/investment-proposals/change-history/change-history.component.scss

@@ -0,0 +1,17 @@
+.user-icon {
+  width: 40px;
+  height: 40px;
+  border: 1px solid #666;
+  line-height: 50px;
+  text-align: center;
+  margin-right: 10px;
+  color: inherit;
+}
+
+.info-bg {
+  background: #a9daf2;
+}
+
+.secondary-bg {
+  background: #ddd;
+}

+ 95 - 0
src/app/components/investment-proposals/change-history/change-history.component.ts

@@ -0,0 +1,95 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router } from "@angular/router";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "../instrument/instrument.directive";
+import { InstrumentComponent } from "../instrument/instrument.component";
+import { InstrumentsService } from "@app/services/instruments.service";
+
+@Component({
+  selector: "app-investment-proposal-changes",
+  templateUrl: "./change-history.component.html",
+  styleUrls: ["./change-history.component.scss"]
+})
+export class ChangeHistoryComponent implements OnInit {
+  title = "Histórico de la propuesta";
+  @Input() ads: Instrument[];
+  @Input() formData: InvestmentProposalForm;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  isFormValid: boolean = false;
+  general: any;
+  instrument: any;
+  complement: any;
+  final: any;
+  workType: string;
+  form: any;
+  currentAdIndex = -1;
+  interval: any;
+  indexDynamicComponent: number;
+
+  constructor(
+    private router: Router,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService
+  ) {}
+
+  ngOnInit() {
+    this.formData = this.formDataService.getFormData();
+    this.isFormValid = this.formDataService.isFormValid();
+    this.ads = this.loadInstrumentsService.getInstruments();
+    this.formData.instrumentos;
+
+    this.indexDynamicComponent = this.ads.findIndex(
+      x => x.data.key == this.formData.instrumentos
+    );
+    if (this.indexDynamicComponent >= 0) {
+      this.loadComponent();
+    } else {
+      console.log("No existe el componente");
+    }
+
+    this.general = this.formDataService.getGeneralInfo();
+    this.instrument = this.formDataService.getWork();
+    this.complement = this.formDataService.getComplementInfo();
+
+    this.final = {};
+
+    Object.assign(this.final, this.general, this.instrument, this.complement);
+    console.log("Result feature loaded!");
+    console.log(this.final);
+  }
+
+  loadComponent() {
+    this.currentAdIndex = this.indexDynamicComponent % this.ads.length;
+    const adItem = this.ads[this.currentAdIndex];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = true;
+  }
+
+  submit() {
+    console.log(this.final);
+
+    this.formData = this.formDataService.resetFormData();
+    this.isFormValid = false;
+  }
+}

+ 411 - 0
src/app/components/investment-proposals/complement-info/complement-info.component.html

@@ -0,0 +1,411 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Nueva</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <inv-proposal-navbar
+            [activeLink]="'other_info'"
+            [investmentID]="investmentProposalID"
+          ></inv-proposal-navbar>
+
+          <div class="card borderless card-wrapper">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Información adicional
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <form
+                  class="form-auth-small ng-untouched ng-pristine ng-valid"
+                  [formGroup]="investmentProposalForm"
+                >
+                  <div class="row">
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="tipo_mercado">Tipo de mercado: </label>
+                        <select
+                          class="custom-select"
+                          formControlName="tipo_mercado"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.tipo_mercado.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of markets"
+                            [value]="item.id_tipo_mercado"
+                            [selected]="
+                              item.id_tipo_mercado ==
+                              complementInfo.tipo_mercado
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.tipo_mercado.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.tipo_mercado.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="emisores">Emisores: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="emisores"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.emisores.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of emitters"
+                            [value]="item.id_tipo_emisor"
+                            [selected]="
+                              item.id_tipo_emisor == complementInfo.emisores
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.emisores.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.emisores.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="empresa">Empresa: </label>
+
+                        <select
+                          s
+                          class="custom-select"
+                          formControlName="empresa"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.empresa.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of companies"
+                            [value]="item.id_empresa"
+                            [selected]="
+                              item.id_empresa == complementInfo.empresa
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.empresa.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.empresa.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="pais">País: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="pais"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.pais.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of countries"
+                            [value]="item.id_pais"
+                            [selected]="item.id_pais == complementInfo.pais"
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.pais.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.pais.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="plazo">Plazos: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="plazo"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.plazo.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of payment_terms"
+                            [value]="item.id_plazo"
+                            [selected]="item.id_plazo == complementInfo.plazo"
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.plazo.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.pais.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="operaciones">Tipo de operación: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="operaciones"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.operaciones.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of operations"
+                            [value]="item.id_tipo_operacion"
+                            [selected]="
+                              item.id_tipo_operacion ==
+                              complementInfo.operaciones
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.operaciones.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.operaciones.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <!--
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="fecha_inicio_vigencia"
+                          >Fecha inicio vigencia:
+                        </label>
+                        <div class="input-box-container">
+                          <p>
+                            <i class="far fa-calendar" aria-hidden="true"></i>
+                          </p>
+                          <input
+                            class="input-box form-control"
+                            placeholder="Seleccione una fecha"
+                            angular-mydatepicker
+                            formControlName="fecha_inicio_vigencia"
+                            (click)="dp.toggleCalendar()"
+                            [options]="myDpOptions"
+                            #dp="angular-mydatepicker"
+                            [ngClass]="{
+                              'is-invalid':
+                                submitted && f.fecha_inicio_vigencia.errors
+                            }"
+                          />
+                        </div>
+
+                        <div
+                          *ngIf="submitted && f.fecha_inicio_vigencia.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.fecha_inicio_vigencia.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="calificadora_riesgo"
+                          >Calificadora de riesgo:
+                        </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="calificadora_riesgo"
+                          [ngClass]="{
+                            'is-invalid':
+                              submitted && f.calificadora_riesgo.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of rate_agencies"
+                            [value]="item.codigo"
+                            [selected]="
+                              item.codigo == complementInfo.calificadora_riesgo
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.calificadora_riesgo.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.calificadora_riesgo.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                      <div class="form-group">
+                        <label for="calificacion"
+                          >Calificación de riesgo:
+                        </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="calificacion"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.calificacion.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of scores"
+                            [value]="item.codigo"
+                            [selected]="
+                              item.codigo == complementInfo.calificacion
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.calificacion.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.calificacion.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    -->
+                  </div>
+
+                  <div class="row">
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="comentarios">Comentarios: </label>
+
+                        <textarea
+                          rows="2"
+                          class="form-control"
+                          formControlName="comentarios"
+                        ></textarea>
+                        <div
+                          *ngIf="submitted && f.comentarios.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.comentarios.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="justificacion">Justificación: </label>
+
+                        <textarea
+                          rows="2"
+                          class="form-control"
+                          formControlName="justificacion"
+                        ></textarea>
+                        <div
+                          *ngIf="submitted && f.justificacion.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.justificacion.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div #testOutlet></div>
+                  </div>
+                  <br />
+                  <div class="form-group text-center space-20">
+                    <button
+                      type="button"
+                      class="btn btn-default center-component margin-right"
+                      (click)="goToPrevious()"
+                    >
+                      Anterior
+                    </button>
+                    <button
+                      type="submit"
+                      class="btn btn-primary center-component margin-right"
+                      (click)="goToNext(investmentProposalForm)"
+                    >
+                      Siguiente
+                    </button>
+                  </div>
+
+                  <!-- [disabled]="!investmentProposalForm.valid"
+                    <div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>-->
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 191 - 0
src/app/components/investment-proposals/complement-info/complement-info.component.ts

@@ -0,0 +1,191 @@
+import { Component, OnInit } from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+
+import { ComplementInfo } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { parse } from "date-fns";
+
+@Component({
+  selector: "app-complement-info",
+  templateUrl: "./complement-info.component.html"
+})
+export class ComplementInfoComponent implements OnInit {
+  title: string = "Formulario propuesta de inversión";
+  complementInfo: ComplementInfo;
+  form: any;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+
+  investmentProposalForm: FormGroup;
+  submitted: boolean = false;
+  role_number: any;
+  markets: any;
+  emitters: any;
+  periodicities: any;
+  rate_agencies: any;
+  scores: any;
+  investmentProposalID: string;
+  countries: any;
+  companies: any;
+  format_incomes: any;
+  operations: any;
+  payment_terms: any;
+
+  complementInfoExists: boolean;
+  constructor(
+    private router: Router,
+    private route: ActivatedRoute,
+    private formBuilder: FormBuilder,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService
+  ) {}
+
+  ngOnInit() {
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    this.complementInfo = this.formDataService.getComplementInfo();
+    this.complementInfoExists = this.complementInfo == undefined;
+
+    this.catalogService.getCompanies().subscribe(res => {
+      this.companies = res;
+    });
+    this.catalogService.getCountries().subscribe(res => {
+      this.countries = res;
+    });
+
+    this.catalogService.getMarketTypes().subscribe(res => {
+      this.markets = res;
+    });
+    this.catalogService.getEmitterTypes().subscribe(res => {
+      this.emitters = res;
+    });
+
+    this.catalogService.getRateAgencies().subscribe(res => {
+      this.rate_agencies = res;
+    });
+
+    this.catalogService.getScores().subscribe(res => {
+      this.scores = res;
+    });
+
+    this.catalogService.getPaymentTerms().subscribe(res => {
+      this.payment_terms = res;
+    });
+
+    this.catalogService.getOperationTypes().subscribe(res => {
+      this.operations = res;
+    });
+
+    this.investmentProposalForm = this.formBuilder.group({
+      tipo_mercado: [
+        this.complementInfoExists ? "" : this.complementInfo.tipo_mercado,
+        [Validators.required]
+      ],
+
+      emisores: [
+        this.complementInfoExists ? "" : this.complementInfo.emisores,
+        [Validators.required]
+      ],
+      empresa: [
+        this.complementInfoExists ? "" : this.complementInfo.empresa,
+        [Validators.required]
+      ],
+      pais: [
+        this.complementInfoExists ? "" : this.complementInfo.pais,
+        [Validators.required]
+      ],
+      plazo: [
+        this.complementInfoExists ? "" : this.complementInfo.plazo,
+        [Validators.required]
+      ],
+      operaciones: [
+        this.complementInfoExists ? "" : this.complementInfo.operaciones,
+        [Validators.required]
+      ],
+
+      comentarios: [
+        this.complementInfoExists ? "" : this.complementInfo.comentarios,
+        []
+      ],
+      justificacion: [
+        this.complementInfoExists ? "" : this.complementInfo.justificacion,
+        []
+      ]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  save(form: any): boolean {
+    //if (!form.valid) {
+    //return false;
+    //}
+    this.formDataService.setComplementInfo(this.investmentProposalForm.value);
+    return true;
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentProposalID != undefined) {
+      this.router.navigate(["/investment-proposal/instrument-work"], {
+        queryParams: { id: this.investmentProposalID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/instrument-work"]);
+    }
+  }
+
+  goToNext(form: any) {
+    this.submitted = true;
+
+    if (this.save(form)) {
+      if (this.investmentProposalID != undefined) {
+        this.router.navigate(["/investment-proposal/result"], {
+          queryParams: { id: this.investmentProposalID }
+        });
+      } else {
+        this.router.navigate(["/investment-proposal/result"]);
+      }
+    }
+  }
+}

+ 367 - 0
src/app/components/investment-proposals/general-info/general-info.component.html

@@ -0,0 +1,367 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Nueva</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <inv-proposal-navbar
+            [activeLink]="'general'"
+            [investmentID]="investmentProposalID"
+          ></inv-proposal-navbar>
+          <div class="card borderless card-wrapper">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Propuesta de inversión
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <form
+                  class="form-auth-small ng-untouched ng-pristine ng-valid"
+                  [formGroup]="investmentProposalForm"
+                >
+                  <div class="row">
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="asunto">Asunto: </label>
+                        <div class="input-box-container">
+                          <p>
+                            <i class="far fa-keyboard"></i>
+                          </p>
+                          <input
+                            type="text"
+                            formControlName="asunto"
+                            class="form-control"
+                            [ngClass]="{
+                              'is-invalid': submitted && f.asunto.errors
+                            }"
+                          />
+                          <div
+                            *ngIf="submitted && f.asunto.errors"
+                            class="invalid-feedback"
+                          >
+                            <div *ngIf="f.asunto.errors.required">
+                              Campo requerido
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="origenes_fondo">Orígenes de fondo: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="origenes_fondo"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.origenes_fondo.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of funds"
+                            [value]="item.id_origen_fondo"
+                            [selected]="
+                              item.id_origen_fondo == general.origenes_fondo
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.origenes_fondo.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.origenes_fondo.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="name">Nombre: </label>
+
+                        <div class="input-box-container">
+                          <p>
+                            <i class="far fa-keyboard"></i>
+                          </p>
+                          <input
+                            type="text"
+                            formControlName="name"
+                            class="form-control"
+                            [ngClass]="{
+                              'is-invalid': submitted && f.name.errors
+                            }"
+                          />
+                          <div
+                            *ngIf="submitted && f.name.errors"
+                            class="invalid-feedback"
+                          >
+                            <div *ngIf="f.name.errors.required">
+                              Campo requerido
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="tipo_tasa">Tipo Tasa: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="tipo_tasa"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.tipo_tasa.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of rates"
+                            [value]="item.id_tipo_tasa"
+                            [selected]="item.id_tipo_tasa == general.tipo_tasa"
+                            >{{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.tipo_tasa.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.tipo_tasa.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="row">
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="tipo_renta">Tipo Renta: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="tipo_renta"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.tipo_renta.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of revenues"
+                            [value]="item.id_tipo_renta"
+                            [selected]="
+                              item.id_tipo_renta == general.tipo_renta
+                            "
+                            >{{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.tipo_renta.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.tipo_renta.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="instrumentos">Instrumentos: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="instrumentos"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.instrumentos.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of instrumentTypes"
+                            [selected]="item.codigo == general.instrumentos"
+                            [value]="item.codigo"
+                            >{{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.instrumentos.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.instrumentos.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="periodicidad">Periodicidad: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="periodicidad"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.periodicidad.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of periodicities"
+                            [value]="item.id_periodicidad"
+                            [selected]="
+                              item.id_periodicidad == general.periodicidad
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.periodicidad.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.periodicidad.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="base_anual">Año base: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="base_anual"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.base_anual.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of base_types"
+                            [value]="item.id_tipo_base"
+                            [selected]="item.id_tipo_base == general.base_anual"
+                            >{{ item.tipo_base }}/{{
+                              item.tipo_base_dias
+                            }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.base_anual.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.base_anual.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="casa">Casa: </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="casa"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.casa.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of financials"
+                            [value]="item.id_entidad_financiera"
+                            [selected]="
+                              item.id_entidad_financiera == general.casa
+                            "
+                          >
+                            {{ item.nombre }}
+                          </option>
+                        </select>
+                        <div
+                          *ngIf="submitted && f.casa.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.casa.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="formato_ingreso"
+                          >Formato de ingreso:
+                        </label>
+
+                        <select
+                          class="custom-select"
+                          formControlName="formato_ingreso"
+                          [ngClass]="{
+                            'is-invalid': submitted && f.formato_ingreso.errors
+                          }"
+                        >
+                          <option
+                            *ngFor="let item of format_incomes"
+                            [value]="item.id_formato_ingreso"
+                            [selected]="
+                              item.id_formato_ingreso == general.formato_ingreso
+                            "
+                          >
+                            {{ item.nombre }}</option
+                          >
+                        </select>
+                        <div
+                          *ngIf="submitted && f.formato_ingreso.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.formato_ingreso.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <br />
+                  <div class="form-group text-center space-20">
+                    <button
+                      type="submit"
+                      class="btn btn-primary center-component margin-right"
+                      (click)="goToNext(investmentProposalForm)"
+                    >
+                      Siguiente
+                    </button>
+                  </div>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 1 - 0
src/app/components/investment-proposals/general-info/general-info.component.scss

@@ -0,0 +1 @@
+

+ 67 - 0
src/app/components/investment-proposals/general-info/general-info.component.spec.ts

@@ -0,0 +1,67 @@
+import { TestBed, ComponentFixture, async } from "@angular/core/testing";
+import { RouterTestingModule } from "@angular/router/testing";
+import { InvestmentProposalGeneralInfoComponent } from "./general-info.component";
+import { By } from "@angular/platform-browser";
+import { RouterOutlet, RouterLinkWithHref } from "@angular/router";
+import { NO_ERRORS_SCHEMA } from "@angular/core";
+import { HttpClientModule } from "@angular/common/http";
+import { ReactiveFormsModule, FormsModule } from "@angular/forms";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { InvestmentsService } from "@app/services/investments.service";
+import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
+
+describe("InvestmentProposalGeneralInfoComponent", () => {
+  let component: InvestmentProposalGeneralInfoComponent;
+  let fixture: ComponentFixture<InvestmentProposalGeneralInfoComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [InvestmentProposalGeneralInfoComponent],
+      imports: [
+        RouterTestingModule,
+        HttpClientModule,
+        ReactiveFormsModule,
+        FormsModule,
+        BrowserAnimationsModule
+      ],
+      providers: [
+        CatalogsService,
+        InvestmentsService,
+        FormInvestmentProposalService
+      ],
+      schemas: [NO_ERRORS_SCHEMA]
+    }).compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(InvestmentProposalGeneralInfoComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+    component.ngOnInit();
+  });
+
+  it("should create", () => {
+    expect(component).toBeTruthy();
+  });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      if (elem.attributes["ng-reflect-router-link"] === "/") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
+});

+ 347 - 0
src/app/components/investment-proposals/general-info/general-info.component.ts

@@ -0,0 +1,347 @@
+import {
+  Component,
+  OnInit,
+  OnChanges,
+  ViewChild,
+  ComponentRef,
+  Type
+} from "@angular/core";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import Swal from "sweetalert2";
+import {
+  GeneralInfo,
+  ComplementInfo
+} from "@app/models/investment-proposal-form";
+import { Router, ActivatedRoute } from "@angular/router";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { InvestmentsService } from "@app/services/investments.service";
+import { DatePipe } from "@angular/common";
+import { parse } from "date-fns";
+
+@Component({
+  selector: "app-new-investment-proposal",
+  templateUrl: "./general-info.component.html",
+  styleUrls: ["./general-info.component.scss"]
+})
+export class InvestmentProposalGeneralInfoComponent
+  implements OnInit, OnChanges {
+  general: GeneralInfo;
+  complement: ComplementInfo;
+  instrument: {};
+  form: any;
+  investmentProposalID: any = undefined;
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  investmentProposalForm: FormGroup;
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+  model: IMyDateModel = null;
+
+  title: string = "Formulario propuesta de inversión";
+  submitted: boolean = false;
+  role_number: any;
+  periodicities: any;
+  rates: any;
+  revenues: any;
+  funds: any;
+  instrumentTypes: any;
+  generalInfoDontExists: boolean;
+  plazos: any;
+  base_types: any;
+  financials: any;
+  format_incomes: any;
+
+  gInfo: any;
+  gInstrument: any;
+  gComplement: any;
+  datez: any;
+  instrumentName: any;
+  constructor(
+    private formBuilder: FormBuilder,
+    private router: Router,
+    private route: ActivatedRoute,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private investmentsService: InvestmentsService,
+    public datepipe: DatePipe
+  ) {}
+
+  ngOnInit() {
+    Swal.close();
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    if (this.investmentProposalID != undefined) {
+      this.investmentsService
+        .getProposalInvestment(this.investmentProposalID)
+        .subscribe(
+          res => {
+            this.gInfo = {
+              asunto: res["result"]["asunto"],
+              origenes_fondo:
+                res["result"]["id_origen_fondo"] == null
+                  ? ""
+                  : res["result"]["id_origen_fondo"]["id_origen_fondo"],
+              name: res["result"]["nombre_inversion"],
+              //date: "",
+              tipo_tasa: res["result"]["id_tipo_tasa"] || "",
+              tipo_renta:
+                res["result"]["id_tipo_renta"] == null
+                  ? ""
+                  : res["result"]["id_tipo_renta"]["id_tipo_renta"],
+              periodicidad:
+                res["result"]["id_periodicidad"] == null
+                  ? ""
+                  : res["result"]["id_periodicidad"]["id_periodicidad"],
+
+              instrumentos:
+                res["result"]["id_inversion_instrumento"][
+                  "id_tipo_instrumento"
+                ]["codigo"],
+              base_anual:
+                res["result"]["id_tipo_base"] == null
+                  ? ""
+                  : res["result"]["id_tipo_base"]["id_tipo_base"],
+              casa:
+                res["result"]["id_entidad"] == null
+                  ? ""
+                  : res["result"]["id_entidad"]["id_entidad_financiera"],
+              formato_ingreso:
+                res["result"]["id_formato_ingreso"] == null
+                  ? ""
+                  : res["result"]["id_formato_ingreso"]["id_formato_ingreso"]
+            };
+
+            this.gInstrument =
+              res["result"]["id_inversion_instrumento"]["instrumento"];
+
+            this.gInstrument["id_inversion_instrumento"] =
+              res["result"]["id_inversion_instrumento"][
+                "id_inversion_instrumento"
+              ];
+
+            this.gComplement = {
+              tipo_mercado:
+                res["result"]["id_tipo_mercado"] == null
+                  ? ""
+                  : res["result"]["id_tipo_mercado"]["id_tipo_mercado"],
+              emisores:
+                res["result"]["id_tipo_emisor"] == null
+                  ? ""
+                  : res["result"]["id_tipo_emisor"]["id_tipo_emisor"],
+              empresa:
+                res["result"]["id_empresa"] == null
+                  ? ""
+                  : res["result"]["id_empresa"]["id_empresa"],
+              pais:
+                res["result"]["id_pais"] == null
+                  ? ""
+                  : res["result"]["id_pais"]["id_pais"],
+              plazo:
+                res["result"]["id_plazo"] == null
+                  ? ""
+                  : res["result"]["id_plazo"]["id_plazo"],
+              operaciones:
+                res["result"]["id_tipo_operacion"] == null
+                  ? ""
+                  : res["result"]["id_tipo_operacion"]["id_tipo_operacion"],
+              comentarios: res["result"]["comentario"],
+              justificacion: res["result"]["justificacion"]
+            };
+
+            // Setear objeto dinamico con valores obtenidos del endpoint
+            this.general = this.formDataService.getGeneralInfo();
+
+            // Validar que el objeto dinamico contenga valores, si no, setear con valores obtenidos del endpoint
+            if (
+              Object.values(this.general).every(x => x === null || x === "")
+            ) {
+              this.formDataService.setGeneralInfo(this.gInfo);
+              this.general = this.formDataService.getGeneralInfo();
+              this.generalInfoDontExists = this.general == undefined;
+              this.investmentProposalForm.setValue({
+                asunto: this.gInfo.asunto,
+                origenes_fondo: this.gInfo.origenes_fondo,
+                name: this.gInfo.name,
+                tipo_tasa: this.gInfo.tipo_tasa,
+                tipo_renta: this.gInfo.tipo_renta,
+                periodicidad: this.gInfo.periodicidad,
+
+                instrumentos: this.gInfo.instrumentos,
+                base_anual: this.gInfo.base_anual,
+                casa: this.gInfo.casa,
+                formato_ingreso: this.gInfo.formato_ingreso
+              });
+            }
+
+            this.instrument = this.formDataService.getWork();
+            if (
+              this.instrument == undefined ||
+              Object.values(this.instrument).every(x => x === null || x === "")
+            ) {
+              this.formDataService.setWork(this.gInstrument);
+              this.instrument = this.formDataService.getWork();
+            }
+
+            this.complement = this.formDataService.getComplementInfo();
+            if (
+              Object.values(this.complement).every(x => x === null || x === "")
+            ) {
+              this.formDataService.setComplementInfo(this.gComplement);
+            }
+          },
+          err => {
+            Swal.fire({
+              icon: "error",
+              title: "Error en el servidor",
+              text: err.message
+            });
+          }
+        );
+    } else {
+    }
+
+    //this.datepipe.transform(new Date(), "yyyy-MM-dd");
+    this.general = this.formDataService.getGeneralInfo();
+    this.generalInfoDontExists = false;
+    // Obtener catalogos
+
+    this.catalogService.getPaymentTerms().subscribe(res => {
+      this.plazos = res;
+    });
+
+    this.catalogService.getFinancialEntities().subscribe(res => {
+      this.financials = res;
+    });
+
+    this.catalogService.getBaseTypes().subscribe(res => {
+      this.base_types = res;
+    });
+    this.catalogService.getPeriodicities().subscribe(res => {
+      this.periodicities = res;
+    });
+
+    this.catalogService.getRateTypes().subscribe(res => {
+      this.rates = res;
+    });
+    this.catalogService.getRevenueTypes().subscribe(res => {
+      this.revenues = res;
+    });
+    this.catalogService.getFundsOrigins().subscribe(res => {
+      this.funds = res;
+    });
+    this.catalogService.getInstrumentTypes().subscribe(res => {
+      this.instrumentTypes = res;
+      if (this.generalInfoDontExists == false) {
+        this.instrumentName = res.find(
+          e => e.codigo == this.general.instrumentos
+        );
+        this.instrumentName =
+          this.instrumentName != undefined ? this.instrumentName.nombre : "-";
+      }
+    });
+    //getIncomeFormat
+    this.catalogService.getIncomeFormat().subscribe(res => {
+      this.format_incomes = res;
+    });
+
+    // Si el arreglo principal de objetos viene con todos sus elementos vacios, inicializo el formulario.
+    //if (Object.values(this.general).every(x => x === null || x === "")) {
+    this.callForm(this.generalInfoDontExists, this.general);
+  }
+
+  ngOnChanges() {}
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+    this.formDataService.setGeneralInfo(this.investmentProposalForm.value);
+    return true;
+  }
+
+  callForm(formExists: boolean, form: any) {
+    this.investmentProposalForm = this.formBuilder.group({
+      asunto: ["", Validators.required],
+      origenes_fondo: ["", Validators.required],
+      name: ["", Validators.required],
+      //date: ["", Validators.required],
+      tipo_tasa: ["", Validators.required],
+      tipo_renta: ["", Validators.required],
+      periodicidad: ["", Validators.required],
+
+      base_anual: ["", Validators.required],
+      casa: ["", Validators.required],
+      instrumentos: ["", Validators.required],
+      formato_ingreso: ["", Validators.required]
+    });
+
+    this.investmentProposalForm.setValue({
+      asunto: form.asunto,
+      origenes_fondo: form.origenes_fondo || "",
+      name: form.name || "",
+      //date: form.date.singleDate == undefined ? "" : form.date,
+      tipo_tasa: form.tipo_tasa || "",
+      tipo_renta: form.tipo_renta || "",
+      periodicidad: form.periodicidad || "",
+
+      instrumentos: form.instrumentos || "",
+      base_anual: form.base_anual || "",
+      casa: form.casa || "",
+      formato_ingreso: form.formato_ingreso || ""
+    });
+  }
+
+  goToNext(form: any) {
+    this.submitted = true;
+    if (this.save(form)) {
+      // Navigate to the work page
+
+      if (this.investmentProposalID != undefined) {
+        this.router.navigate(["/investment-proposal/instrument-work"], {
+          queryParams: { id: this.investmentProposalID },
+          relativeTo: this.route
+        });
+        //this.router.navigateByUrl(         `/investment-proposal/${this.investmentProposalID}/instrument-work/`);
+      } else {
+        this.router.navigate(["/investment-proposal/instrument-work"]);
+      }
+    }
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+}

+ 51 - 0
src/app/components/investment-proposals/instrument-work/instrument-work.component.html

@@ -0,0 +1,51 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Nueva</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <inv-proposal-navbar
+            [activeLink]="'instrument'"
+            [investmentID]="investmentProposalID"
+          ></inv-proposal-navbar>
+
+          <div class="card borderless card-wrapper">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Instrumento
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ng-template instrument-host></ng-template>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 105 - 0
src/app/components/investment-proposals/instrument-work/instrument-work.component.ts

@@ -0,0 +1,105 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "../instrument/instrument.directive";
+import { InstrumentComponent } from "../instrument/instrument.component";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { InstrumentsService } from "@app/services/instruments.service";
+
+@Component({
+  selector: "app-instrument-work",
+  templateUrl: "./instrument-work.component.html"
+})
+export class InstrumentWorkComponent implements OnInit {
+  title = "Formulario propuesta de inversión";
+  workType: string;
+  form: any;
+  @Input() ads: Instrument[];
+  currentAdIndex = -1;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  interval: any;
+  @Input() formData: InvestmentProposalForm;
+  indexDynamicComponent: number;
+  investmentProposalID: string = undefined;
+  constructor(
+    private router: Router,
+    private route: ActivatedRoute,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService
+  ) {}
+
+  ngOnInit() {
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    this.ads = this.loadInstrumentsService.getInstruments();
+    this.formData = this.formDataService.getFormData();
+    this.formData.instrumentos;
+    this.indexDynamicComponent = this.ads.findIndex(
+      x => x.data.key == this.formData.instrumentos
+    );
+    if (this.indexDynamicComponent >= 0) {
+      this.loadComponent();
+    } else {
+    }
+    //this.workType = this.formDataService.getWork();
+  }
+
+  loadComponent() {
+    this.currentAdIndex = this.indexDynamicComponent % this.ads.length;
+    const adItem = this.ads[this.currentAdIndex];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = false;
+    (<InstrumentComponent>(
+      componentRef.instance
+    )).investmentID = this.investmentProposalID;
+  }
+
+  save(form: any): boolean {
+    if (!form.valid) {
+      return false;
+    }
+
+    this.formDataService.setWork(this.workType);
+    return true;
+  }
+
+  goToPrevious(form: any) {
+    if (this.save(form)) {
+      // Navigate to the general info page
+      this.router.navigate(["/investment-proposals/general-info"]);
+    }
+  }
+
+  goToNext(form: any) {
+    if (this.save(form)) {
+      // Navigate to the address page
+      this.router.navigate(["/address"]);
+    }
+  }
+}

+ 5 - 0
src/app/components/investment-proposals/instrument/instrument.component.ts

@@ -0,0 +1,5 @@
+export interface InstrumentComponent {
+  data: any;
+  summary: boolean;
+  investmentID: string;
+}

+ 8 - 0
src/app/components/investment-proposals/instrument/instrument.directive.ts

@@ -0,0 +1,8 @@
+import { Directive, ViewContainerRef } from "@angular/core";
+
+@Directive({
+  selector: "[instrument-host]"
+})
+export class InstrumentDirective {
+  constructor(public viewContainerRef: ViewContainerRef) {}
+}

+ 222 - 3
src/app/components/investment-proposals/investment-proposals.component.html

@@ -13,8 +13,11 @@
               <li class="breadcrumb-item">Propuestas de inversión</li>
             </ol>
           </nav>
-
-          <a class="btn btn-primary" href="#">
+          <a
+            class="btn btn-primary"
+            *ngIf="userType(userRole, 'analistas')"
+            (click)="create_investment_proposal()"
+          >
             Nuevo registro
           </a>
         </div>
@@ -22,7 +25,223 @@
 
       <div class="col-12">
         <div class="align-container">
-          <h4><b>Listado de propuestas de inversiones</b></h4>
+          <h4><b>Listado de propuestas de inversión</b></h4>
+          <br />
+          <div class="form-group">
+            <label for="filter" class="control-label">Filtro: </label>
+            <input
+              name="filter"
+              (keyup)="applyFilter($event)"
+              class="form-control input-md"
+              placeholder="Codigo, Instrumento, Estado, Asunto o Comentario"
+            />
+          </div>
+          <br />
+          <div class="example-container mat-elevation-z8">
+            <div class="example-table-container">
+              <table mat-table [dataSource]="dataSource" class="example-table">
+                <!-- Name Column -->
+                <ng-container matColumnDef="codigo_inversion">
+                  <th mat-header-cell *matHeaderCellDef>Codigo</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{ row.codigo_inversion }}
+                  </td>
+                </ng-container>
+                <!-- Country Column -->
+                <ng-container matColumnDef="asunto">
+                  <th mat-header-cell *matHeaderCellDef>Asunto</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{ row.asunto }}
+                  </td>
+                </ng-container>
+
+                <!-- Country Column -->
+                <ng-container matColumnDef="id_tipo_mercado">
+                  <th mat-header-cell *matHeaderCellDef>Tipo de mercado</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{
+                      row.id_tipo_mercado == "" ||
+                      row.id_tipo_mercado == undefined
+                        ? "-"
+                        : row.id_tipo_mercado.nombre
+                    }}
+                  </td>
+                </ng-container>
+
+                <!-- Country Column -->
+                <ng-container matColumnDef="id_inversion_instrumento">
+                  <th mat-header-cell *matHeaderCellDef>Instrumento</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{
+                      row.id_inversion_instrumento.id_tipo_instrumento == "" ||
+                      row.id_inversion_instrumento.id_tipo_instrumento ==
+                        undefined
+                        ? "-"
+                        : row.id_inversion_instrumento.id_tipo_instrumento
+                            .nombre
+                    }}
+                  </td>
+                </ng-container>
+
+                <ng-container matColumnDef="id_estado_inversion">
+                  <th mat-header-cell *matHeaderCellDef>Estado</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{
+                      row.id_estado_inversion == "" ||
+                      row.id_estado_inversion == undefined
+                        ? "-"
+                        : row.id_estado_inversion.nombre
+                    }}
+                  </td>
+                </ng-container>
+
+                <!--  Column -->
+                <ng-container matColumnDef="id">
+                  <th mat-header-cell *matHeaderCellDef>&nbsp;</th>
+                  <td mat-cell *matCellDef="let row">
+                    <div class="action-buttons">
+                      <a
+                        title="Detalle propuesta"
+                        class="btn btn-primary btn-custom-small"
+                        (click)="view_investment_proposal(row.id_inversion)"
+                      >
+                        <i class="fas fa-info"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_modify_or_send_to_review(
+                            row.id_estado_inversion.codigo
+                          ) ||
+                          (can_finish_proposal(
+                            row.id_estado_inversion.codigo
+                          ) &&
+                            userType(userRole, 'analistas'))
+                        "
+                        title="Editar"
+                        class="btn btn-primary btn-custom-small"
+                        (click)="modify_investment_proposal(row.id_inversion)"
+                      >
+                        <i class="fas fa-edit"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_modify_or_send_to_review(
+                            row.id_estado_inversion.codigo
+                          ) && userType(userRole, 'analistas')
+                        "
+                        title="Enviar a revisión"
+                        class="btn btn-dark btn-custom-small"
+                        (click)="
+                          sendToReview(row.id_inversion, row.codigo_inversion)
+                        "
+                      >
+                        <i class="fas fa-share"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_review(row.id_estado_inversion.codigo) &&
+                          userType(userRole, 'supervisores')
+                        "
+                        title="Revisar"
+                        class="btn btn-warning btn-custom-small"
+                        [routerLink]="[
+                          '/investment-proposal',
+                          row.id_inversion,
+                          'review'
+                        ]"
+                      >
+                        <i class="fas fa-spell-check"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_approve(row.id_estado_inversion.codigo) &&
+                          userType(userRole, 'autorizadores')
+                        "
+                        title="Aprobar"
+                        class="btn btn-warning btn-custom-small"
+                        [routerLink]="[
+                          '/investment-proposal',
+                          row.id_inversion,
+                          'approve'
+                        ]"
+                      >
+                        <i class="far fa-thumbs-up"></i>
+                      </a>
+
+                      <a
+                        *ngIf="
+                          can_write_payment_info(
+                            row.id_estado_inversion.codigo
+                          ) && userType(userRole, 'analistas')
+                        "
+                        title="Información de pago"
+                        class="btn btn-warning btn-custom-small"
+                        [routerLink]="[
+                          '/investment-proposal',
+                          row.id_inversion,
+                          'payment-info'
+                        ]"
+                      >
+                        <i class="fas fa-money-check-alt"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_upload_payment(row.id_estado_inversion.codigo) &&
+                          userType(userRole, 'contabilidad')
+                        "
+                        title="Requisición de pago"
+                        class="btn btn-success btn-custom-small"
+                        [routerLink]="[
+                          '/investment-proposal',
+                          row.id_inversion,
+                          'payment'
+                        ]"
+                      >
+                        <i class="fas fa-money-bill-wave"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_finish_proposal(row.id_estado_inversion.codigo) &&
+                          userType(userRole, 'analistas')
+                        "
+                        title="Finalizar inversión"
+                        class="btn btn-success btn-custom-small"
+                        (click)="
+                          finishProposal(row.id_inversion, row.codigo_inversion)
+                        "
+                      >
+                        <i class="far fa-check-circle"></i>
+                      </a>
+                      <!--
+                      <a
+                        title="Historico"
+                        class="btn btn-link btn-custom-small"
+                        [routerLink]="[
+                          '/investment-proposal',
+                          row.id_inversion,
+                          'change-history'
+                        ]"
+                      >
+                        <i class="fas fa-history"></i>
+                      </a>-->
+                    </div>
+                  </td>
+                </ng-container>
+
+                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                <tr
+                  mat-row
+                  *matRowDef="let row; columns: displayedColumns"
+                ></tr>
+              </table>
+
+              <mat-paginator
+                [pageSizeOptions]="[10, 15, 25]"
+                [pageIndex]="0"
+                [pageSize]="10"
+              ></mat-paginator>
+            </div>
+          </div>
         </div>
       </div>
       <br />

+ 10 - 0
src/app/components/investment-proposals/investment-proposals.component.scss

@@ -0,0 +1,10 @@
+.action-buttons {
+  i {
+    font-size: 18px;
+  }
+}
+
+.btn-custom-small {
+  padding: 7px 12px 5px 13px;
+  margin: 0 4px;
+}

+ 66 - 8
src/app/components/investment-proposals/investment-proposals.component.spec.ts

@@ -1,25 +1,83 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { TestBed, ComponentFixture, async } from "@angular/core/testing";
+import { RouterTestingModule } from "@angular/router/testing";
+import { InvestmentProposalsComponent } from "./investment-proposals.component";
+import { By } from "@angular/platform-browser";
+import { RouterOutlet, RouterLinkWithHref } from "@angular/router";
+import { NO_ERRORS_SCHEMA } from "@angular/core";
+import { HttpClientModule } from "@angular/common/http";
+import { ReactiveFormsModule, FormsModule } from "@angular/forms";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+import {
+  MatButtonModule,
+  MatInputModule,
+  MatRippleModule,
+  MatFormFieldModule,
+  MatSelectModule,
+  MatExpansionModule,
+  MatTableModule,
+  MatPaginatorModule,
+  MatProgressSpinnerModule,
+  MatSortModule
+} from "@angular/material";
+import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
 
-import { InvestmentProposalsComponent } from './investment-proposals.component';
-
-describe('InvestmentProposalsComponent', () => {
+describe("InvestmentProposalsComponent", () => {
   let component: InvestmentProposalsComponent;
   let fixture: ComponentFixture<InvestmentProposalsComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ InvestmentProposalsComponent ]
-    })
-    .compileComponents();
+      declarations: [InvestmentProposalsComponent],
+      imports: [
+        RouterTestingModule,
+        HttpClientModule,
+        ReactiveFormsModule,
+        FormsModule,
+        MatButtonModule,
+        MatInputModule,
+        MatRippleModule,
+        MatFormFieldModule,
+        MatSelectModule,
+        MatExpansionModule,
+        MatTableModule,
+        MatPaginatorModule,
+        MatProgressSpinnerModule,
+        MatSortModule,
+        BrowserAnimationsModule
+      ],
+      providers: [CatalogsService, InvestmentsService],
+      schemas: [NO_ERRORS_SCHEMA]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
     fixture = TestBed.createComponent(InvestmentProposalsComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
+    component.ngOnInit();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      if (elem.attributes["ng-reflect-router-link"] === "/") {
+        existe = false;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 322 - 3
src/app/components/investment-proposals/investment-proposals.component.ts

@@ -3,8 +3,14 @@ import { MatPaginator } from "@angular/material/paginator";
 import { MatSort } from "@angular/material/sort";
 import { MatTableDataSource } from "@angular/material/table";
 import Swal from "sweetalert2";
-import { Router } from "@angular/router";
+import { CatalogsService } from "src/app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
 import { AuthService } from "@app/services/auth2.service";
+import { JwtHelperService } from "@auth0/angular-jwt";
+import { InvestmentProposal } from "@app/models/investment-proposal";
+import { from } from "rxjs";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Router } from "@angular/router";
 
 @Component({
   selector: "app-investment-proposals",
@@ -12,9 +18,322 @@ import { AuthService } from "@app/services/auth2.service";
   styleUrls: ["./investment-proposals.component.scss"]
 })
 export class InvestmentProposalsComponent implements OnInit {
+  helper = new JwtHelperService();
+
   title: string = "Propuestas de inversión";
 
-  constructor(private router: Router, private authService: AuthService) {}
+  displayedColumns: string[] = [
+    "codigo_inversion",
+    "asunto",
+    "id_tipo_mercado",
+    "id_inversion_instrumento",
+    "id_estado_inversion",
+    "id"
+  ];
+  //displayedColumns: string[] = ['state'];
+
+  listProposals: InvestmentProposal[];
+  dataSource = new MatTableDataSource(this.listProposals);
+
+  resultsLength = 0;
+  isLoadingResults = true;
+  isRateLimitReached = false;
+  userRole: any;
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+  role_number: any;
+
+  constructor(
+    private catalogService: CatalogsService,
+    private investmentsService: InvestmentsService,
+    private authService: AuthService,
+    private formInvestmentProposal: FormInvestmentProposalService,
+    private router: Router
+  ) {
+    const decodedToken = this.helper.decodeToken(
+      this.authService.getJwtToken()
+    );
+    this.userRole = decodedToken.groups;
+    this.dataSource.filterPredicate = (data, filter) => {
+      const dataStr =
+        data.id_inversion_instrumento.id_tipo_instrumento.nombre.toLowerCase() +
+        data.id_estado_inversion.nombre.toLowerCase() +
+        data.codigo_inversion.toLowerCase() +
+        data.nombre_inversion.toLowerCase() +
+        data.asunto.toLowerCase() +
+        data.comentario.toLowerCase() +
+        data.justificacion.toLowerCase();
+      return dataStr.indexOf(filter) != -1;
+    };
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+  }
+
+  ngOnInit() {
+    this.investmentsService.getProposalInvestmentsList().subscribe(
+      ans => {
+        this.listProposals = ans.result;
+
+        if (this.userType(this.userRole, "analistas")) {
+          this.listProposals;
+        } else if (this.userType(this.userRole, "contabilidad")) {
+          this.listProposals = this.listProposals.filter(proposals =>
+            ["COMPR", "LIQUI"].includes(
+              proposals["id_estado_inversion"]["codigo"]
+            )
+          );
+        } else if (this.userType(this.userRole, "autorizadores")) {
+          this.listProposals = this.listProposals.filter(proposals =>
+            ["REVIS", "APROB", "FINAL"].includes(
+              proposals["id_estado_inversion"]["codigo"]
+            )
+          );
+        } else if (this.userType(this.userRole, "supervisores")) {
+          this.listProposals = this.listProposals.filter(proposals =>
+            ["PENDI", "REVIS", "FINAL"].includes(
+              proposals["id_estado_inversion"]["codigo"]
+            )
+          );
+        }
+
+        this.dataSource.data = this.listProposals;
+        this.dataSource.paginator = this.paginator;
+        this.dataSource.sort = this.sort;
+      },
+      err => {
+        Swal.fire({
+          icon: "error",
+          title: "Error en el servidor",
+          text: err.message
+        });
+      }
+    );
+
+    setTimeout(() => {
+      Swal.close();
+    }, 1200);
+  }
+
+  applyFilter(event: Event) {
+    const filterValue = (event.target as HTMLInputElement).value.toLowerCase();
+    this.dataSource.filter = filterValue;
+
+    if (this.dataSource.paginator) {
+      this.dataSource.paginator.firstPage();
+    }
+  }
+
+  view_investment_proposal(id: string) {
+    this.formInvestmentProposal.resetFormData();
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    setTimeout(() => {
+      this.router.navigate([`/investment-proposal/${id}`]);
+    }, 1000);
+  }
+
+  modify_investment_proposal(id: string) {
+    this.formInvestmentProposal.resetFormData();
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    setTimeout(() => {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: id }
+      });
+    }, 1000);
+  }
+
+  create_investment_proposal() {
+    this.formInvestmentProposal.resetFormData();
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    setTimeout(() => {
+      this.router.navigate(["/investment-proposal/general-info"], {});
+    }, 1000);
+  }
+
+  // Verifica permisos para mostrar boton de edicion y/o envio a revision,
+  // segun los permisos del usuario y el estado de la propuesta
+  can_modify_or_send_to_review(status: string) {
+    if (status == "NUEVA" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_review(status: string) {
+    if (status == "PENDI" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_approve(status: string) {
+    if (status == "REVIS" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_write_payment_info(status: string) {
+    if (status == "APROB" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_upload_payment(status: string) {
+    if (status == "COMPR" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_finish_proposal(status: string) {
+    if (status == "LIQUI" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  sendToReview(investmentProposalID: number, investmentCode: string) {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: `<h3>Enviar a revisión propuesta de inversión ${investmentCode}</h3>`,
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Enviar propuesta",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+
+        preConfirm: comentario => {
+          let reviewProposal = {
+            id_inversion: investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentsService
+            .sendReviewProposalInvestment(reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido enviada a revisión"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.reload();
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  //Enviar a revision la propuesta de inversion
+  finishProposal(investmentProposalID: number, investmentCode: string) {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: `<h3>Finalizar propuesta de inversión: ${investmentCode}</h3>`,
+        icon: "info",
+        input: "textarea",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        showCancelButton: true,
+        confirmButtonText: "Finalizar",
+        cancelButtonText: "Cancelar",
+        preConfirm: comentario => {
+          let reviewProposal = {
+            id_inversion: investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentsService
+            .sendReviewProposalInvestment(reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido finalizada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.reload();
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  userType(userRole: any, requiredRole: any) {
+    if (userRole.length == 0) {
+      return true;
+    }
 
-  ngOnInit() {}
+    return userRole.includes(requiredRole);
+  }
 }

+ 188 - 0
src/app/components/investment-proposals/payment-info/payment-info.component.html

@@ -0,0 +1,188 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Información de pago</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="card borderless card-wrapper">
+          <div class="card-header card-header-icon card-header-rose">
+            <br />
+            <h4 class="card-title">
+              Información de pago para la inversión: {{ inversionCode }}
+            </h4>
+          </div>
+          <div class="card-body">
+            <form
+              class="form-auth-small ng-untouched ng-pristine ng-valid"
+              [formGroup]="investmentProposalForm"
+            >
+              <div class="row">
+                <!-- Valor nominal -->
+                <div class="col-lg-6 col-sm-12 pr-xl-3">
+                  <div class="form-group">
+                    <label for="monto">Monto: </label>
+                    <div class="input-box-container">
+                      <p>
+                        <i class="fas fa-dollar-sign"></i>
+                      </p>
+                      <input
+                        type="text"
+                        formControlName="monto"
+                        class="form-control"
+                        [ngClass]="{
+                          'is-invalid': submitted && f.monto.errors
+                        }"
+                      />
+                      <div
+                        *ngIf="submitted && f.monto.errors"
+                        class="invalid-feedback"
+                      >
+                        <div *ngIf="f.monto.errors.required">
+                          Campo requerido
+                        </div>
+                        <div *ngIf="f.monto.errors.pattern">
+                          Debe ingresar una cifra válida
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+
+                <div class="col-lg-6 col-sm-12 pr-xl-3">
+                  <div class="form-group">
+                    <label for="payment_types">Tipo pago: </label>
+
+                    <select
+                      class="custom-select"
+                      formControlName="tipo_pago"
+                      [ngClass]="{
+                        'is-invalid': submitted && f.tipo_pago.errors
+                      }"
+                    >
+                      <option
+                        *ngFor="let item of payment_types"
+                        [value]="item.id_tipo_pago"
+                      >
+                        {{ item.nombre }}</option
+                      >
+                    </select>
+                    <div
+                      *ngIf="submitted && f.tipo_pago.errors"
+                      class="invalid-feedback"
+                    >
+                      <div *ngIf="f.tipo_pago.errors.required">
+                        Campo requerido
+                      </div>
+                    </div>
+                  </div>
+                </div>
+
+                <div class="col-lg-6 col-sm-12 pr-xl-3">
+                  <div class="form-group">
+                    <label for="cuenta_bancaria">Cuenta bancaria: </label>
+
+                    <select
+                      class="custom-select"
+                      formControlName="cuenta_bancaria"
+                      [ngClass]="{
+                        'is-invalid': submitted && f.cuenta_bancaria.errors
+                      }"
+                    >
+                      <option
+                        *ngFor="let item of accounts"
+                        [value]="item.id_cuenta_bancaria"
+                      >
+                        {{ nameBankAccounts(item.id_banco) }} -
+                        {{ item.nombre }}</option
+                      >
+                    </select>
+                    <div
+                      *ngIf="submitted && f.cuenta_bancaria.errors"
+                      class="invalid-feedback"
+                    >
+                      <div *ngIf="f.cuenta_bancaria.errors.required">
+                        Campo requerido
+                      </div>
+                    </div>
+                  </div>
+                </div>
+
+                <!-- Fecha vencimiento -->
+                <div class="col-lg-6 col-sm-12 pr-xl-3">
+                  <div class="form-group">
+                    <label for="fecha_vencimiento">Fecha vencimiento: </label>
+
+                    <div class="input-box-container">
+                      <div>
+                        <p>
+                          <i class="far fa-calendar" aria-hidden="true"></i>
+                        </p>
+                        <input
+                          class="input-box form-control"
+                          placeholder="Seleccione una fecha"
+                          angular-mydatepicker
+                          formControlName="fecha_vencimiento"
+                          (click)="dp2.toggleCalendar()"
+                          [options]="myDpOptions"
+                          #dp2="angular-mydatepicker"
+                          [ngClass]="{
+                            'is-invalid':
+                              submitted && f.fecha_vencimiento.errors
+                          }"
+                        />
+                      </div>
+                    </div>
+
+                    <div
+                      *ngIf="submitted && f.fecha_vencimiento.errors"
+                      class="invalid-feedback"
+                    >
+                      <div *ngIf="f.fecha_vencimiento.errors.required">
+                        Campo requerido
+                      </div>
+                    </div>
+                  </div>
+                </div>
+
+                <div class="col-lg-12 col-sm-12 pr-xl-12">
+                  <div class="form-group text-right">
+                    <br />
+                    <button
+                      class="btn btn-primary center-component"
+                      type="submit"
+                      (click)="sendPaymentInfo(investmentProposalForm)"
+                    >
+                      Enviar información de pago
+                    </button>
+                  </div>
+                </div>
+              </div>
+            </form>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 208 - 0
src/app/components/investment-proposals/payment-info/payment-info.component.ts

@@ -0,0 +1,208 @@
+import { Component, OnInit } from "@angular/core";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { IAngularMyDpOptions, IMyDateModel } from "angular-mydatepicker";
+import { formatDate, DatePipe } from "@angular/common";
+import { parse } from "date-fns";
+import { Router, ActivatedRoute } from "@angular/router";
+import { InvestmentsService } from "@app/services/investments.service";
+import Swal from "sweetalert2";
+
+@Component({
+  selector: "app-payment-info",
+  templateUrl: "./payment-info.component.html"
+})
+export class PaymentInfoComponent implements OnInit {
+  title: string = "Formulario de información para el pago";
+
+  form: any;
+
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+
+  investmentProposalForm: FormGroup;
+  submitted: boolean = false;
+  role_number: any;
+  markets: any;
+  emitters: any;
+  periodicities: any;
+  rate_agencies: any;
+  scores: any;
+  investmentProposalID: string;
+  funds: any;
+  companies: any;
+  format_incomes: any;
+  operations: any;
+  payment_terms: any;
+  payment_types: any;
+  inversionCode: any;
+  paymentProposal: any;
+  banks: any;
+  accounts: any;
+  paymentObject: Object;
+
+  constructor(
+    private router: Router,
+    private route: ActivatedRoute,
+    private formBuilder: FormBuilder,
+    private formDataService: FormInvestmentProposalService,
+    private catalogService: CatalogsService,
+    private investmentsService: InvestmentsService
+  ) {}
+
+  ngOnInit() {
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    this.investmentsService
+      .getProposalInvestment(this.investmentProposalID)
+      .subscribe(
+        res => {
+          this.inversionCode = res["result"]["codigo_inversion"];
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: err.message
+          });
+        }
+      );
+
+    this.catalogService.getPaymentTypes().subscribe(res => {
+      this.payment_types = res;
+    });
+    this.catalogService.getCountries().subscribe(res => {
+      this.funds = res;
+    });
+    this.catalogService.getCatalogInfo("bancos").subscribe(res => {
+      this.banks = res;
+      this.catalogService.getCatalogInfo("cuentas-bancarias").subscribe(res => {
+        this.accounts = res;
+      });
+      //this.payment_types = res;
+    });
+
+    this.investmentProposalForm = this.formBuilder.group({
+      monto: [
+        "",
+        [
+          Validators.required,
+          Validators.pattern(/^[+]?([0-9]+(?:[\.][0-9]*)?|\.[0-9]+)$/)
+        ]
+      ],
+      tipo_pago: ["", Validators.required],
+      cuenta_bancaria: ["", Validators.required],
+      fecha_vencimiento: ["", Validators.required]
+    });
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  nameBankAccounts(id: string) {
+    let bank;
+    bank = this.banks.find(e => e.id_banco == id);
+    return bank.nombre;
+  }
+
+  sendPaymentInfo(form: any) {
+    this.submitted = true;
+    console.log(form);
+    if (!form.valid) {
+      return false;
+    }
+
+    this.paymentProposal = {
+      id_inversion: this.investmentProposalID,
+      step: "next",
+      comentario: "Informacion de pago"
+    };
+
+    this.paymentObject = {
+      monto: this.investmentProposalForm.value.monto,
+      id_tipo_pago: this.investmentProposalForm.value.tipo_pago,
+      id_cuenta_bancaria: this.investmentProposalForm.value.cuenta_bancaria,
+      //fecha_pago: this.investmentProposalForm.value.fecha_pago.singleDate.formatted,
+      fecha_vencimiento: this.investmentProposalForm.value.fecha_vencimiento
+        .singleDate.formatted,
+      id_inversion: this.investmentProposalID
+    };
+
+    this.investmentsService
+      .sendPaymentInfoProposalInvestment(
+        this.investmentProposalID,
+        this.paymentObject
+      )
+      .subscribe(
+        success => {
+          this.investmentsService
+            .sendProposalInvestmentToNextStep(this.paymentProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La requisicion de pago ha sido generada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error al guardar",
+            text: err.message
+          });
+        }
+      );
+  }
+}

+ 173 - 0
src/app/components/investment-proposals/payment-requirement/payment-requirement.component.html

@@ -0,0 +1,173 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Requisición</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Requisición
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <div class="instrument-calcs">
+                  <div class="row">
+                    <div class="col-12">
+                      <span class="badge badge-success badge-custom"
+                        >Información del pago</span
+                      >
+                    </div>
+
+                    <div class="col-sm-6">
+                      <h4>Código de la propuesta de inversión:</h4>
+                      <div class="field">{{ codigo_inversion }}</div>
+                    </div>
+                    <div class="col-sm-6">
+                      <h4>Monto:</h4>
+                      <div class="field">
+                        $USD {{ monto | number: "1.2-4" }}
+                      </div>
+                    </div>
+                    <div class="col-sm-6">
+                      <h4>Código:</h4>
+                      <div class="field">{{ codigo }}</div>
+                    </div>
+                    <div class="col-sm-6">
+                      <h4>Tipo pago:</h4>
+                      <div class="field">{{ tipo_pago }}</div>
+                    </div>
+                    <div class="col-sm-6">
+                      <h4>Cuenta bancaria:</h4>
+                      <div class="field">{{ cuenta_bancaria }}</div>
+                    </div>
+
+                    <div class="col-sm-6">
+                      <h4>Fecha de vencimiento:</h4>
+                      <div class="field">{{ fecha_vencimiento }}</div>
+                    </div>
+                  </div>
+                </div>
+
+                <br />
+
+                <form
+                  class="form-auth-small ng-untouched ng-pristine ng-valid"
+                  [formGroup]="investmentProposalForm"
+                >
+                  <div class="row">
+                    <div class="col-lg-6 col-sm-12 pr-xl-6">
+                      <div class="form-group">
+                        <label for="justificacion">Archivo: </label>
+
+                        <input
+                          type="file"
+                          name="evidencia"
+                          (change)="fileProgress($event)"
+                        />
+                      </div>
+                      <br />
+                      <div *ngIf="fileUploadProgress">
+                        Progreso: {{ fileUploadProgress }}
+                      </div>
+                      <div class="image-preview mb-3" *ngIf="previewUrl">
+                        <img [src]="previewUrl" height="300" />
+                      </div>
+
+                      <div class="mb-3" *ngIf="uploadedFilePath">
+                        {{ uploadedFilePath }}
+                      </div>
+                    </div>
+                    <!-- Fecha operación -->
+                    <div class="col-lg-6 col-sm-12 pr-xl-3">
+                      <div class="form-group">
+                        <label for="fecha_pago">Fecha pago: </label>
+                        <div class="input-box-container">
+                          <p>
+                            <i class="far fa-calendar" aria-hidden="true"></i>
+                          </p>
+                          <input
+                            class="input-box form-control"
+                            placeholder="Seleccione una fecha"
+                            angular-mydatepicker
+                            formControlName="fecha_pago"
+                            (click)="dp.toggleCalendar()"
+                            [options]="myDpOptions"
+                            #dp="angular-mydatepicker"
+                            [ngClass]="{
+                              'is-invalid': submitted && f.fecha_pago.errors
+                            }"
+                          />
+                        </div>
+
+                        <div
+                          *ngIf="submitted && f.fecha_pago.errors"
+                          class="invalid-feedback"
+                        >
+                          <div *ngIf="f.fecha_pago.errors.required">
+                            Campo requerido
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+
+                    <div class="col-lg-6 col-sm-12 pr-xl-6">
+                      <div class="form-group">
+                        <label for="comentario">Comentario: </label>
+
+                        <textarea
+                          rows="2"
+                          class="form-control"
+                          formControlName="comentario"
+                        ></textarea>
+                      </div>
+                    </div>
+                  </div>
+                  <br />
+                  <div class="row">
+                    <div class="col-lg-12 col-sm-12 align-right">
+                      <div class="form-group">
+                        <button
+                          class="btn btn-primary"
+                          (click)="onSubmit(investmentProposalForm)"
+                          type="submit"
+                        >
+                          Enviar requisición de pago
+                        </button>
+                      </div>
+                    </div>
+                  </div>
+                  <br />
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 27 - 0
src/app/components/investment-proposals/payment-requirement/payment-requirement.component.scss

@@ -0,0 +1,27 @@
+.area {
+  width: 77%;
+  padding: 15px;
+  margin: 15px;
+  border: 1px solid #333;
+  background: rgba(0, 0, 0, 0.7);
+}
+
+#dropZone {
+  border: 2px dashed #bbb;
+  -webkit-border-radius: 5px;
+  border-radius: 5px;
+  padding: 50px;
+  text-align: center;
+  font: 21pt bold arial;
+  color: #bbb;
+}
+
+.drop-file-over {
+  background: #333;
+}
+
+.form-group input[type="file"] {
+  opacity: 1;
+  z-index: 1;
+  position: relative;
+}

+ 6 - 6
src/app/components/users/new-user/new-user.component.spec.ts → src/app/components/investment-proposals/payment-requirement/payment-requirement.component.spec.ts

@@ -1,20 +1,20 @@
 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { NewUserComponent } from './new-user.component';
+import { PaymentRequirementComponent } from './payment-requirement.component';
 
-describe('NewUserComponent', () => {
-  let component: NewUserComponent;
-  let fixture: ComponentFixture<NewUserComponent>;
+describe('PaymentRequirementComponent', () => {
+  let component: PaymentRequirementComponent;
+  let fixture: ComponentFixture<PaymentRequirementComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ NewUserComponent ]
+      declarations: [ PaymentRequirementComponent ]
     })
     .compileComponents();
   }));
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(NewUserComponent);
+    fixture = TestBed.createComponent(PaymentRequirementComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });

+ 207 - 0
src/app/components/investment-proposals/payment-requirement/payment-requirement.component.ts

@@ -0,0 +1,207 @@
+import { Component, OnInit, ComponentFactoryResolver } from "@angular/core";
+import { FileUploader, FileLikeObject } from "ng2-file-upload";
+import { concat } from "rxjs";
+import { FormBuilder, FormGroup, Validators } from "@angular/forms";
+import { HttpClient, HttpEventType } from "@angular/common/http";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentsService } from "@app/services/instruments.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { ActivatedRoute } from "@angular/router";
+import { InvestmentsService } from "@app/services/investments.service";
+import Swal from "sweetalert2";
+import { IAngularMyDpOptions } from "angular-mydatepicker";
+
+@Component({
+  selector: "app-payment-requirement",
+  templateUrl: "./payment-requirement.component.html",
+  styleUrls: ["./payment-requirement.component.scss"]
+})
+export class PaymentRequirementComponent implements OnInit {
+  title: string = "Formulario de requisición de pago";
+  // For daterange
+  daysLabels: any = {
+    su: "Dom",
+    mo: "Lun",
+    tu: "Mar",
+    we: "Mie",
+    th: "Jue",
+    fr: "Vie",
+    sa: "Sab"
+  };
+  monthsLabels: any = {
+    1: "Ene",
+    2: "Feb",
+    3: "Mar",
+    4: "Abr",
+    5: "May",
+    6: "Jun",
+    7: "Jul",
+    8: "Ago",
+    9: "Sep",
+    10: "Oct",
+    11: "Nov",
+    12: "Dic"
+  };
+  myDpOptions: IAngularMyDpOptions = {
+    dateRange: false,
+    dateFormat: "dd/mm/yyyy",
+    dayLabels: this.daysLabels,
+    monthLabels: this.monthsLabels
+  };
+  myDateInit: boolean = true;
+
+  form: FormGroup;
+  fileData: File = null;
+  previewUrl: any = null;
+  fileUploadProgress: string = null;
+  uploadedFilePath: string = null;
+  interval: any;
+  indexDynamicComponent: number;
+  investmentProposalID: string;
+  investmentExists;
+  monto: string = "";
+  codigo_inversion: string = "";
+  codigo: string = "";
+  tipo_pago: string = "";
+  cuenta_bancaria: string = "";
+  fecha_pago: string = "";
+  fecha_vencimiento: string = "";
+  investmentProposalForm: FormGroup;
+  submitted: boolean = false;
+  paymentObject: Object;
+
+  constructor(
+    private http: HttpClient,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService,
+    private catalogService: CatalogsService,
+    private route: ActivatedRoute,
+    private investmentService: InvestmentsService,
+    private formBuilder: FormBuilder,
+
+    private investmentsService: InvestmentsService
+  ) {}
+
+  ngOnInit() {
+    //this.formDataService
+    //this.ads = this.loadInstrumentsService.getInstruments();
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    this.investmentService
+      .getPaymentInfoProposalInvestment(this.investmentProposalID)
+      .subscribe(resp => {
+        this.monto = resp["result"]["monto"];
+        this.codigo_inversion =
+          resp["result"]["id_inversion"]["codigo_inversion"];
+        this.codigo = resp["result"]["codigo"];
+        this.tipo_pago = resp["result"]["id_tipo_pago"]["nombre"];
+        this.cuenta_bancaria = resp["result"]["id_cuenta_bancaria"]["nombre"];
+        this.fecha_vencimiento = resp["result"]["fecha_vencimiento"];
+      });
+
+    this.investmentProposalForm = this.formBuilder.group({
+      comentario: [""],
+      fecha_pago: ["", Validators.required]
+    });
+  }
+
+  fileProgress(fileInput: any) {
+    this.fileData = <File>fileInput.target.files[0];
+    this.preview();
+  }
+
+  preview() {
+    // Show preview
+    var mimeType = this.fileData.type;
+    if (mimeType.match(/image\/*/) == null) {
+      return;
+    }
+
+    var reader = new FileReader();
+    reader.readAsDataURL(this.fileData);
+    reader.onload = _event => {
+      this.previewUrl = reader.result;
+    };
+  }
+
+  get f() {
+    return this.investmentProposalForm.controls;
+  }
+
+  onSubmit(form: any) {
+    this.submitted = true;
+    console.log(form);
+    if (!form.valid) {
+      return false;
+    }
+
+    this.paymentObject = {
+      fecha_pago: form.value.fecha_pago.singleDate.formatted,
+      id_inversion: this.investmentProposalID
+      //comentario:
+    };
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    const formData = new FormData();
+    formData.append("id_inversion", this.investmentProposalID);
+    formData.append("evidencia", this.fileData);
+    formData.append("step", "next");
+    formData.append("comentario", form.value.comentario);
+
+    this.investmentsService
+      .updatePaymentInfoProposalInvestment(
+        this.investmentProposalID,
+        this.paymentObject
+      )
+      .subscribe(
+        success => {
+          this.investmentService
+            .sendProposalInvestmentToNextStep(formData)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido liquidada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error en el servidor",
+                  text: err.message
+                });
+              }
+            );
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error en el servidor",
+            text: err.message
+          });
+        }
+      );
+  }
+}

+ 172 - 0
src/app/components/investment-proposals/proposal-detail/proposal-detail.component.html

@@ -0,0 +1,172 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Detalle propuesta</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Resumen de la propuesta
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ul class="timeline timeline-simple">
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-success"
+                          >Información general</span
+                        >
+                      </div>
+                      <div class="timeline-body">
+                        <div class="row">
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Asunto:</h4>
+                            <div class="field">
+                              {{ subject }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Orígenes de fondo:</h4>
+                            <div class="field">
+                              {{ funds }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Nombre:</h4>
+                            <div class="field">
+                              {{ investmentName }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Tasa:</h4>
+                            <div class="field">
+                              {{ rates }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Renta:</h4>
+                            <div class="field">
+                              {{ revenues }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Periodicidad:</h4>
+                            <div class="field">
+                              {{ periodicities }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Instrumentos:</h4>
+                            <div class="field">
+                              {{ instrumentTypes }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Casa:</h4>
+                            <div class="field">
+                              {{ financials }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Base:</h4>
+                            <div class="field">
+                              {{ base_types }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo de mercado:</h4>
+                            <div class="field">
+                              {{ markets }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Emisores:</h4>
+                            <div class="field">
+                              {{ emitters }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Empresa:</h4>
+                            <div class="field">
+                              {{ companies }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>País:</h4>
+                            <div class="field">
+                              {{ countries }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Plazo:</h4>
+                            <div class="field">
+                              {{ payment_terms }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipos de operaciones:</h4>
+                            <div class="field">
+                              {{ operations }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Comentarios:</h4>
+                            <div class="field">
+                              {{ comment }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Justificación:</h4>
+                            <div class="field">
+                              {{ justification }}
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </li>
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-warning">Instrumento</span>
+                      </div>
+                      <ng-template instrument-host></ng-template>
+                    </div>
+                  </li>
+                </ul>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 6 - 0
src/app/components/investment-proposals/proposal-detail/proposal-detail.component.scss

@@ -0,0 +1,6 @@
+.review-buttons {
+  text-align: center;
+  button {
+    margin: 0 20px;
+  }
+}

+ 325 - 0
src/app/components/investment-proposals/proposal-detail/proposal-detail.component.ts

@@ -0,0 +1,325 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "@app/components/investment-proposals/instrument/instrument.directive";
+import { InstrumentComponent } from "@app/components/investment-proposals/instrument/instrument.component";
+import { InstrumentsService } from "@app/services/instruments.service";
+import Swal from "sweetalert2";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+
+@Component({
+  selector: "app-investment-proposal-detail",
+  templateUrl: "./proposal-detail.component.html",
+  styleUrls: ["./proposal-detail.component.scss"]
+})
+export class InvestmentProposalDetailComponent implements OnInit {
+  title = "Detalle de la propuesta de inversión";
+  @Input() ads: Instrument[];
+  @Input() formData: InvestmentProposalForm;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  isFormValid: boolean = false;
+  general: any;
+  instrument: any;
+  complement: any;
+  final: any;
+  workType: string;
+  form: any;
+  currentAdIndex = -1;
+  interval: any;
+  indexDynamicComponent: number;
+  investmentProposalID: string;
+  investmentExists;
+  state;
+  financials;
+  base_types;
+  countries;
+  companies;
+  rates;
+  revenues;
+  funds;
+  instrumentTypes;
+  markets;
+  emitters;
+  periodicities;
+  format_incomes;
+  payment_terms;
+  operations;
+  gInfo: any;
+  gInstrument: any;
+  gComplement: any;
+  subject: any;
+  investmentName: any;
+  comment: any;
+  justification: any;
+
+  constructor(
+    private router: Router,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService,
+    private catalogService: CatalogsService,
+    private route: ActivatedRoute,
+    private investmentService: InvestmentsService
+  ) {}
+
+  ngOnInit() {
+    //this.formDataService
+
+    this.ads = this.loadInstrumentsService.getInstruments();
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    if (this.investmentProposalID != undefined) {
+      this.investmentExists = true;
+      this.investmentService
+        .getProposalInvestment(this.investmentProposalID)
+        .subscribe(res => {
+          this.state = res["result"]["id_estado_inversion"]["codigo"];
+
+          this.gInfo = {
+            asunto: res["result"]["asunto"],
+            origenes_fondo:
+              res["result"]["id_origen_fondo"] == null
+                ? ""
+                : res["result"]["id_origen_fondo"]["id_origen_fondo"],
+            name: res["result"]["nombre_inversion"],
+            //date: "",
+            tipo_tasa: res["result"]["id_tipo_tasa"] || "",
+            tipo_renta:
+              res["result"]["id_tipo_renta"] == null
+                ? ""
+                : res["result"]["id_tipo_renta"]["id_tipo_renta"],
+            periodicidad:
+              res["result"]["id_periodicidad"] == null
+                ? ""
+                : res["result"]["id_periodicidad"]["id_periodicidad"],
+
+            instrumentos:
+              res["result"]["id_inversion_instrumento"]["id_tipo_instrumento"][
+                "codigo"
+              ],
+            base_anual:
+              res["result"]["id_tipo_base"] == null
+                ? ""
+                : res["result"]["id_tipo_base"]["id_tipo_base"],
+            casa:
+              res["result"]["id_entidad"] == null
+                ? ""
+                : res["result"]["id_entidad"]["id_entidad_financiera"],
+            formato_ingreso:
+              res["result"]["id_formato_ingreso"] == null
+                ? ""
+                : res["result"]["id_formato_ingreso"]["id_formato_ingreso"]
+          };
+
+          this.gInstrument =
+            res["result"]["id_inversion_instrumento"]["instrumento"];
+
+          this.gInstrument["id_inversion_instrumento"] =
+            res["result"]["id_inversion_instrumento"][
+              "id_inversion_instrumento"
+            ];
+
+          this.gComplement = {
+            tipo_mercado:
+              res["result"]["id_tipo_mercado"] == null
+                ? ""
+                : res["result"]["id_tipo_mercado"]["id_tipo_mercado"],
+            emisores:
+              res["result"]["id_tipo_emisor"] == null
+                ? ""
+                : res["result"]["id_tipo_emisor"]["id_tipo_emisor"],
+            empresa:
+              res["result"]["id_empresa"] == null
+                ? ""
+                : res["result"]["id_empresa"]["id_empresa"],
+            pais:
+              res["result"]["id_pais"] == null
+                ? ""
+                : res["result"]["id_pais"]["id_pais"],
+            plazo:
+              res["result"]["id_plazo"] == null
+                ? ""
+                : res["result"]["id_plazo"]["id_plazo"],
+            operaciones:
+              res["result"]["id_tipo_operacion"] == null
+                ? ""
+                : res["result"]["id_tipo_operacion"]["id_tipo_operacion"],
+            comentarios: res["result"]["comentario"],
+            justificacion: res["result"]["justificacion"]
+          };
+          this.formDataService.setGeneralInfo(this.gInfo);
+
+          this.formDataService.setWork(this.gInstrument);
+
+          this.formDataService.setComplementInfo(this.gComplement);
+
+          this.general = this.formDataService.getGeneralInfo();
+          this.instrument = this.formDataService.getWork();
+          this.complement = this.formDataService.getComplementInfo();
+          this.formData = this.formDataService.getFormData();
+
+          this.formData.instrumentos;
+
+          this.indexDynamicComponent = this.ads.findIndex(
+            x => x.data.key == this.formData.instrumentos
+          );
+          if (this.indexDynamicComponent >= 0) {
+            this.loadComponent();
+          } else {
+            console.log("No existe el componente");
+          }
+          if (this.general != undefined) {
+            this.subject = this.general.asunto;
+            this.investmentName = this.general.name;
+            this.comment = this.complement.comment;
+            this.justification = this.complement.comment;
+
+            this.catalogService.getFinancialEntities().subscribe(res => {
+              this.financials = res.find(
+                e => e.id_entidad_financiera == this.general.casa
+              );
+              this.financials =
+                this.financials != undefined ? this.financials.nombre : "-";
+            });
+
+            this.catalogService.getBaseTypes().subscribe(res => {
+              this.base_types = res.find(
+                e => e.id_tipo_base == this.general.base_anual
+              );
+              this.base_types =
+                this.base_types != undefined
+                  ? ` ${this.base_types.tipo_base} / ${this.base_types.tipo_base_dias}`
+                  : "-";
+            });
+
+            this.catalogService.getCountries().subscribe(res => {
+              this.countries = res.find(e => e.id_pais == this.complement.pais);
+              this.countries =
+                this.countries != undefined ? this.countries.nombre : "-";
+            });
+            this.catalogService.getCompanies().subscribe(res => {
+              this.companies = res.find(
+                e => e.id_empresa == this.complement.empresa
+              );
+              this.companies =
+                this.companies != undefined ? this.companies.nombre : "-";
+            });
+            this.catalogService.getRateTypes().subscribe(res => {
+              this.rates = res.find(
+                e => e.id_tipo_tasa == this.general.tipo_tasa
+              );
+              this.rates = this.rates != undefined ? this.rates.nombre : "-";
+            });
+            this.catalogService.getRevenueTypes().subscribe(res => {
+              this.revenues = res.find(
+                e => e.id_tipo_renta == this.general.tipo_renta
+              );
+              this.revenues =
+                this.revenues != undefined ? this.revenues.nombre : "-";
+            });
+
+            this.catalogService.getFundsOrigins().subscribe(res => {
+              this.funds = res.find(
+                e => e.id_origen_fondo == this.general.origenes_fondo
+              );
+              this.funds = this.funds != undefined ? this.funds.nombre : "-";
+            });
+            this.catalogService.getInstrumentTypes().subscribe(res => {
+              this.instrumentTypes = res.find(
+                e => e.codigo == this.general.instrumentos
+              );
+              this.instrumentTypes =
+                this.instrumentTypes != undefined
+                  ? this.instrumentTypes.nombre
+                  : "-";
+            });
+
+            this.catalogService.getMarketTypes().subscribe(res => {
+              this.markets = res.find(
+                e => e.id_tipo_mercado == this.complement.tipo_mercado
+              );
+              this.markets =
+                this.markets != undefined ? this.markets.nombre : "-";
+            });
+            this.catalogService.getEmitterTypes().subscribe(res => {
+              this.emitters = res.find(
+                e => e.id_tipo_emisor == this.complement.emisores
+              );
+              this.emitters =
+                this.emitters != undefined ? this.emitters.nombre : "-";
+            });
+            this.catalogService.getPeriodicities().subscribe(res => {
+              this.periodicities = res.find(
+                e => e.id_periodicidad == this.general.periodicidad
+              );
+              this.periodicities =
+                this.periodicities != undefined
+                  ? this.periodicities.nombre
+                  : "-";
+            });
+            this.catalogService.getPaymentTerms().subscribe(res => {
+              this.payment_terms = res.find(
+                e => e.id_plazo == this.complement.plazo
+              );
+              this.payment_terms =
+                this.payment_terms != undefined
+                  ? this.payment_terms.nombre
+                  : "-";
+            });
+            this.catalogService.getOperationTypes().subscribe(res => {
+              this.operations = res.find(
+                e => e.id_tipo_operacion == this.complement.operaciones
+              );
+              this.operations =
+                this.operations != undefined ? this.operations.nombre : "-";
+            });
+
+            //getIncomeFormat
+            this.catalogService.getIncomeFormat().subscribe(res => {
+              this.format_incomes = res.find(
+                e => e.id_formato_ingreso == this.general.formato_ingreso
+              );
+              this.format_incomes =
+                this.format_incomes != undefined
+                  ? this.format_incomes.nombre
+                  : "-";
+            });
+          }
+        });
+    } else {
+      this.investmentExists = false;
+    }
+    Swal.close();
+  }
+
+  loadComponent() {
+    const adItem = this.ads[this.indexDynamicComponent];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = true;
+  }
+}

+ 243 - 0
src/app/components/investment-proposals/result/result.component.html

@@ -0,0 +1,243 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Nueva</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <inv-proposal-navbar
+            [activeLink]="'result'"
+            [investmentID]="investmentProposalID"
+          ></inv-proposal-navbar>
+
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Resumen de la propuesta
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ul class="timeline timeline-simple">
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-success"
+                          >Información general</span
+                        >
+                      </div>
+                      <div class="timeline-body">
+                        <div class="row">
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Asunto:</h4>
+                            <div class="field">
+                              {{ general.asunto }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Orígenes de fondo:</h4>
+                            <div class="field">
+                              {{ funds }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Nombre:</h4>
+                            <div class="field">
+                              {{ general.name }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Tasa:</h4>
+                            <div class="field">
+                              {{ rates }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Renta:</h4>
+                            <div class="field">
+                              {{ revenues }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Periodicidad:</h4>
+                            <div class="field">
+                              {{ periodicities }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Instrumentos:</h4>
+                            <div class="field">
+                              {{ instrumentTypes }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Casa:</h4>
+                            <div class="field">
+                              {{ financials }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Base:</h4>
+                            <div class="field">
+                              {{ base_types }}
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </li>
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-warning">Instrumento</span>
+                        <ng-template instrument-host></ng-template>
+                      </div>
+                    </div>
+                  </li>
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-primary"
+                          >Información complementaria</span
+                        >
+                      </div>
+                      <div class="timeline-body">
+                        <div class="row">
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo de mercado:</h4>
+                            <div class="field">
+                              {{ markets }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Emisores:</h4>
+                            <div class="field">
+                              {{ emitters }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Empresa:</h4>
+                            <div class="field">
+                              {{ companies }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>País:</h4>
+                            <div class="field">
+                              {{ countries }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Plazo:</h4>
+                            <div class="field">
+                              {{ payment_terms }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipos de operaciones:</h4>
+                            <div class="field">
+                              {{ operations }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Comentarios:</h4>
+                            <div class="field">
+                              {{ complement.comentarios }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Justificación:</h4>
+                            <div class="field">
+                              {{ complement.justificacion }}
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </li>
+                </ul>
+
+                <div *ngIf="!investmentExists" class="text-center">
+                  <button
+                    class="btn btn-success center-component"
+                    [disabled]="!isFormValid"
+                    (click)="submit()"
+                    type="button"
+                  >
+                    Guardar propuesta
+                  </button>
+                </div>
+
+                <div *ngIf="investmentExists">
+                  <a
+                    class="btn btn-default center-component margin-right float-left"
+                    href="#/investment-proposals"
+                  >
+                    Ir a listado
+                  </a>
+
+                  <button
+                    *ngIf="can_finish_proposal(state)"
+                    class="btn btn-primary center-component float-right"
+                    type="button"
+                    (click)="finishProposal()"
+                  >
+                    Finalizar
+                  </button>
+
+                  <button
+                    *ngIf="can_send_to_review(state)"
+                    class="btn btn-primary center-component float-right"
+                    type="button"
+                    (click)="sendToReview()"
+                  >
+                    Enviar a revision
+                  </button>
+                  <button
+                    class="btn btn-success center-component margin-right float-right"
+                    type="button"
+                    (click)="update_proposal()"
+                  >
+                    Guardar propuesta
+                  </button>
+                  <button
+                    class="btn btn-default center-component margin-right float-right"
+                    type="button"
+                    (click)="goToPrevious()"
+                  >
+                    Anterior
+                  </button>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 8 - 0
src/app/components/investment-proposals/result/result.component.scss

@@ -0,0 +1,8 @@
+h4 {
+  margin: 0 !important;
+}
+
+.field {
+  margin-bottom: 10px;
+  color: green;
+}

+ 477 - 0
src/app/components/investment-proposals/result/result.component.ts

@@ -0,0 +1,477 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "../instrument/instrument.directive";
+import { InstrumentComponent } from "../instrument/instrument.component";
+import { InstrumentsService } from "@app/services/instruments.service";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+import { AuthService } from "@app/services/auth2.service";
+import { JwtHelperService } from "@auth0/angular-jwt";
+import Swal from "sweetalert2";
+
+@Component({
+  selector: "mt-wizard-result",
+  templateUrl: "./result.component.html",
+  styleUrls: ["./result.component.scss"]
+})
+export class ResultComponent implements OnInit {
+  helper = new JwtHelperService();
+
+  title = "Resumen de la propuesta";
+  @Input() ads: Instrument[];
+  @Input() formData: InvestmentProposalForm;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  isFormValid: boolean = false;
+  general: any;
+  instrument: any;
+  complement: any;
+  final: any;
+  workType: string;
+  form: any;
+  currentAdIndex = -1;
+  interval: any;
+  indexDynamicComponent: number;
+  countries: any;
+  companies: any;
+  rates: any;
+  revenues: any;
+  funds: any;
+  instrumentTypes: any;
+  markets: any;
+  emitters: any;
+  periodicities: any;
+  operations: any;
+  format_incomes: any;
+  base_types: any;
+  payment_terms: any;
+  financials: any;
+  inversion: {};
+  investmentProposalID: string;
+  investmentExists: boolean = false;
+  reviewProposal: {};
+  userRole: any;
+  state: string = "";
+  submitted: boolean = false;
+
+  constructor(
+    private router: Router,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService,
+    private catalogService: CatalogsService,
+    private investmentService: InvestmentsService,
+    private route: ActivatedRoute,
+    private authService: AuthService
+  ) {
+    this.formData = this.formDataService.getFormData();
+    this.isFormValid = this.formDataService.isFormValid();
+    this.ads = this.loadInstrumentsService.getInstruments();
+
+    const decodedToken = this.helper.decodeToken(
+      this.authService.getJwtToken()
+    );
+
+    this.userRole = decodedToken.groups;
+  }
+
+  ngOnInit() {
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    if (this.investmentProposalID != undefined) {
+      this.investmentExists = true;
+      this.investmentService
+        .getProposalInvestment(this.investmentProposalID)
+        .subscribe(res => {
+          this.state = res["result"]["id_estado_inversion"]["codigo"];
+        });
+    } else {
+      this.investmentExists = false;
+    }
+
+    this.formData.instrumentos;
+    this.indexDynamicComponent = this.ads.findIndex(
+      x => x.data.key == this.formData.instrumentos
+    );
+    if (this.indexDynamicComponent >= 0) {
+      this.loadComponent();
+    } else {
+      console.log("No existe el componente");
+    }
+
+    this.general = this.formDataService.getGeneralInfo();
+    this.instrument = this.formDataService.getWork();
+    this.complement = this.formDataService.getComplementInfo();
+
+    this.catalogService.getFinancialEntities().subscribe(res => {
+      this.financials = res.find(
+        e => e.id_entidad_financiera == this.general.casa
+      );
+      this.financials =
+        this.financials != undefined ? this.financials.nombre : "-";
+    });
+
+    this.catalogService.getBaseTypes().subscribe(res => {
+      this.base_types = res.find(
+        e => e.id_tipo_base == this.general.base_anual
+      );
+      this.base_types =
+        this.base_types != undefined
+          ? ` ${this.base_types.tipo_base} / ${this.base_types.tipo_base_dias}`
+          : "-";
+    });
+
+    this.catalogService.getCountries().subscribe(res => {
+      this.countries = res.find(e => e.id_pais == this.complement.pais);
+      this.countries =
+        this.countries != undefined ? this.countries.nombre : "-";
+    });
+    this.catalogService.getCompanies().subscribe(res => {
+      this.companies = res.find(e => e.id_empresa == this.complement.empresa);
+      this.companies =
+        this.companies != undefined ? this.companies.nombre : "-";
+    });
+    this.catalogService.getRateTypes().subscribe(res => {
+      this.rates = res.find(e => e.id_tipo_tasa == this.general.tipo_tasa);
+      this.rates = this.rates != undefined ? this.rates.nombre : "-";
+    });
+    this.catalogService.getRevenueTypes().subscribe(res => {
+      this.revenues = res.find(e => e.id_tipo_renta == this.general.tipo_renta);
+      this.revenues = this.revenues != undefined ? this.revenues.nombre : "-";
+    });
+
+    this.catalogService.getFundsOrigins().subscribe(res => {
+      this.funds = res.find(
+        e => e.id_origen_fondo == this.general.origenes_fondo
+      );
+      this.funds = this.funds != undefined ? this.funds.nombre : "-";
+    });
+    this.catalogService.getInstrumentTypes().subscribe(res => {
+      this.instrumentTypes = res.find(
+        e => e.codigo == this.general.instrumentos
+      );
+      this.instrumentTypes =
+        this.instrumentTypes != undefined ? this.instrumentTypes.nombre : "-";
+    });
+
+    this.catalogService.getMarketTypes().subscribe(res => {
+      this.markets = res.find(
+        e => e.id_tipo_mercado == this.complement.tipo_mercado
+      );
+      this.markets = this.markets != undefined ? this.markets.nombre : "-";
+    });
+    this.catalogService.getEmitterTypes().subscribe(res => {
+      this.emitters = res.find(
+        e => e.id_tipo_emisor == this.complement.emisores
+      );
+      this.emitters = this.emitters != undefined ? this.emitters.nombre : "-";
+    });
+    this.catalogService.getPeriodicities().subscribe(res => {
+      this.periodicities = res.find(
+        e => e.id_periodicidad == this.general.periodicidad
+      );
+      this.periodicities =
+        this.periodicities != undefined ? this.periodicities.nombre : "-";
+    });
+    this.catalogService.getPaymentTerms().subscribe(res => {
+      this.payment_terms = res.find(e => e.id_plazo == this.complement.plazo);
+      this.payment_terms =
+        this.payment_terms != undefined ? this.payment_terms.nombre : "-";
+    });
+    this.catalogService.getOperationTypes().subscribe(res => {
+      this.operations = res.find(
+        e => e.id_tipo_operacion == this.complement.operaciones
+      );
+      this.operations =
+        this.operations != undefined ? this.operations.nombre : "-";
+    });
+
+    //getIncomeFormat
+    this.catalogService.getIncomeFormat().subscribe(res => {
+      this.format_incomes = res.find(
+        e => e.id_formato_ingreso == this.general.formato_ingreso
+      );
+      this.format_incomes =
+        this.format_incomes != undefined ? this.format_incomes.nombre : "-";
+    });
+
+    this.final = {};
+
+    Object.assign(this.final, this.general, this.instrument, this.complement);
+    this.inversion = {
+      codigo_instrumento: this.general.instrumentos,
+      info_inversion: {
+        id_empresa: +this.complement.empresa,
+        id_pais: +this.complement.pais,
+        id_entidad: +this.general.casa,
+        id_origen_fondo: +this.general.origenes_fondo,
+        id_periodicidad: +this.general.periodicidad,
+        id_plazo: +this.complement.plazo,
+        id_tipo_base: +this.general.base_anual,
+        id_tipo_emisor: +this.complement.emisores,
+        id_tipo_mercado: this.complement.tipo_mercado,
+        id_tipo_operacion: +this.complement.operaciones,
+        //id_tipo_pago: 1,
+        id_formato_ingreso: +this.general.formato_ingreso,
+        id_tipo_renta: +this.general.tipo_renta,
+        id_tipo_tasa: +this.general.tipo_tasa,
+        nombre_inversion: this.general.name,
+        asunto: this.general.asunto,
+        comentario: this.complement.comentarios,
+        justificacion: this.complement.justificacion
+      },
+      info_instrumento: this.instrument
+    };
+
+    if (
+      (this.inversion["codigo_instrumento"] == "CETE" ||
+        this.inversion["codigo_instrumento"] == "DAP" ||
+        this.inversion["codigo_instrumento"] == "VCN" ||
+        this.inversion["codigo_instrumento"] == "PBUR") &&
+      (this.instrument["proyecciones"] != undefined ||
+        this.instrument["proyecciones"] != "")
+    ) {
+      this.inversion["proyecciones"] = this.instrument["proyecciones"];
+    }
+  }
+
+  loadComponent() {
+    const adItem = this.ads[this.indexDynamicComponent];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = true;
+  }
+
+  // Guardar propuesta de inversion (Crear)
+  submit() {
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    if (this.investmentProposalID != undefined) {
+    } else {
+      this.investmentService.createProposalInvestment(this.inversion).subscribe(
+        success => {
+          if (success) {
+            Swal.fire({
+              allowOutsideClick: false,
+              icon: "success",
+              showCancelButton: false,
+              title: "Exito",
+              confirmButtonText: "El registro ha sido guardado"
+            }).then(result => {
+              if (result.value) {
+                window.location.href = "#/investment-proposals";
+              }
+            });
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error al guardar",
+            text: err.message
+          });
+        }
+      );
+    }
+  }
+
+  //Enviar a revision la propuesta de inversion
+  sendToReview() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Enviar a revisión propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Enviar propuesta",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendReviewProposalInvestment(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido enviada a revisión"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  // Actualizar la propuesta de inversion si se han realizado cambios
+  update_proposal() {
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+
+    this.investmentService
+      .updateProposalInvestment(this.investmentProposalID, this.inversion)
+      .subscribe(
+        success => {
+          if (success) {
+            Swal.fire({
+              allowOutsideClick: false,
+              icon: "success",
+              showCancelButton: false,
+              title: "Exito",
+              confirmButtonText: "El registro ha sido actualizado"
+            }).then(result => {
+              Swal.close();
+            });
+          }
+        },
+        err => {
+          Swal.fire({
+            icon: "error",
+            title: "Error al guardar",
+            text: err.message
+          });
+        }
+      );
+  }
+
+  goToPrevious() {
+    this.submitted = true;
+    if (this.investmentProposalID != undefined) {
+      this.router.navigate(["/investment-proposal/complement-info"], {
+        queryParams: { id: this.investmentProposalID }
+      });
+    } else {
+      this.router.navigate(["/investment-proposal/complement-info"]);
+    }
+  }
+
+  //Enviar a revision la propuesta de inversion
+  finishProposal() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Finalizar propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Finalizar",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendReviewProposalInvestment(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido finalizada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  // Verifica permisos para mostrar boton de edicion y/o envio a revision,
+  // segun los permisos del usuario y el estado de la propuesta
+  can_send_to_review(status: string) {
+    if (status == "NUEVA" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  can_finish_proposal(status: string) {
+    if (status == "LIQUI" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
+}

+ 189 - 0
src/app/components/investment-proposals/review/review.component.html

@@ -0,0 +1,189 @@
+<h2 class="floating-title">{{ title }}</h2>
+
+<div class="main-content">
+  <div class="container-fluid">
+    <div class="row">
+      <div class="col-12 align-right">
+        <div class="align-container">
+          <nav aria-label="breadcrumb">
+            <ol class="breadcrumb">
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/']">Dashboard</a>
+              </li>
+              <li class="breadcrumb-item">
+                <a [routerLink]="['/investment-proposals']">
+                  Propuestas de inversión
+                </a>
+              </li>
+              <li class="breadcrumb-item">Revisar</li>
+            </ol>
+          </nav>
+        </div>
+      </div>
+
+      <br />
+    </div>
+    <br />
+    <div class="row justify-content-center">
+      <div class="col-12">
+        <div class="align-container">
+          <div class="card borderless">
+            <div class="card-header card-header-icon card-header-rose">
+              <h4 class="card-title">
+                Resumen de la propuesta
+              </h4>
+            </div>
+            <div class="card-body">
+              <div class="align-container">
+                <ul class="timeline timeline-simple">
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-success"
+                          >Información general</span
+                        >
+                      </div>
+                      <div class="timeline-body">
+                        <div class="row">
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Asunto:</h4>
+                            <div class="field">
+                              {{ subject }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Orígenes de fondo:</h4>
+                            <div class="field">
+                              {{ funds }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Nombre:</h4>
+                            <div class="field">
+                              {{ investmentName }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Tasa:</h4>
+                            <div class="field">
+                              {{ rates }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo Renta:</h4>
+                            <div class="field">
+                              {{ revenues }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Periodicidad:</h4>
+                            <div class="field">
+                              {{ periodicities }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Instrumentos:</h4>
+                            <div class="field">
+                              {{ instrumentTypes }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Casa:</h4>
+                            <div class="field">
+                              {{ financials }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Base:</h4>
+                            <div class="field">
+                              {{ base_types }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipo de mercado:</h4>
+                            <div class="field">
+                              {{ markets }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Emisores:</h4>
+                            <div class="field">
+                              {{ emitters }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Empresa:</h4>
+                            <div class="field">
+                              {{ companies }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>País:</h4>
+                            <div class="field">
+                              {{ countries }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Plazo:</h4>
+                            <div class="field">
+                              {{ payment_terms }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Tipos de operaciones:</h4>
+                            <div class="field">
+                              {{ operations }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Comentarios:</h4>
+                            <div class="field">
+                              {{ comment }}
+                            </div>
+                          </div>
+                          <div class="col-lg-3 col-md-4 col-sm-6">
+                            <h4>Justificación:</h4>
+                            <div class="field">
+                              {{ justification }}
+                            </div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+                  </li>
+                  <li class="timeline-inverted">
+                    <div class="timeline-badge"></div>
+                    <div class="timeline-panel">
+                      <div class="timeline-heading">
+                        <span class="badge badge-warning">Instrumento</span>
+                        <ng-template instrument-host></ng-template>
+                      </div>
+                    </div>
+                  </li>
+                </ul>
+                <div class="review-buttons">
+                  <button
+                    class="btn btn-danger "
+                    (click)="dismiss_proposal()"
+                    type="button"
+                  >
+                    Rechazar propuesta
+                  </button>
+
+                  <button
+                    class="btn btn-success "
+                    (click)="approve_proposal()"
+                    type="button"
+                  >
+                    Aprobar propuesta
+                  </button>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 6 - 0
src/app/components/investment-proposals/review/review.component.scss

@@ -0,0 +1,6 @@
+.review-buttons {
+  text-align: center;
+  button {
+    margin: 0 20px;
+  }
+}

+ 429 - 0
src/app/components/investment-proposals/review/review.component.ts

@@ -0,0 +1,429 @@
+import {
+  Component,
+  OnInit,
+  Input,
+  ViewChild,
+  ComponentFactoryResolver
+} from "@angular/core";
+import { Router, ActivatedRoute } from "@angular/router";
+import { InvestmentProposalForm } from "@app/models/investment-proposal-form";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Instrument } from "@app/models/instrument";
+import { InvestmentProposalWorkflowService } from "@app/services/investment-proposal-workflow.service";
+import { InstrumentDirective } from "../instrument/instrument.directive";
+import { InstrumentComponent } from "../instrument/instrument.component";
+import { InstrumentsService } from "@app/services/instruments.service";
+import Swal from "sweetalert2";
+import { CatalogsService } from "@app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+
+@Component({
+  selector: "app-investment-proposal-review",
+  templateUrl: "./review.component.html",
+  styleUrls: ["./review.component.scss"]
+})
+export class InvestmentProposalReviewComponent implements OnInit {
+  title = "Revisión de propuesta";
+  @Input() ads: Instrument[];
+  @Input() formData: InvestmentProposalForm;
+  @ViewChild(InstrumentDirective, { static: true })
+  adHost: InstrumentDirective;
+  isFormValid: boolean = false;
+  general: any;
+  instrument: any;
+  complement: any;
+  final: any;
+  workType: string;
+  form: any;
+  currentAdIndex = -1;
+  interval: any;
+  indexDynamicComponent: number;
+  investmentProposalID: string;
+  investmentExists;
+  state;
+  financials;
+  base_types;
+  countries;
+  companies;
+  rates;
+  revenues;
+  funds;
+  instrumentTypes;
+  markets;
+  emitters;
+  periodicities;
+  format_incomes;
+  payment_terms;
+  operations;
+  gInfo: any;
+  gInstrument: any;
+  gComplement: any;
+  subject: any;
+  investmentName: any;
+  comment: any;
+  justification: any;
+  reviewProposal: {};
+
+  constructor(
+    private router: Router,
+
+    private formDataService: FormInvestmentProposalService,
+    private componentFactoryResolver: ComponentFactoryResolver,
+    private instrumentService: InvestmentProposalWorkflowService,
+    private loadInstrumentsService: InstrumentsService,
+    private catalogService: CatalogsService,
+    private route: ActivatedRoute,
+    private investmentService: InvestmentsService
+  ) {}
+
+  ngOnInit() {
+    //this.formDataService
+    this.ads = this.loadInstrumentsService.getInstruments();
+    this.route.params.subscribe(params => {
+      this.investmentProposalID = params["id"];
+    });
+    if (this.investmentProposalID == undefined)
+      this.investmentProposalID = this.route.snapshot.queryParamMap.get("id");
+
+    if (this.investmentProposalID != undefined) {
+      this.investmentExists = true;
+      this.investmentService
+        .getProposalInvestment(this.investmentProposalID)
+        .subscribe(res => {
+          this.state = res["result"]["id_estado_inversion"]["codigo"];
+
+          this.gInfo = {
+            asunto: res["result"]["asunto"],
+            origenes_fondo:
+              res["result"]["id_origen_fondo"] == null
+                ? ""
+                : res["result"]["id_origen_fondo"]["id_origen_fondo"],
+            name: res["result"]["nombre_inversion"],
+            //date: "",
+            tipo_tasa: res["result"]["id_tipo_tasa"] || "",
+            tipo_renta:
+              res["result"]["id_tipo_renta"] == null
+                ? ""
+                : res["result"]["id_tipo_renta"]["id_tipo_renta"],
+            periodicidad:
+              res["result"]["id_periodicidad"] == null
+                ? ""
+                : res["result"]["id_periodicidad"]["id_periodicidad"],
+
+            instrumentos:
+              res["result"]["id_inversion_instrumento"]["id_tipo_instrumento"][
+                "codigo"
+              ],
+            base_anual:
+              res["result"]["id_tipo_base"] == null
+                ? ""
+                : res["result"]["id_tipo_base"]["id_tipo_base"],
+            casa:
+              res["result"]["id_entidad"] == null
+                ? ""
+                : res["result"]["id_entidad"]["id_entidad_financiera"],
+            formato_ingreso:
+              res["result"]["id_formato_ingreso"] == null
+                ? ""
+                : res["result"]["id_formato_ingreso"]["id_formato_ingreso"]
+          };
+
+          this.gInstrument =
+            res["result"]["id_inversion_instrumento"]["instrumento"];
+
+          this.gInstrument["id_inversion_instrumento"] =
+            res["result"]["id_inversion_instrumento"][
+              "id_inversion_instrumento"
+            ];
+
+          this.gComplement = {
+            tipo_mercado:
+              res["result"]["id_tipo_mercado"] == null
+                ? ""
+                : res["result"]["id_tipo_mercado"]["id_tipo_mercado"],
+            emisores:
+              res["result"]["id_tipo_emisor"] == null
+                ? ""
+                : res["result"]["id_tipo_emisor"]["id_tipo_emisor"],
+            empresa:
+              res["result"]["id_empresa"] == null
+                ? ""
+                : res["result"]["id_empresa"]["id_empresa"],
+            pais:
+              res["result"]["id_pais"] == null
+                ? ""
+                : res["result"]["id_pais"]["id_pais"],
+            plazo:
+              res["result"]["id_plazo"] == null
+                ? ""
+                : res["result"]["id_plazo"]["id_plazo"],
+            operaciones:
+              res["result"]["id_tipo_operacion"] == null
+                ? ""
+                : res["result"]["id_tipo_operacion"]["id_tipo_operacion"],
+            comentarios: res["result"]["comentario"],
+            justificacion: res["result"]["justificacion"]
+          };
+          this.formDataService.setGeneralInfo(this.gInfo);
+
+          this.formDataService.setWork(this.gInstrument);
+
+          this.formDataService.setComplementInfo(this.gComplement);
+
+          this.general = this.formDataService.getGeneralInfo();
+          this.instrument = this.formDataService.getWork();
+          this.complement = this.formDataService.getComplementInfo();
+          this.formData = this.formDataService.getFormData();
+
+          this.formData.instrumentos;
+
+          this.indexDynamicComponent = this.ads.findIndex(
+            x => x.data.key == this.formData.instrumentos
+          );
+          if (this.indexDynamicComponent >= 0) {
+            this.loadComponent();
+          } else {
+            console.log("No existe el componente");
+          }
+          if (this.general != undefined) {
+            this.subject = this.general.asunto;
+            this.investmentName = this.general.name;
+            this.comment = this.complement.comment;
+            this.justification = this.complement.comment;
+
+            this.catalogService.getFinancialEntities().subscribe(res => {
+              this.financials = res.find(
+                e => e.id_entidad_financiera == this.general.casa
+              );
+              this.financials =
+                this.financials != undefined ? this.financials.nombre : "-";
+            });
+
+            this.catalogService.getBaseTypes().subscribe(res => {
+              this.base_types = res.find(
+                e => e.id_tipo_base == this.general.base_anual
+              );
+              this.base_types =
+                this.base_types != undefined
+                  ? ` ${this.base_types.tipo_base} / ${this.base_types.tipo_base_dias}`
+                  : "-";
+            });
+
+            this.catalogService.getCountries().subscribe(res => {
+              this.countries = res.find(e => e.id_pais == this.complement.pais);
+              this.countries =
+                this.countries != undefined ? this.countries.nombre : "-";
+            });
+            this.catalogService.getCompanies().subscribe(res => {
+              this.companies = res.find(
+                e => e.id_empresa == this.complement.empresa
+              );
+              this.companies =
+                this.companies != undefined ? this.companies.nombre : "-";
+            });
+            this.catalogService.getRateTypes().subscribe(res => {
+              this.rates = res.find(
+                e => e.id_tipo_tasa == this.general.tipo_tasa
+              );
+              this.rates = this.rates != undefined ? this.rates.nombre : "-";
+            });
+            this.catalogService.getRevenueTypes().subscribe(res => {
+              this.revenues = res.find(
+                e => e.id_tipo_renta == this.general.tipo_renta
+              );
+              this.revenues =
+                this.revenues != undefined ? this.revenues.nombre : "-";
+            });
+
+            this.catalogService.getFundsOrigins().subscribe(res => {
+              this.funds = res.find(
+                e => e.id_origen_fondo == this.general.origenes_fondo
+              );
+              this.funds = this.funds != undefined ? this.funds.nombre : "-";
+            });
+            this.catalogService.getInstrumentTypes().subscribe(res => {
+              this.instrumentTypes = res.find(
+                e => e.codigo == this.general.instrumentos
+              );
+              this.instrumentTypes =
+                this.instrumentTypes != undefined
+                  ? this.instrumentTypes.nombre
+                  : "-";
+            });
+
+            this.catalogService.getMarketTypes().subscribe(res => {
+              this.markets = res.find(
+                e => e.id_tipo_mercado == this.complement.tipo_mercado
+              );
+              this.markets =
+                this.markets != undefined ? this.markets.nombre : "-";
+            });
+            this.catalogService.getEmitterTypes().subscribe(res => {
+              this.emitters = res.find(
+                e => e.id_tipo_emisor == this.complement.emisores
+              );
+              this.emitters =
+                this.emitters != undefined ? this.emitters.nombre : "-";
+            });
+            this.catalogService.getPeriodicities().subscribe(res => {
+              this.periodicities = res.find(
+                e => e.id_periodicidad == this.general.periodicidad
+              );
+              this.periodicities =
+                this.periodicities != undefined
+                  ? this.periodicities.nombre
+                  : "-";
+            });
+
+            this.catalogService.getPaymentTerms().subscribe(res => {
+              this.payment_terms = res.find(
+                e => e.codigo == this.complement.calificadora_riesgo
+              );
+              this.payment_terms =
+                this.payment_terms != undefined
+                  ? this.payment_terms.nombre
+                  : "-";
+            });
+            this.catalogService.getOperationTypes().subscribe(res => {
+              this.operations = res.find(
+                e => e.codigo == this.complement.operaciones
+              );
+              this.operations =
+                this.operations != undefined ? this.operations.nombre : "-";
+            });
+            //getIncomeFormat
+            this.catalogService.getIncomeFormat().subscribe(res => {
+              this.format_incomes = res.find(
+                e => e.id_formato_ingreso == this.general.formato_ingreso
+              );
+              this.format_incomes =
+                this.format_incomes != undefined
+                  ? this.format_incomes.nombre
+                  : "-";
+            });
+          }
+        });
+    } else {
+      this.investmentExists = false;
+    }
+  }
+
+  loadComponent() {
+    const adItem = this.ads[this.indexDynamicComponent];
+    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
+      adItem.component
+    );
+
+    const viewContainerRef = this.adHost.viewContainerRef;
+    viewContainerRef.clear();
+
+    const componentRef = viewContainerRef.createComponent(componentFactory);
+    (<InstrumentComponent>componentRef.instance).data = adItem.data;
+    (<InstrumentComponent>componentRef.instance).summary = true;
+  }
+
+  approve_proposal() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Revisión propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Enviar propuesta",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "next",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendProposalInvestmentToNextStep(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "success",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido aprobada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error al guardar",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+
+  dismiss_proposal() {
+    (async () => {
+      const { value: comentario } = await Swal.fire({
+        title: "<h3>Revisión propuesta de inversión</h3>",
+        icon: "info",
+        html: `<p style="text-align:left;">Comentario:</p>`,
+        input: "textarea",
+        showCancelButton: true,
+        confirmButtonText: "Rechazar propuesta",
+        confirmButtonColor: "#C82333",
+        cancelButtonText: "Cancelar",
+        // inputValidator: value => {
+        //   if (!value) {
+        //     return "Debe ingresar un comentario";
+        //   }
+        // }
+        preConfirm: comentario => {
+          this.reviewProposal = {
+            id_inversion: this.investmentProposalID,
+            step: "previous",
+            comentario: comentario
+          };
+
+          this.investmentService
+            .sendProposalInvestmentToNextStep(this.reviewProposal)
+            .subscribe(
+              success => {
+                if (success) {
+                  Swal.fire({
+                    allowOutsideClick: false,
+                    icon: "warning",
+                    showCancelButton: false,
+                    title: "Exito",
+                    confirmButtonText: "La propuesta ha sido rechazada"
+                  }).then(result => {
+                    Swal.close();
+                    window.location.href = "#/investment-proposals";
+                  });
+                }
+              },
+              err => {
+                Swal.fire({
+                  icon: "error",
+                  title: "Error en el servidor",
+                  text: err.message
+                });
+              }
+            );
+        }
+      });
+    })();
+  }
+}

+ 100 - 5
src/app/components/investments/investments.component.html

@@ -10,19 +10,114 @@
               <li class="breadcrumb-item">
                 <a [routerLink]="['/']">Dashboard</a>
               </li>
-              <li class="breadcrumb-item">Inversiones</li>
+              <li class="breadcrumb-item">Inversiones activas</li>
             </ol>
           </nav>
-
-          <a class="btn btn-primary" href="#">
-            Nuevo registro
-          </a>
         </div>
       </div>
 
       <div class="col-12">
         <div class="align-container">
           <h4><b>Listado de inversiones</b></h4>
+          <br />
+          <div class="form-group">
+            <label for="filter" class="control-label">Filtro: </label>
+            <input
+              name="filter"
+              (keyup)="applyFilter($event)"
+              class="form-control input-md"
+              placeholder="Codigo, Instrumento, Asunto o Comentario"
+            />
+          </div>
+          <br />
+          <div class="example-container mat-elevation-z8">
+            <div class="example-table-container">
+              <table mat-table [dataSource]="dataSource" class="example-table">
+                <!-- Name Column -->
+                <ng-container matColumnDef="codigo_inversion">
+                  <th mat-header-cell *matHeaderCellDef>Codigo</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{ row.codigo_inversion }}
+                  </td>
+                </ng-container>
+                <!-- Country Column -->
+                <ng-container matColumnDef="asunto">
+                  <th mat-header-cell *matHeaderCellDef>Asunto</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{ row.asunto }}
+                  </td>
+                </ng-container>
+
+                <!-- Country Column -->
+                <ng-container matColumnDef="id_tipo_mercado">
+                  <th mat-header-cell *matHeaderCellDef>Tipo de mercado</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{
+                      row.id_tipo_mercado == "" ||
+                      row.id_tipo_mercado == undefined
+                        ? "-"
+                        : row.id_tipo_mercado.nombre
+                    }}
+                  </td>
+                </ng-container>
+
+                <!-- Country Column -->
+                <ng-container matColumnDef="id_inversion_instrumento">
+                  <th mat-header-cell *matHeaderCellDef>Instrumento</th>
+                  <td mat-cell *matCellDef="let row">
+                    {{
+                      row.id_inversion_instrumento.id_tipo_instrumento == "" ||
+                      row.id_inversion_instrumento.id_tipo_instrumento ==
+                        undefined
+                        ? "-"
+                        : row.id_inversion_instrumento.id_tipo_instrumento
+                            .nombre
+                    }}
+                  </td>
+                </ng-container>
+
+                <!--  Column -->
+                <ng-container matColumnDef="id">
+                  <th mat-header-cell *matHeaderCellDef>&nbsp;</th>
+                  <td mat-cell *matCellDef="let row">
+                    <div class="action-buttons">
+                      <a
+                        title="Detalle propuesta"
+                        class="btn btn-primary btn-custom-small"
+                        (click)="view_investment_proposal(row.id_inversion)"
+                      >
+                        <i class="fas fa-info"></i>
+                      </a>
+                      <a
+                        *ngIf="
+                          can_modify_or_send_to_review(
+                            row.id_estado_inversion.codigo
+                          )
+                        "
+                        title="Editar"
+                        class="btn btn-primary btn-custom-small"
+                        (click)="modify_investment_proposal(row.id_inversion)"
+                      >
+                        <i class="fas fa-edit"></i>
+                      </a>
+                    </div>
+                  </td>
+                </ng-container>
+
+                <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+                <tr
+                  mat-row
+                  *matRowDef="let row; columns: displayedColumns"
+                ></tr>
+              </table>
+
+              <mat-paginator
+                [pageSizeOptions]="[10, 15, 25]"
+                [pageIndex]="0"
+                [pageSize]="10"
+              ></mat-paginator>
+            </div>
+          </div>
         </div>
       </div>
       <br />

+ 10 - 0
src/app/components/investments/investments.component.scss

@@ -0,0 +1,10 @@
+.action-buttons {
+  i {
+    font-size: 18px;
+  }
+}
+
+.btn-custom-small {
+  padding: 7px 12px 5px 13px;
+  margin: 0 4px;
+}

+ 29 - 7
src/app/components/investments/investments.component.spec.ts

@@ -1,16 +1,19 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { InvestmentsComponent } from './investments.component';
+import { InvestmentsComponent } from "./investments.component";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
 
-describe('InvestmentsComponent', () => {
+describe("InvestmentsComponent", () => {
   let component: InvestmentsComponent;
   let fixture: ComponentFixture<InvestmentsComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ InvestmentsComponent ]
-    })
-    .compileComponents();
+      declarations: [InvestmentsComponent],
+      imports: [RouterTestingModule]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +22,26 @@ describe('InvestmentsComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      if (elem.attributes["ng-reflect-router-link"] === "/") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 148 - 5
src/app/components/investments/investments.component.ts

@@ -1,14 +1,157 @@
-import { Component, OnInit } from "@angular/core";
+import { Component, ViewChild, OnInit } from "@angular/core";
+import { MatPaginator } from "@angular/material/paginator";
+import { MatSort } from "@angular/material/sort";
+import { MatTableDataSource } from "@angular/material/table";
+import Swal from "sweetalert2";
+import { CatalogsService } from "src/app/services/catalogs.service";
+import { InvestmentsService } from "@app/services/investments.service";
+import { AuthService } from "@app/services/auth2.service";
+import { JwtHelperService } from "@auth0/angular-jwt";
+import { InvestmentProposal } from "@app/models/investment-proposal";
+import { from } from "rxjs";
+import { FormInvestmentProposalService } from "@app/services/form-investment-proposal.service";
+import { Router } from "@angular/router";
 
 @Component({
-  selector: "app-investments",
+  selector: "app-investment-proposals",
   templateUrl: "./investments.component.html",
   styleUrls: ["./investments.component.scss"]
 })
 export class InvestmentsComponent implements OnInit {
-  title: string = "Inversiones";
+  helper = new JwtHelperService();
 
-  constructor() {}
+  title: string = "Inversiones activas";
 
-  ngOnInit() {}
+  displayedColumns: string[] = [
+    "codigo_inversion",
+    "asunto",
+    "id_tipo_mercado",
+    "id_inversion_instrumento",
+    "id"
+  ];
+  //displayedColumns: string[] = ['state'];
+
+  listProposals: InvestmentProposal[];
+  dataSource = new MatTableDataSource(this.listProposals);
+
+  resultsLength = 0;
+  isLoadingResults = true;
+  isRateLimitReached = false;
+  userRole: any;
+
+  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
+  @ViewChild(MatSort, { static: true }) sort: MatSort;
+  role_number: any;
+
+  constructor(
+    private catalogService: CatalogsService,
+    private investmentsService: InvestmentsService,
+    private authService: AuthService,
+    private formInvestmentProposal: FormInvestmentProposalService,
+    private router: Router
+  ) {
+    const decodedToken = this.helper.decodeToken(
+      this.authService.getJwtToken()
+    );
+    this.userRole = decodedToken.groups;
+    //    console.log("User role");
+    //  console.log(this.userRole);
+    //console.log(this.userRole.length == 0);
+
+    this.dataSource.filterPredicate = (data, filter) => {
+      const dataStr =
+        data.id_inversion_instrumento.id_tipo_instrumento.nombre +
+        data.codigo_inversion +
+        data.nombre_inversion +
+        data.asunto +
+        data.comentario +
+        data.justificacion;
+      return dataStr.indexOf(filter) != -1;
+    };
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+  }
+
+  ngOnInit() {
+    this.investmentsService.getProposalInvestmentsList().subscribe(
+      ans => {
+        this.listProposals = ans.result;
+
+        this.listProposals = this.listProposals.filter(
+          proposals => proposals["id_estado_inversion"]["codigo"] == "FINAL"
+        );
+
+        console.log(this.listProposals);
+        this.dataSource.data = this.listProposals;
+
+        this.dataSource.paginator = this.paginator;
+        this.dataSource.sort = this.sort;
+      },
+      err => {
+        Swal.fire({
+          icon: "error",
+          title: "Error en el servidor",
+          text: err.message
+        });
+      }
+    );
+
+    setTimeout(() => {
+      Swal.close();
+    }, 1200);
+  }
+
+  applyFilter(event: Event) {
+    const filterValue = (event.target as HTMLInputElement).value;
+    this.dataSource.filter = filterValue;
+
+    if (this.dataSource.paginator) {
+      this.dataSource.paginator.firstPage();
+    }
+  }
+
+  view_investment_proposal(id: string) {
+    this.formInvestmentProposal.resetFormData();
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    setTimeout(() => {
+      this.router.navigate([`/investment-proposal/${id}`]);
+    }, 1000);
+  }
+
+  modify_investment_proposal(id: string) {
+    this.formInvestmentProposal.resetFormData();
+
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
+    setTimeout(() => {
+      this.router.navigate(["/investment-proposal/general-info"], {
+        queryParams: { id: id }
+      });
+    }, 1000);
+  }
+
+  // Verifica permisos para mostrar boton de edicion y/o envio a revision,
+  // segun los permisos del usuario y el estado de la propuesta
+  can_modify_or_send_to_review(status: string) {
+    if (status == "NUEVA" && (this.userRole.length == 0 || this.userRole)) {
+      // TO DO ver que el codigo de los tipos de usuario
+      return true;
+    } else {
+      return false;
+    }
+  }
 }

+ 31 - 15
src/app/components/login/login.component.html

@@ -2,10 +2,9 @@
   <div class="vertical-align-wrap">
     <div class="vertical-align-middle auth-main">
       <div class="auth-box">
-        
         <div class="card">
           <div class="top d-block d-lg-none">
-            <img alt="Inverlec" src="./assets/img/inverlec_logo.png">
+            <img alt="Inverlec" src="./assets/img/inverlec_logo.png" />
           </div>
 
           <div class="header">
@@ -14,26 +13,43 @@
           <div class="body">
             <form [formGroup]="loginForm" (ngSubmit)="login()">
               <div class="form-group">
-                <label for="email">Correo electrónico</label>
+                <label for="username">Nombre de usuario</label>
 
-                <input type="text" name="email" class="form-control"
-                formControlName="email" [ngClass]="{ 'is-invalid': submitted && f.email.errors }" email/>
-                <div *ngIf="submitted && f.email.errors" class="invalid-feedback">
-                  <div>Ingresar un correo válido</div>
+                <input
+                  type="text"
+                  name="username"
+                  class="form-control"
+                  formControlName="username"
+                  [ngClass]="{ 'is-invalid': submitted && f.username.errors }"
+                />
+                <div
+                  *ngIf="submitted && f.username.errors"
+                  class="invalid-feedback"
+                >
+                  <div>Ingresar usuario válido</div>
                 </div>
-  
               </div>
               <div class="form-group">
                 <label for="password">Contraseña</label>
-                <input type="password" name="password"  class="form-control"
-                formControlName="password" minlength="5"  [ngClass]="{ 'is-invalid': submitted && f.password.errors }"/>
-                <div *ngIf="submitted && f.password.errors" class="invalid-feedback">
-                  <div *ngIf="f.password.errors.required">Ingresar contraseña</div>
+                <input
+                  type="password"
+                  name="password"
+                  class="form-control"
+                  formControlName="password"
+                  minlength="5"
+                  [ngClass]="{ 'is-invalid': submitted && f.password.errors }"
+                />
+                <div
+                  *ngIf="submitted && f.password.errors"
+                  class="invalid-feedback"
+                >
+                  <div *ngIf="f.password.errors.required">
+                    Ingresar contraseña
+                  </div>
                 </div>
-  
               </div>
-  
-              <button class="btn btn-primary" type="submit"> 
+
+              <button class="btn btn-primary" type="submit">
                 Iniciar sesión
               </button>
             </form>

+ 1 - 1
src/app/components/login/login.component.scss

@@ -79,7 +79,7 @@
 
   .auth-main:before {
     width: 100%;
-    background-image: url("/assets/img/login-bg.png");
+    //background-image: url("/assets/img/login-bg.png");
   }
 
   .top {

+ 20 - 8
src/app/components/login/login.component.spec.ts

@@ -1,25 +1,37 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
+import { LoginComponent } from "./login.component";
+import { RouterTestingModule } from "@angular/router/testing";
+import { AuthService } from "@app/services/auth2.service";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref, Router } from "@angular/router";
+import { HttpClientModule } from "@angular/common/http";
+import { ReactiveFormsModule, FormsModule } from "@angular/forms";
 
-import { LoginComponent } from './login.component';
-
-describe('LoginComponent', () => {
+describe("LoginComponent", () => {
   let component: LoginComponent;
   let fixture: ComponentFixture<LoginComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ LoginComponent ]
-    })
-    .compileComponents();
+      declarations: [LoginComponent],
+      imports: [
+        RouterTestingModule,
+        HttpClientModule,
+        ReactiveFormsModule,
+        FormsModule
+      ],
+      providers: [AuthService]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
     fixture = TestBed.createComponent(LoginComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
+    component.ngOnInit();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
 });

+ 46 - 124
src/app/components/login/login.component.ts

@@ -1,29 +1,34 @@
-import { Component, OnInit } from '@angular/core';
-import { FormGroup, FormBuilder, Validators } from '@angular/forms';
-import { Router } from '@angular/router';
-import { AuthService } from '@app/services/auth2.service';
-import Swal from 'sweetalert2';
+import { Component, OnInit } from "@angular/core";
+import { FormGroup, FormBuilder, Validators } from "@angular/forms";
+import { Router } from "@angular/router";
+import { AuthService } from "@app/services/auth2.service";
+import Swal from "sweetalert2";
 
 @Component({
-  selector: 'app-login',
-  templateUrl: './login.component.html',
-  styleUrls: ['./login.component.scss']
+  selector: "app-login",
+  templateUrl: "./login.component.html",
+  styleUrls: ["./login.component.scss"]
 })
 export class LoginComponent implements OnInit {
-
   loginForm: FormGroup;
-  submitted:boolean = false;
+  submitted: boolean = false;
 
-  constructor(private authService: AuthService, private formBuilder: FormBuilder, private router: Router) { }
+  constructor(
+    private authService: AuthService,
+    private formBuilder: FormBuilder,
+    private router: Router
+  ) {}
 
   ngOnInit() {
     this.loginForm = this.formBuilder.group({
-      email: ['', [Validators.required, Validators.email]],
-      password: ['', Validators.required]
+      username: ["", [Validators.required]],
+      password: ["", Validators.required]
     });
   }
 
-  get f() { return this.loginForm.controls; }
+  get f() {
+    return this.loginForm.controls;
+  }
 
   login() {
     this.submitted = true;
@@ -33,121 +38,38 @@ export class LoginComponent implements OnInit {
       return;
     }
 
-    Swal.fire({
-      
-    });
-    Swal.showLoading();
-
-    this.authService.login(
-      {
-        email: this.f.email.value,
-        password: this.f.password.value
-      }
-    )
-    .subscribe(success => {
-      if (success) {
-        window.location.href="#/dashboard";
-      }
-      else {
-        Swal.fire({
-      
-        })  
-      }
-    },(err) => {
-      Swal.fire({
-      
-      });
-    });
-  }
-
-}
-
-/* import { Component, OnInit } from '@angular/core';
-import { Location } from '@angular/common';
-
-import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
-import { NgForm } from '@angular/forms';
-
-import { User } from '../../models/user';
-import { AuthService } from '../../services/auth.service';
-
-import Swal from 'sweetalert2';
-
-@Component({
-  selector: 'app-login',
-  templateUrl: './login.component.html',
-  styleUrls: ['./login.component.scss']
-})
-export class LoginComponent implements OnInit {
-
-  user: User = new User();
-  recordarme = false;
-  returnUrl: string;
-  error_message: string;
-
-  constructor( private auth: AuthService,
-               private router: Router,
-               private route: ActivatedRoute,
-               private location: Location ) {
-
-              this.router.routeReuseStrategy.shouldReuseRoute = function(){
-                return false;
-              }
-
-              this.router.events.subscribe((evt) => {
-                if (evt instanceof NavigationEnd) {
-                  // trick the Router into believing it's last link wasn't previously loaded
-                  this.router.navigated = false;
-                  // if you need to scroll back to top, here is the right place
-                  window.scrollTo(0, 0);
-                }
-              });
-            }
-
-  ngOnInit() {
-    this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
-    if ( localStorage.getItem('email') ) {
-      this.user.email = localStorage.getItem('email');
-      //this.recordarme = true;
-    }
-  }
-
-  login( form: NgForm ) {
-    if (  form.invalid ) { return; }
-
     Swal.fire({
       allowOutsideClick: false,
-      type: 'info',
-      text: 'Espere por favor...'
+      icon: "info",
+      text: "Espere por favor..."
     });
     Swal.showLoading();
 
-    this.auth.login( this.user )
-      .subscribe( resp => {
-
-        Swal.close();
-
-        localStorage.setItem('email', this.user.email);
-
-        //this.router.navigate([this.returnUrl]);
-        window.location.href="";
-      }, (err) => {
-        if(err.error.error.message == "INVALID_EMAIL"){
-          this.error_message = "Correo electrónico inválido";
-        }
-        else if(err.error.error.message == "INVALID_PASSWORD"){
-          this.error_message = "Contraseña incorrecta";
-        }
-        else {
-          this.error_message = "Ha ocurrido un error";
+    this.authService
+      .login({
+        username: this.f.username.value,
+        password: this.f.password.value
+      })
+      .subscribe(
+        success => {
+          if (success) {
+            window.location.href = "#/investment-proposals";
+          } else {
+            Swal.fire({
+              icon: "warning",
+              title: "No se pudo auntenticar",
+              text: "Usuario o contraseña inválidos"
+            });
+          }
+        },
+        err => {
+          console.log(err);
+          Swal.fire({
+            icon: "error",
+            title: "Error al autenticar",
+            text: "Usuario o contraseña inválidos"
+          });
         }
-        Swal.fire({
-          type: 'error',
-          title: 'Error al autenticar',
-          text: this.error_message
-        });
-      });
+      );
   }
-
 }
-*/

+ 29 - 7
src/app/components/performances/performances.component.spec.ts

@@ -1,16 +1,19 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { PerformancesComponent } from './performances.component';
+import { PerformancesComponent } from "./performances.component";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
 
-describe('PerformancesComponent', () => {
+describe("PerformancesComponent", () => {
   let component: PerformancesComponent;
   let fixture: ComponentFixture<PerformancesComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ PerformancesComponent ]
-    })
-    .compileComponents();
+      declarations: [PerformancesComponent],
+      imports: [RouterTestingModule]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +22,26 @@ describe('PerformancesComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      if (elem.attributes["ng-reflect-router-link"] === "/") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 68 - 0
src/app/components/plugins/dynamic-component-loader/dynamic-component-loader.module.ts

@@ -0,0 +1,68 @@
+import {
+  ANALYZE_FOR_ENTRY_COMPONENTS,
+  ModuleWithProviders,
+  NgModule,
+  NgModuleFactoryLoader,
+  SystemJsNgModuleLoader,
+  Type
+} from '@angular/core';
+import { ROUTES } from '@angular/router';
+
+import { DynamicComponentLoader } from './dynamic-component-loader.service';
+import {
+  DYNAMIC_COMPONENT,
+  DYNAMIC_COMPONENT_MANIFESTS,
+  DYNAMIC_MODULE,
+  DynamicComponentManifest
+} from './dynamic-component-manifest';
+
+@NgModule()
+export class DynamicComponentLoaderModule {
+  static forRoot(manifests: DynamicComponentManifest[]): ModuleWithProviders {
+    return {
+      ngModule: DynamicComponentLoaderModule,
+      providers: [
+        DynamicComponentLoader,
+        { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader },
+        // provider for Angular CLI to analyze
+        { provide: ROUTES, useValue: manifests, multi: true },
+        // provider for DynamicComponentLoader to analyze
+        { provide: DYNAMIC_COMPONENT_MANIFESTS, useValue: manifests }
+      ]
+    };
+  }
+  static forModule(manifest: DynamicComponentManifest): ModuleWithProviders {
+    return {
+      ngModule: DynamicComponentLoaderModule,
+      providers: [
+        {
+          provide: ANALYZE_FOR_ENTRY_COMPONENTS,
+          useValue: manifest,
+          multi: true
+        },
+        // provider for @angular/router to parse
+        { provide: ROUTES, useValue: manifest, multi: true },
+        // provider for DynamicComponentLoader to analyze
+        { provide: DYNAMIC_MODULE, useValue: manifest }
+      ]
+    };
+  }
+  static forChild(component: Type<any>): ModuleWithProviders {
+    return {
+      ngModule: DynamicComponentLoaderModule,
+      providers: [
+        {
+          provide: ANALYZE_FOR_ENTRY_COMPONENTS,
+          useValue: component,
+          multi: true
+        },
+        // provider for @angular/router to parse
+        { provide: ROUTES, useValue: [], multi: true },
+        // provider for DynamicComponentLoader to analyze
+        { provide: DYNAMIC_COMPONENT, useValue: component }
+      ]
+    };
+  }
+}
+
+export { DynamicComponentManifest } from './dynamic-component-manifest';

+ 172 - 0
src/app/components/plugins/dynamic-component-loader/dynamic-component-loader.service.ts

@@ -0,0 +1,172 @@
+import {
+  ComponentFactory,
+  Inject,
+  Injectable,
+  Injector,
+  NgModuleFactory,
+  NgModuleFactoryLoader,
+  Compiler
+} from '@angular/core';
+import { from, Observable, throwError, of,  } from 'rxjs';
+import { mergeMap } from 'rxjs/operators';
+import {
+  DynamicComponentManifest,
+  DYNAMIC_COMPONENT,
+  DYNAMIC_COMPONENT_MANIFESTS,
+  DYNAMIC_MODULE
+} from './dynamic-component-manifest';
+
+@Injectable()
+export class DynamicComponentLoader {
+  constructor(
+    @Inject(DYNAMIC_COMPONENT_MANIFESTS)
+    private manifests: DynamicComponentManifest[],
+    private loader: NgModuleFactoryLoader,
+    private injector: Injector,
+    private compiler: Compiler
+  ) {}
+
+  /**
+   * Get the value as an observable
+   *
+   * @template T
+   * @param {(T | NgModuleFactory<T> | Promise<T> | Observable<T>)} value
+   * @returns
+   * @memberof LibConfigService
+   */
+  private _wrapIntoObservable<T>(value: T | NgModuleFactory<T> | Promise<T> | Observable<T>) {
+    if (value instanceof Observable) {
+      return value;
+    } else if (value instanceof Promise) {
+      return from(value);
+    } else {
+      return of(value);
+    }
+  }
+
+  /**
+   *  Retrieve a ComponentFactory, based on the specified componentId
+   *  (defined in the DynamicComponentManifest array).
+   *
+   * @template T
+   * @param {string} componentId
+   * @param {Injector} [injector]
+   * @returns {Observable<ComponentFactory<T>>}
+   * @memberof DynamicComponentLoader
+   */
+  getComponentFactory<T>(
+    componentId: string,
+    injector?: Injector
+  ): Observable<ComponentFactory<T>> {
+    const manifest = this.manifests.find(m => m.componentId === componentId);
+    if (!manifest) {
+      return throwError(
+        `DynamicComponentLoader: Unknown componentId "${componentId}"`
+      );
+    }
+
+    const path = manifest.loadChildren;
+
+    if (!path) {
+      throw new Error(`${componentId} unknown!`);
+    }
+
+    // Check the path type
+    if (path instanceof Function) {
+      return this._wrapIntoObservable(path()).pipe(mergeMap((t: any) => {
+        let moduleFactory = null;
+        const offlineMode = this.compiler instanceof Compiler;
+        //  true means AOT enalbed compiler (Prod build), false means JIT enabled compiler (Dev build)
+        moduleFactory = offlineMode ? t : this.compiler.compileModuleSync(t);
+        return this.loadFactory<T>(moduleFactory, componentId, injector);
+      }));
+    } else {
+      return from(this.load<T>(path, componentId, injector));
+    }
+  }
+
+  /**
+   * Get the instance of the component factory
+   *
+   * @template T
+   * @param {string} path
+   * @param {string} componentId
+   * @param {Injector} [injector]
+   * @returns {Promise<ComponentFactory<T>>}
+   * @memberof DynamicComponentLoader
+   */
+  async load<T>(
+    path: string,
+    componentId: string,
+    injector?: Injector
+  ): Promise<ComponentFactory<T>> {
+    const ngModuleFactory = await this.loader.load(path);
+    return await this.loadFactory<T>(ngModuleFactory, componentId, injector);
+  }
+
+  /**
+   * Load the factory object
+   *
+   * @template T
+   * @param {NgModuleFactory<any>} ngModuleFactory
+   * @param {string} componentId
+   * @param {Injector} [injector]
+   * @returns {Promise<ComponentFactory<T>>}
+   * @memberof DynamicComponentLoader
+   */
+  loadFactory<T>(
+    ngModuleFactory: NgModuleFactory<any>,
+    componentId: string,
+    injector?: Injector
+  ): Promise<ComponentFactory<T>> {
+    const moduleRef = ngModuleFactory.create(injector || this.injector);
+    const dynamicComponentType = moduleRef.injector.get(
+      DYNAMIC_COMPONENT,
+      null
+    );
+    if (!dynamicComponentType) {
+      const dynamicModule: DynamicComponentManifest = moduleRef.injector.get(
+        DYNAMIC_MODULE,
+        null
+      );
+
+      if (!dynamicModule) {
+        throw new Error(
+          'DynamicComponentLoader: Dynamic module for' +
+            ` componentId "${componentId}" does not contain` +
+            ' DYNAMIC_COMPONENT or DYNAMIC_MODULE as a provider.'
+        );
+      }
+      if (dynamicModule.componentId !== componentId) {
+        throw new Error(
+          'DynamicComponentLoader: Dynamic module for' +
+            `${componentId} does not match manifest.`
+        );
+      }
+
+      const path = dynamicModule.loadChildren;
+
+      if (!path) {
+        throw new Error(`${componentId} unknown!`);
+      }
+
+      if (path instanceof Function) {
+        return this._wrapIntoObservable(path()).pipe(mergeMap((t: any) => {
+          let moduleFactory = null;
+          const offlineMode = this.compiler instanceof Compiler;
+          //  true means AOT enalbed compiler (Prod build), false means JIT enabled compiler (Dev build)
+          moduleFactory = offlineMode ? t : this.compiler.compileModuleSync(t);
+          return this.loadFactory<T>(moduleFactory, componentId, injector);
+        })).toPromise();
+      } else {
+        return this.load<T>(path, componentId, injector);
+      }
+    }
+
+    return Promise.resolve(
+      moduleRef.componentFactoryResolver.resolveComponentFactory<T>(
+        dynamicComponentType
+      )
+    );
+  }
+}

+ 20 - 0
src/app/components/plugins/dynamic-component-loader/dynamic-component-manifest.ts

@@ -0,0 +1,20 @@
+import { InjectionToken } from '@angular/core';
+
+export const DYNAMIC_COMPONENT = new InjectionToken<any>('DYNAMIC_COMPONENT');
+
+export const DYNAMIC_MODULE = new InjectionToken<any>('DYNAMIC_MODULE');
+
+export const DYNAMIC_COMPONENT_MANIFESTS = new InjectionToken<any>(
+  'DYNAMIC_COMPONENT_MANIFESTS'
+);
+
+export interface DynamicComponentManifest {
+  /** Unique identifier, used in the application to retrieve a ComponentFactory. */
+  componentId: string;
+
+  /** Unique identifier, used internally by Angular. */
+  path: string;
+
+  /** Path to component module. */
+  loadChildren: string | any; // Support for angular 8 style module imports
+}

+ 58 - 0
src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.html

@@ -0,0 +1,58 @@
+<div class="board-inner" id="status-buttons">
+  <ul class="nav nav-tabs" id="myTab">
+    <div class="liner"></div>
+
+    <!-- circular user icon -->
+    <li>
+      <a
+        (click)="goToStep('general')"
+        title="general"
+        [ngClass]="activeLink == 'general' ? 'active' : ''"
+      >
+        <span class="round-tabs one">
+          <i class="material-icons">post_add</i>
+        </span>
+      </a>
+    </li>
+
+    <!-- circular tasks icon -->
+    <li>
+      <a
+        (click)="goToStep('instrument')"
+        title="instrument"
+        [ngClass]="activeLink == 'instrument' ? 'active' : ''"
+      >
+        <span class="round-tabs two">
+          <i class="material-icons">business_center</i>
+        </span>
+      </a>
+    </li>
+
+    <!-- circular home icon -->
+    <li>
+      <a
+        (click)="goToStep('other_info')"
+        [ngClass]="activeLink == 'other_info' ? 'active' : ''"
+        title="address"
+      >
+        <span class="round-tabs three">
+          <i class="material-icons">library_books</i>
+        </span>
+      </a>
+    </li>
+
+    <!-- circular ok icon -->
+    <li>
+      <a
+        (click)="goToStep('result')"
+        [ngClass]="activeLink == 'result' ? 'active' : ''"
+        title="completed"
+      >
+        <span class="round-tabs four">
+          <i class="material-icons">check_box</i>
+        </span>
+      </a>
+    </li>
+  </ul>
+  <div class="clearfix"></div>
+</div>

+ 212 - 0
src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.scss

@@ -0,0 +1,212 @@
+@import url("http://fonts.googleapis.com/css?family=Roboto+Condensed:400, 700");
+/* written by riliwan balogun http://www.facebook.com/riliwan.rabo*/
+.nav-tabs {
+  position: relative;
+  margin: 0 auto;
+  box-sizing: border-box;
+}
+
+div.board-inner {
+  background: #fff;
+}
+
+p.narrow {
+  width: 60%;
+  margin: 10px auto;
+}
+
+.liner {
+  height: 2px;
+  background: #ddd;
+  position: absolute;
+  width: 75%;
+  margin: 0 auto;
+  left: 0;
+  right: 0;
+  top: 50%;
+  z-index: 1;
+}
+
+.nav-tabs > li.active > a {
+  color: #555555;
+  cursor: default;
+  /* background-color: #ffffff; */
+  border: 0;
+  border-bottom-color: transparent;
+}
+
+span.round-tabs {
+  width: 70px;
+  height: 70px;
+  line-height: 65px;
+  display: inline-block;
+  border-radius: 100px;
+  background: white;
+  z-index: 2;
+  position: absolute;
+  text-align: center;
+  font-size: 25px;
+}
+
+span.round-tabs.one {
+  color: rgb(34, 194, 34);
+  border: 2px solid rgb(34, 194, 34);
+}
+
+a.active span.round-tabs.one {
+  border: 2px solid #00a000;
+  background-color: #22c222;
+  color: #fff;
+}
+
+span.round-tabs.two {
+  color: #febe29;
+  border: 2px solid #febe29;
+}
+
+a.active span.round-tabs.two {
+  border: 2px solid #fece19;
+  background-color: #febe29;
+  color: #fff;
+}
+
+span.round-tabs.three {
+  color: #3e5e9a;
+  border: 2px solid #3e5e9a;
+}
+
+a.active span.round-tabs.three {
+  border: 2px solid #3e5e9a;
+  background-color: #3f5e9a;
+  color: #fff;
+}
+
+span.round-tabs.four {
+  color: #f1685e;
+  border: 2px solid #f1685e;
+}
+
+a.active span.round-tabs.four {
+  border: 2px solid #f0685e;
+  background-color: #f1685e;
+  color: #fff;
+}
+
+span.round-tabs.five {
+  color: #999;
+  border: 2px solid #999;
+}
+
+a.active span.round-tabs.five {
+  color: #fff;
+}
+
+.nav-tabs > li.active > a span.round-tabs {
+  background: #fafafa;
+}
+.nav-tabs > li {
+  /*width: 20%;*/
+  width: 25%;
+  float: left;
+  margin-bottom: -1px;
+  display: block;
+  position: relative;
+}
+/*li.active:before {
+    content: " ";
+    position: absolute;
+    left: 45%;
+    opacity:0;
+    margin: 0 auto;
+    bottom: -2px;
+    border: 10px solid transparent;
+    border-bottom-color: #fff;
+    z-index: 1;
+    transition:0.2s ease-in-out;
+}*/
+.nav-tabs > li:after {
+  content: " ";
+  position: absolute;
+  left: 45%;
+  opacity: 0;
+  margin: 0 auto;
+  bottom: 0px;
+  border: 5px solid transparent;
+  border-bottom-color: #ddd;
+  transition: 0.1s ease-in-out;
+}
+.nav-tabs > li.active:after {
+  content: " ";
+  position: absolute;
+  left: 45%;
+  opacity: 1;
+  margin: 0 auto;
+  bottom: 0px;
+  border: 10px solid transparent;
+  border-bottom-color: #ddd;
+}
+.nav-tabs > li a {
+  width: 70px;
+  height: 70px;
+  margin: 20px auto;
+  border-radius: 100%;
+  padding: 0;
+  display: block;
+}
+.nav-tabs > li a:hover {
+  background: transparent;
+}
+
+.tab-content .tab-pane {
+  position: relative;
+  padding-top: 50px;
+}
+.tab-content .head {
+  font-family: "Roboto Condensed", sans-serif;
+  font-size: 25px;
+  text-transform: uppercase;
+  padding-bottom: 10px;
+}
+.btn-outline-rounded {
+  padding: 10px 40px;
+  margin: 20px 0;
+  border: 2px solid transparent;
+  border-radius: 25px;
+}
+
+.btn.green {
+  background-color: #5cb85c;
+  /*border: 2px solid #5cb85c;*/
+  color: #ffffff;
+}
+
+@media (max-width: 585px) {
+  .board {
+    width: 90%;
+    height: auto !important;
+  }
+  span.round-tabs {
+    font-size: 16px;
+    width: 50px;
+    height: 50px;
+    line-height: 50px;
+  }
+  .tab-content .head {
+    font-size: 20px;
+  }
+  .nav-tabs > li a {
+    width: 50px;
+    height: 50px;
+    line-height: 50px;
+  }
+
+  .nav-tabs > li.active:after {
+    content: " ";
+    position: absolute;
+    left: 35%;
+  }
+
+  .btn-outline-rounded {
+    padding: 12px 20px;
+  }
+}

+ 70 - 0
src/app/components/plugins/navbar-inv-proposals/navbar-inv-proposals.ts

@@ -0,0 +1,70 @@
+import { Component, Input, OnInit, OnChanges } from "@angular/core";
+import { Router } from "@angular/router";
+
+@Component({
+  selector: "inv-proposal-navbar",
+  templateUrl: "./navbar-inv-proposals.html",
+  styleUrls: ["./navbar-inv-proposals.scss"]
+})
+export class NavbarInvProposalComponent implements OnInit, OnChanges {
+  @Input() activeLink: string;
+  @Input() investmentID: string;
+  activeRoute: string;
+  general_link: string;
+
+  constructor(private router: Router) {}
+
+  ngOnInit() {}
+  ngOnChanges() {}
+  /**if (this.investmentProposalID != undefined) {
+        this.router.navigate([
+          "/investment-proposal/instrument-work",
+          { id: this.investmentProposalID }
+        ]);
+      } else {
+        this.router.navigate(["/investment-proposal/instrument-work"]);
+      } */
+  goToStep(step: string) {
+    console.log(step);
+    switch (step) {
+      case "general":
+        if (this.investmentID != undefined) {
+          this.router.navigate(["/investment-proposal/general-info"], {
+            queryParams: { id: this.investmentID }
+          });
+        } else {
+          this.router.navigate(["/investment-proposal/general-info"]);
+        }
+        break;
+      case "instrument":
+        if (this.investmentID != undefined) {
+          this.router.navigate(["/investment-proposal/instrument-work"], {
+            queryParams: { id: this.investmentID }
+          });
+        } else {
+          this.router.navigate(["/investment-proposal/instrument-work"]);
+        }
+
+        break;
+      case "other_info":
+        if (this.investmentID != undefined) {
+          this.router.navigate(["/investment-proposal/complement-info"], {
+            queryParams: { id: this.investmentID }
+          });
+        } else {
+          this.router.navigate(["/investment-proposal/complement-info"]);
+        }
+        break;
+      case "result":
+        if (this.investmentID != undefined) {
+          this.router.navigate(["/investment-proposal/result"], {
+            queryParams: { id: this.investmentID }
+          });
+        } else {
+          this.router.navigate(["/investment-proposal/result"]);
+        }
+        break;
+      default:
+    }
+  }
+}

+ 6 - 8
src/app/components/plugins/plugins.module.ts

@@ -12,12 +12,11 @@ import {
   MatPaginatorModule,
   MatProgressSpinnerModule,
   MatSortModule
-} from '@angular/material';
-import { } from '@angular/material/table';
+} from "@angular/material";
+import {} from "@angular/material/table";
 
 @NgModule({
-  declarations: [
-  ],
+  declarations: [],
   imports: [
     CommonModule,
     MatButtonModule,
@@ -30,9 +29,8 @@ import { } from '@angular/material/table';
     MatTableModule,
     MatPaginatorModule,
     MatProgressSpinnerModule,
-    MatSortModule,
+    MatSortModule
   ],
-  exports: [
-  ]
+  exports: []
 })
-export class PluginsModule { }
+export class PluginsModule {}

+ 9 - 5
src/app/components/shared/footer/footer.component.html

@@ -1,8 +1,12 @@
-<div class="row align-container">
-  <div class="col-12">
-    <div class="card">
-      <div class="card-body">
-        <p class="card-text">&copy; 2019-2020 - INVERLEC. <a href="#/terms">Términos y condiciones.</a> </p>
+<div class="container-fluid">
+  <div class="row align-container">
+    <div class="col-12">
+      <div class="card">
+        <div class="card-body">
+          <p class="card-text">
+            &copy; 2019-2020 - INVERLEC.
+          </p>
+        </div>
       </div>
     </div>
   </div>

+ 33 - 7
src/app/components/shared/navbar/navbar.component.spec.ts

@@ -1,16 +1,22 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { NavbarComponent } from './navbar.component';
+import { NavbarComponent } from "./navbar.component";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
+import { HttpClientModule } from "@angular/common/http";
+import { AuthService } from "../../../services/auth2.service";
 
-describe('NavbarComponent', () => {
+describe("NavbarComponent", () => {
   let component: NavbarComponent;
   let fixture: ComponentFixture<NavbarComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ NavbarComponent ]
-    })
-    .compileComponents();
+      declarations: [NavbarComponent],
+      imports: [RouterTestingModule, HttpClientModule],
+      providers: [AuthService]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +25,27 @@ describe('NavbarComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      console.log(elem.attributes);
+      if (elem.attributes["ng-reflect-router-link"] === "/dashboard") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 175 - 164
src/app/components/shared/navbar/navbar.component.ts

@@ -1,186 +1,197 @@
-import { Observable } from 'rxjs';
-
-import { Component, OnInit, ElementRef } from '@angular/core';
-import { ROUTES } from '../sidebar/sidebar.component';
-import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
-import { Router, ActivatedRoute } from '@angular/router';
+import { Observable } from "rxjs";
+
+import { Component, OnInit, ElementRef } from "@angular/core";
+import { ROUTES } from "../sidebar/sidebar.component";
+import {
+  Location,
+  LocationStrategy,
+  PathLocationStrategy
+} from "@angular/common";
+import { Router, ActivatedRoute } from "@angular/router";
 //import { AuthenticationService } from 'src/app/services/authentication.service';
-import { AdminLayoutRoutes } from 'src/app/layouts/admin/admin.routing';
-import { AuthService } from '../../../services/auth2.service';
-import Swal from 'sweetalert2';
+import { AdminLayoutRoutes } from "src/app/layouts/admin/admin.routing";
+import { AuthService } from "../../../services/auth2.service";
+import Swal from "sweetalert2";
 
 @Component({
-  selector: 'app-navbar',
-  templateUrl: './navbar.component.html',
-  styleUrls: ['./navbar.component.scss']
+  selector: "app-navbar",
+  templateUrl: "./navbar.component.html",
+  styleUrls: ["./navbar.component.scss"]
 })
 export class NavbarComponent implements OnInit {
-    private listTitles: any[];
-
-    private leTitles: any[];
-
-    location: Location;
-      mobile_menu_visible: any = 0;
-    private toggleButton: any;
-    private sidebarVisible: boolean;
-    private sidebarMini: boolean;
-    constructor(location: Location,  private element: ElementRef, private router: Router, private auth: AuthService, private route: ActivatedRoute) {
-      this.location = location;
-      this.sidebarVisible = false;
-      this.sidebarMini = false;
+  private listTitles: any[];
+
+  private leTitles: any[];
+
+  location: Location;
+  mobile_menu_visible: any = 0;
+  private toggleButton: any;
+  private sidebarVisible: boolean;
+  private sidebarMini: boolean;
+  constructor(
+    location: Location,
+    private element: ElementRef,
+    private router: Router,
+    private auth: AuthService,
+    private route: ActivatedRoute
+  ) {
+    this.location = location;
+    this.sidebarVisible = false;
+    this.sidebarMini = false;
+  }
+
+  ngOnInit() {
+    this.listTitles = ROUTES.filter(listTitle => listTitle);
+    this.leTitles = AdminLayoutRoutes.filter(listTitle => listTitle);
+    const navbar: HTMLElement = this.element.nativeElement;
+    this.toggleButton = navbar.getElementsByClassName("navbar-toggler")[0];
+    this.router.events.subscribe(event => {
+      this.sidebarClose();
+      var $layer: any = document.getElementsByClassName("close-layer")[0];
+      if ($layer) {
+        $layer.remove();
+        this.mobile_menu_visible = 0;
+      }
+    });
+  }
+
+  sidebarMiniOn() {
+    const toggleButton = this.toggleButton;
+    const body = document.getElementsByTagName("body")[0];
+    setTimeout(function() {
+      toggleButton.classList.add("sidebar-mini");
+    }, 500);
+    body.classList.add("sidebar-mini");
+
+    this.sidebarMini = true;
+  }
+
+  sidebarMiniOff() {
+    const body = document.getElementsByTagName("body")[0];
+    //this.toggleButton.classList.remove('');
+    this.sidebarMini = false;
+    body.classList.remove("sidebar-mini");
+  }
+
+  menuToggle() {
+    const body = document.getElementsByTagName("body")[0];
+    //body.classList.add('sidebar-mini');
+    if (this.sidebarMini === false) {
+      this.sidebarMiniOn();
+    } else {
+      this.sidebarMiniOff();
     }
-
-    ngOnInit(){
-      this.listTitles = ROUTES.filter(listTitle => listTitle);
-      this.leTitles = AdminLayoutRoutes.filter(listTitle => listTitle);
-      const navbar: HTMLElement = this.element.nativeElement;
-      this.toggleButton = navbar.getElementsByClassName('navbar-toggler')[0];
-      this.router.events.subscribe((event) => {
-        this.sidebarClose();
-         var $layer: any = document.getElementsByClassName('close-layer')[0];
-         if ($layer) {
-           $layer.remove();
-           this.mobile_menu_visible = 0;
-         }
-     });
+  }
+
+  sidebarOpen() {
+    const toggleButton = this.toggleButton;
+    const body = document.getElementsByTagName("body")[0];
+    setTimeout(function() {
+      toggleButton.classList.add("toggled");
+    }, 500);
+
+    body.classList.add("nav-open");
+
+    this.sidebarVisible = true;
+  }
+  sidebarClose() {
+    const body = document.getElementsByTagName("body")[0];
+    this.toggleButton.classList.remove("toggled");
+    this.sidebarVisible = false;
+    body.classList.remove("nav-open");
+  }
+  sidebarToggle() {
+    // const toggleButton = this.toggleButton;
+    // const body = document.getElementsByTagName('body')[0];
+    var $toggle = document.getElementsByClassName("navbar-toggler")[0];
+
+    if (this.sidebarVisible === false) {
+      this.sidebarOpen();
+    } else {
+      this.sidebarClose();
     }
+    const body = document.getElementsByTagName("body")[0];
 
-    sidebarMiniOn() {
-      const toggleButton = this.toggleButton;
-      const body = document.getElementsByTagName('body')[0];
-      setTimeout(function(){
-        toggleButton.classList.add('sidebar-mini');
-      }, 500);
-      body.classList.add('sidebar-mini');
-
-      this.sidebarMini = true;
-    };
-
-    sidebarMiniOff() {
-      const body = document.getElementsByTagName('body')[0];
-      //this.toggleButton.classList.remove('');
-      this.sidebarMini = false;
-      body.classList.remove('sidebar-mini');
-    };
-
-    menuToggle(){
-      const body = document.getElementsByTagName('body')[0];
-      //body.classList.add('sidebar-mini');
-      if (this.sidebarMini === false) {
-          this.sidebarMiniOn();
-      } else {
-          this.sidebarMiniOff();
+    if (this.mobile_menu_visible == 1) {
+      // $('html').removeClass('nav-open');
+      body.classList.remove("nav-open");
+      if ($layer) {
+        $layer.remove();
       }
-    }
-
-    sidebarOpen() {
-      const toggleButton = this.toggleButton;
-      const body = document.getElementsByTagName('body')[0];
-      setTimeout(function(){
-        toggleButton.classList.add('toggled');
-      }, 500);
-
-      body.classList.add('nav-open');
-
-      this.sidebarVisible = true;
-    };
-    sidebarClose() {
-      const body = document.getElementsByTagName('body')[0];
-      this.toggleButton.classList.remove('toggled');
-      this.sidebarVisible = false;
-      body.classList.remove('nav-open');
-    };
-    sidebarToggle() {
-      // const toggleButton = this.toggleButton;
-      // const body = document.getElementsByTagName('body')[0];
-      var $toggle = document.getElementsByClassName('navbar-toggler')[0];
-
-      if (this.sidebarVisible === false) {
-          this.sidebarOpen();
-      } else {
-          this.sidebarClose();
+      setTimeout(function() {
+        $toggle.classList.remove("toggled");
+      }, 400);
+
+      this.mobile_menu_visible = 0;
+    } else {
+      setTimeout(function() {
+        $toggle.classList.add("toggled");
+      }, 430);
+
+      var $layer = document.createElement("div");
+      $layer.setAttribute("class", "close-layer");
+
+      if (body.querySelectorAll(".main-panel")) {
+        document.getElementsByClassName("main-panel")[0].appendChild($layer);
+      } else if (body.classList.contains("off-canvas-sidebar")) {
+        document
+          .getElementsByClassName("wrapper-full-page")[0]
+          .appendChild($layer);
       }
-      const body = document.getElementsByTagName('body')[0];
-
-      if (this.mobile_menu_visible == 1) {
-          // $('html').removeClass('nav-open');
-          body.classList.remove('nav-open');
-          if ($layer) {
-              $layer.remove();
-          }
-          setTimeout(function() {
-              $toggle.classList.remove('toggled');
-          }, 400);
-
-          this.mobile_menu_visible = 0;
-      } else {
-        setTimeout(function() {
-            $toggle.classList.add('toggled');
-        }, 430);
 
-        var $layer = document.createElement('div');
-        $layer.setAttribute('class', 'close-layer');
-
-        if (body.querySelectorAll('.main-panel')) {
-          document.getElementsByClassName('main-panel')[0].appendChild($layer);
-        }else if (body.classList.contains('off-canvas-sidebar')) {
-          document.getElementsByClassName('wrapper-full-page')[0].appendChild($layer);
-        }
+      setTimeout(function() {
+        $layer.classList.add("visible");
+      }, 100);
 
+      $layer.onclick = function() {
+        //asign a function
+        body.classList.remove("nav-open");
+        this.mobile_menu_visible = 0;
+        $layer.classList.remove("visible");
         setTimeout(function() {
-            $layer.classList.add('visible');
-        }, 100);
-
-        $layer.onclick = function() { //asign a function
-          body.classList.remove('nav-open');
-          this.mobile_menu_visible = 0;
-          $layer.classList.remove('visible');
-          setTimeout(function() {
-            $layer.remove();
-            $toggle.classList.remove('toggled');
-          }, 400);
-        }.bind(this);
-
-        body.classList.add('nav-open');
-        this.mobile_menu_visible = 1;
-      }
-    };
+          $layer.remove();
+          $toggle.classList.remove("toggled");
+        }, 400);
+      }.bind(this);
 
-    logout() {
+      body.classList.add("nav-open");
+      this.mobile_menu_visible = 1;
+    }
+  }
 
-      Swal.fire({
-      
-      });
-      Swal.showLoading();
+  logout() {
+    Swal.fire({
+      allowOutsideClick: false,
+      icon: "info",
+      text: "Espere por favor..."
+    });
+    Swal.showLoading();
 
-      this.auth.logout();
+    this.auth.logout();
 
-      //this.router.navigateByUrl("login");
-    }
+    //this.router.navigateByUrl("login");
+  }
 
-    getTitle(){
-      var titlee = this.location.prepareExternalUrl(this.location.path());
-      var component_local = this.router.url;
-      var main_title:string;
+  getTitle() {
+    var titlee = this.location.prepareExternalUrl(this.location.path());
+    var component_local = this.router.url;
+    var main_title: string;
 
-      if(titlee.charAt(0) === '#'){
-        titlee = titlee.slice( 1 );
-      }
-      var item=0
-      while( item < this.leTitles.length){
-        
-        if("/"+this.leTitles[item].path === titlee){
-          main_title = this.leTitles[item].data['title'];
-          break;
-        }
-        item++;
-      }
-      if (main_title === undefined) {
-        return 'Dashboard';
-      }
-      else {
-        return main_title;
+    if (titlee.charAt(0) === "#") {
+      titlee = titlee.slice(1);
+    }
+    var item = 0;
+    while (item < this.leTitles.length) {
+      if ("/" + this.leTitles[item].path === titlee) {
+        main_title = this.leTitles[item].data["title"];
+        break;
       }
-
+      item++;
+    }
+    if (main_title === undefined) {
+      return "Dashboard";
+    } else {
+      return main_title;
     }
+  }
 }

+ 22 - 9
src/app/components/shared/sidebar/sidebar.component.html

@@ -33,28 +33,41 @@
         <p>{{ menuItem.title }}</p>
       </a>
     </li>
+    <!--
     <li class="nav-item" routerlinkactive="active">
-      <a class="nav-link" data-toggle="collapse" href="#tables">
-        <i class="material-icons"> grid_on </i>
+      <a class="nav-link" data-toggle="collapse" href="#catalogs">
+        <i class="material-icons">grid_on</i>
         <p>Catálogos<b class="caret"></b></p>
       </a>
-      <div class="collapse" id="tables">
+      <div class="collapse" id="catalogs">
         <ul class="nav">
           <li class="nav-item" routerlinkactive="active">
-            <a class="nav-link" href="">
-              <span class="sidebar-mini"> C1 </span>
-              <span class="sidebar-normal"> Catalogo </span>
+            <a class="nav-link" href="#/companies">
+              <span class="sidebar-mini">EMP</span>
+              <span class="sidebar-normal">Empresas</span>
+            </a>
+          </li>
+          <li class="nav-item" routerlinkactive="active">
+            <a class="nav-link" href="#/countries">
+              <span class="sidebar-mini">PAI</span>
+              <span class="sidebar-normal">Países</span>
             </a>
           </li>
           <li class="nav-item" routerlinkactive="active">
-            <a class="nav-link" href="">
-              <span class="sidebar-mini"> C2 </span>
+            <a class="nav-link" href="#/emitters">
+              <span class="sidebar-mini">EMI</span>
+              <span class="sidebar-normal">Emisores</span>
+            </a>
+          </li>
+          <li class="nav-item" routerlinkactive="active">
+            <a class="nav-link" href="#">
+              <span class="sidebar-mini">C2</span>
               <span class="sidebar-normal">Catalogo</span>
             </a>
           </li>
         </ul>
       </div>
-    </li>
+    </li>-->
     <hr />
   </ul>
 

+ 2 - 2
src/app/components/shared/sidebar/sidebar.component.scss

@@ -3,7 +3,7 @@ ul.nav.navbar-nav.nav-mobile-menu-bottom {
   width: 100%;
 }
 
-span.nav-link{
+span.nav-link {
   margin: 10px 15px 0;
   padding: 10px 12px;
-}
+}

+ 33 - 7
src/app/components/shared/sidebar/sidebar.component.spec.ts

@@ -1,16 +1,22 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { SidebarComponent } from './sidebar.component';
+import { SidebarComponent } from "./sidebar.component";
+import { By } from "@angular/platform-browser";
+import { RouterLinkWithHref } from "@angular/router";
+import { RouterTestingModule } from "@angular/router/testing";
+import { HttpClientModule } from "@angular/common/http";
+import { AuthService } from "../../../services/auth2.service";
 
-describe('SidebarComponent', () => {
+describe("SidebarComponent", () => {
   let component: SidebarComponent;
   let fixture: ComponentFixture<SidebarComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ SidebarComponent ]
-    })
-    .compileComponents();
+      declarations: [SidebarComponent],
+      imports: [RouterTestingModule, HttpClientModule],
+      providers: [AuthService]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +25,27 @@ describe('SidebarComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un link a la página root", () => {
+    const elementos = fixture.debugElement.queryAll(
+      By.directive(RouterLinkWithHref)
+    );
+
+    // console.log( elementos );
+
+    let existe = false;
+
+    for (const elem of elementos) {
+      console.log(elem.attributes);
+      if (elem.attributes["ng-reflect-router-link"] === "/dashboard") {
+        existe = true;
+        break;
+      }
+    }
+
+    expect(existe).toBeTruthy();
+  });
 });

+ 16 - 21
src/app/components/shared/sidebar/sidebar.component.ts

@@ -1,7 +1,6 @@
 import { Component, OnInit } from "@angular/core";
 import { AuthService } from "../../../services/auth2.service";
 import { Router } from "@angular/router";
-import * as CryptoJS from "crypto-js";
 import Swal from "sweetalert2";
 
 declare const $: any;
@@ -23,37 +22,39 @@ export const ROUTES: RouteInfo[] = [
     path: "/investment-proposals",
     title: "Propuestas de inversión",
     icon: "wb_incandescent",
-    class: "",
-    allowed_roles: [2, 3]
-  },
+    class: ""
+    //allowed_roles: [2, 3]
+  }
+  /*,
   {
     path: "/investments",
     title: "Inversiones",
     icon: "work",
-    class: "",
-    allowed_roles: [2, 3]
-  },
+    class: ""
+    //allowed_roles: [2, 3]
+  }
+  /*
   {
     path: "/arbitrations",
     title: "Arbitrajes",
     icon: "flag",
-    class: "",
-    allowed_roles: [2, 3]
+    class: ""
+    //allowed_roles: [2, 3]
   },
   {
     path: "/performances",
     title: "Rendimientos",
     icon: "playlist_add",
-    class: "",
-    allowed_roles: [2, 3]
+    class: ""
+    //allowed_roles: [2, 3]
   },
   {
     path: "/users",
     title: "Usuarios",
     icon: "people",
-    class: "",
-    allowed_roles: [2, 3]
-  }
+    class: ""
+    //allowed_roles: [2, 3]
+  }*/
 ];
 
 @Component({
@@ -67,13 +68,7 @@ export class SidebarComponent implements OnInit {
   adminMenu: boolean = false;
   role_number: any;
 
-  constructor(private auth: AuthService, private router: Router) {
-    var bytes = CryptoJS.AES.decrypt(
-      localStorage.getItem("USER_MENU"),
-      "soma-inverlec-2019"
-    );
-    this.role_number = bytes.toString(CryptoJS.enc.Utf8);
-  }
+  constructor(private auth: AuthService, private router: Router) {}
 
   ngOnInit() {
     this.menuItems = ROUTES.filter(menuItem => menuItem);

+ 0 - 171
src/app/components/users/new-user/new-user.component.html

@@ -1,171 +0,0 @@
-<h2 class="floating-title">{{ title }}</h2>
-
-<div class="main-content">
-  <div class="container-fluid">
-    <div class="row">
-      <div class="col-12">
-        <nav aria-label="breadcrumb">
-          <ol class="breadcrumb">
-            <li class="breadcrumb-item">
-              <a [routerLink]="['/']">Dashboard</a>
-            </li>
-            <li class="breadcrumb-item">
-              <a [routerLink]="['/users']">Usuarios</a>
-            </li>
-            <li class="breadcrumb-item">Nuevo Usuario</li>
-          </ol>
-        </nav>
-      </div>
-    </div>
-    <br />
-    <div class="row justify-content-center">
-      <div class="col-8">
-        <div class="align-container">
-          <div class="card">
-            <div class="card-header card-header-icon card-header-rose">
-              <div class="card-icon">
-                <i class="material-icons">person_add</i>
-              </div>
-              <h4 class="card-title">
-                Nuevo Usuario -
-                <small class="category">Complete la información básica</small>
-              </h4>
-            </div>
-            <div class="card-body">
-              <div class="align-container">
-                <form
-                  class="form-auth-small ng-untouched ng-pristine ng-valid"
-                  [formGroup]="userForm"
-                  (ngSubmit)="createUser()"
-                >
-                  <div class="form-group">
-                    <label for="first_name">Nombre: </label>
-                    <input
-                      type="text"
-                      formControlName="first_name"
-                      class="form-control"
-                      [ngClass]="{
-                        'is-invalid': submitted && f.first_name.errors
-                      }"
-                    />
-                    <div
-                      *ngIf="submitted && f.first_name.errors"
-                      class="invalid-feedback"
-                    >
-                      <div *ngIf="f.first_name.errors.required">
-                        Campo requerido
-                      </div>
-                    </div>
-                  </div>
-
-                  <div class="form-group">
-                    <label for="last_name">Apellido: </label>
-                    <input
-                      type="text"
-                      formControlName="last_name"
-                      class="form-control"
-                      [ngClass]="{
-                        'is-invalid': submitted && f.last_name.errors
-                      }"
-                    />
-                    <div
-                      *ngIf="submitted && f.last_name.errors"
-                      class="invalid-feedback"
-                    >
-                      <div *ngIf="f.last_name.errors.required">
-                        Campo requerido
-                      </div>
-                    </div>
-                  </div>
-
-                  <div class="form-group">
-                    <label for="email">Email: </label>
-                    <input
-                      type="text"
-                      formControlName="email"
-                      class="form-control"
-                      [ngClass]="{ 'is-invalid': submitted && f.email.errors }"
-                    />
-                    <div
-                      *ngIf="submitted && f.email.errors"
-                      class="invalid-feedback"
-                    >
-                      <div *ngIf="f.email.errors.required">Campo requerido</div>
-                    </div>
-                  </div>
-
-                  <div class="form-group">
-                    <label for="role">Rol: </label>
-                    <br />
-
-                    <div class="form-check form-check-inline">
-                      <input
-                        class="form-check-input"
-                        type="radio"
-                        formControlName="role"
-                        id="roleRadios1"
-                        value="0"
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }"
-                      />
-                      <label class="form-check-label" for="roleRadios1">
-                        Invitado
-                      </label>
-                    </div>
-                    <div class="form-check form-check-inline">
-                      <input
-                        class="form-check-input"
-                        type="radio"
-                        formControlName="role"
-                        id="roleRadios2"
-                        value="1"
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }"
-                      />
-                      <label class="form-check-label" for="roleRadios2">
-                        Usuario
-                      </label>
-                    </div>
-                    <div class="form-check form-check-inline">
-                      <input
-                        class="form-check-input"
-                        type="radio"
-                        formControlName="role"
-                        id="roleRadios3"
-                        value="2"
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }"
-                      />
-                      <label class="form-check-label" for="roleRadios3">
-                        Administrador
-                      </label>
-                    </div>
-                    <div class="form-check form-check-inline">
-                      <input
-                        class="form-check-input"
-                        type="radio"
-                        formControlName="role"
-                        id="roleRadios4"
-                        value="3"
-                        [ngClass]="{ 'is-invalid': submitted && f.role.errors }"
-                      />
-                      <label class="form-check-label" for="roleRadios4">
-                        Super Admin
-                      </label>
-                    </div>
-                  </div>
-
-                  <br />
-                  <button class="btn btn-primary">
-                    Crear usuario
-                  </button>
-                </form>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</div>
-
-<ng-template #loadingTmpl>
-  <div>Cargando...</div>
-</ng-template>

+ 0 - 3
src/app/components/users/new-user/new-user.component.scss

@@ -1,3 +0,0 @@
-.card-header-rose {
-  color: #fff;
-}

+ 0 - 95
src/app/components/users/new-user/new-user.component.ts

@@ -1,95 +0,0 @@
-import { Component, OnInit } from "@angular/core";
-import { FormGroup, FormBuilder, Validators, FormArray } from "@angular/forms";
-import { UserService } from "@app/services/user.service";
-import Swal from "sweetalert2";
-
-@Component({
-  selector: "app-new-user",
-  templateUrl: "./new-user.component.html",
-  styleUrls: ["./new-user.component.scss"]
-})
-export class NewUserComponent implements OnInit {
-  title: string = "Nuevo usuario";
-  userForm: FormGroup;
-  submitted: boolean = false;
-  isLoadingOrganization: boolean;
-  listOrganization: any;
-  selectedHobbiesNames: [string];
-
-  constructor(
-    private userService: UserService,
-    private formBuilder: FormBuilder
-  ) {}
-
-  get organizationsFormArr(): FormArray {
-    return this.f && <FormArray>this.f.organizationsFormArr;
-  }
-
-  get organizationsFormGroup(): FormGroup {
-    return this.f && <FormGroup>this.f.organizationsFormGroup;
-  }
-
-  get organizationsFormGroupSelectedIds(): string[] {
-    let ids: string[] = [];
-    for (var key in this.organizationsFormGroup.controls) {
-      if (this.organizationsFormGroup.controls[key].value) {
-        ids.push(key);
-      } else {
-        ids = ids.filter(id => id !== key);
-      }
-    }
-    return ids;
-  }
-
-  ngOnInit() {
-    this.isLoadingOrganization = true;
-    this.userForm = this.formBuilder.group({
-      first_name: [""],
-      last_name: [""],
-      email: [""],
-      role: [""]
-    });
-  }
-
-  buildOrganizationFormGroup(
-    organizations: any,
-    selectedOrganizationIds: string[] = []
-  ): FormGroup {
-    let group = this.formBuilder.group({});
-    organizations.forEach(category => {
-      let isSelected = selectedOrganizationIds.some(id => id === category.id);
-      group.addControl(category.id, this.formBuilder.control(isSelected));
-    });
-    return group;
-  }
-
-  get f() {
-    return this.userForm.controls;
-  }
-
-  createUser() {
-    this.submitted = true;
-
-    // stop here if form is invalid
-    if (this.userForm.invalid) {
-      return;
-    }
-
-    this.userService
-      .createUser({
-        first_name: this.f.first_name.value,
-        last_name: this.f.last_name.value,
-        email: this.f.email.value,
-        role: +this.f.role.value
-      })
-      .subscribe(success => {
-        if (success) {
-          Swal.fire({}).then(result => {
-            if (result.value) {
-              window.location.href = "#/users";
-            }
-          });
-        }
-      });
-  }
-}

+ 0 - 80
src/app/components/users/users.component.html

@@ -1,80 +0,0 @@
-<h2 class="floating-title">{{title}}</h2>
-
-<div class="main-content">
-  <div class="container-fluid">
-    <div class="row">
-      
-      <div class="col-12 align-right">
-        <div class="align-container">
-          
-          <nav aria-label="breadcrumb">
-            <ol class="breadcrumb">
-              <li class="breadcrumb-item"><a [routerLink]="['/']">Dashboard</a></li>
-              <li class="breadcrumb-item">Usuarios</li>
-            </ol>
-          </nav>
-
-          <a class="btn btn-primary" [routerLink]="['/users/new']">
-            Nuevo registro
-          </a>
-        </div>
-      </div>
-
-      <div class="col-12">
-          <div class="align-container">
-
-            <h4><b>Listado de usuarios</b></h4>
-            <div class="example-container mat-elevation-z8">
-              <div class="example-table-container">
-          
-                <table mat-table [dataSource]="dataSource" class="example-table">
-          
-                  <!-- Name Column -->
-                  <ng-container matColumnDef="email">
-                    <th mat-header-cell *matHeaderCellDef>Correo</th>
-                    <td mat-cell *matCellDef="let row">{{row.email}}</td>
-                  </ng-container>
-
-                  <!-- Country Column -->
-                  <ng-container matColumnDef="first_name">
-                    <th mat-header-cell *matHeaderCellDef>Nombre</th>
-                    <td mat-cell *matCellDef="let row">{{row.first_name}}</td>
-                  </ng-container>
-
-                  <!-- Country Column -->
-                  <ng-container matColumnDef="last_name">
-                    <th mat-header-cell *matHeaderCellDef>Apellido</th>
-                    <td mat-cell *matCellDef="let row">{{row.last_name}}</td>
-                  </ng-container>
-                  
-                  <!-- Country Column -->
-                  <ng-container matColumnDef="role">
-                    <th mat-header-cell *matHeaderCellDef>Rol</th>
-                    <td mat-cell *matCellDef="let row">{{userType(row.role)}}</td>
-                  </ng-container>
-
-                  <!--  Column 
-                  <ng-container matColumnDef="id">
-                    <th mat-header-cell *matHeaderCellDef>&nbsp;</th>
-                    <td mat-cell *matCellDef="let row">
-                      <a class="btn btn-primary btn-sm" [routerLink]="['/plant', row.id, 'edit']"  >
-                        Editar
-                      </a>
-                    </td>
-                  </ng-container>
-          -->
-          
-                  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
-                  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
-                </table>
-                <mat-paginator [pageSizeOptions]="[10, 15, 25]" [pageIndex]="0" [pageSize]="10"></mat-paginator>
-              </div>
-            </div>
-          </div>
-      
-      </div>
-      <br>
-      
-    </div>          
-  </div>
-</div>

+ 0 - 0
src/app/components/users/users.component.scss


+ 0 - 25
src/app/components/users/users.component.spec.ts

@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { UsersComponent } from './users.component';
-
-describe('UsersComponent', () => {
-  let component: UsersComponent;
-  let fixture: ComponentFixture<UsersComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [ UsersComponent ]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(UsersComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 76
src/app/components/users/users.component.ts

@@ -1,76 +0,0 @@
-import { Component, ViewChild, OnInit } from "@angular/core";
-
-import { HttpClient } from "@angular/common/http";
-import { User } from "src/app/models/user";
-import { UserService } from "src/app/services/user.service";
-import { MatPaginator } from "@angular/material/paginator";
-import { MatSort } from "@angular/material/sort";
-import { MatTableDataSource } from "@angular/material/table";
-import Swal from "sweetalert2";
-
-@Component({
-  selector: "app-users",
-  templateUrl: "./users.component.html",
-  styleUrls: ["./users.component.scss"]
-})
-export class UsersComponent implements OnInit {
-  title: string = "Usuarios";
-
-  displayedColumns: string[] = ["email", "first_name", "last_name", "role"];
-  //displayedColumns: string[] = ['state'];
-
-  listData: User[] = [];
-  listUsers: any;
-  dataSource = new MatTableDataSource(this.listUsers);
-
-  resultsLength = 0;
-  isLoadingResults = true;
-  isRateLimitReached = false;
-
-  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
-  @ViewChild(MatSort, { static: true }) sort: MatSort;
-  role_number: any;
-
-  constructor(private userService: UserService) {
-    Swal.fire({});
-    Swal.showLoading();
-  }
-
-  ngOnInit() {
-    this.userService.getAllUsers().subscribe(
-      ans => {
-        this.listUsers = ans["data"]["users"];
-        this.dataSource.data = this.listUsers;
-        this.dataSource.paginator = this.paginator;
-        this.dataSource.sort = this.sort;
-      },
-      err => {
-        Swal.fire({});
-      }
-    );
-
-    setTimeout(() => {
-      Swal.close();
-    }, 1200);
-  }
-
-  userType(userRole: any) {
-    switch (+userRole) {
-      case 0:
-        return "Invitado";
-      case 1:
-        return "Usuario";
-      case 2:
-        return "Administrador";
-      case 3:
-        return "Super Admin";
-    }
-  }
-
-  applyFilter(filterValue: string) {
-    this.dataSource.filter = filterValue.trim().toLowerCase();
-    if (this.dataSource.paginator) {
-      this.dataSource.paginator.firstPage();
-    }
-  }
-}

+ 9 - 53
src/app/layouts/admin/admin.component.html

@@ -1,55 +1,11 @@
 <div class="wrapper">
-    <div class="sidebar" data-color="blue" data-background-color="white" >
-        <app-sidebar></app-sidebar>
-        <div class="sidebar-background" ></div>
-    </div>
-    <div class="main-panel">
-      <app-navbar></app-navbar>
-      <router-outlet></router-outlet>
-      <app-footer></app-footer>
-    </div>
-    <!--
-    <div class="fixed-plugin">
-        <div class="dropdown show-dropdown">
-            <a href="#" data-toggle="dropdown" aria-expanded="true">
-                <i class="fa fa-cog fa-2x"> </i>
-            </a>
-            <ul class="dropdown-menu" x-placement="bottom-start">
-                <li class="header-title"> Sidebar Filters</li>
-                <li class="adjustments-line">
-                    <a href="javascript:void(0)" class="switch-trigger active-color">
-                        <div class="ml-auto mr-auto">
-                            <span class="badge filter badge-white" data-color="white"></span>
-                            <span class="badge filter badge-yellow" data-color="yellow"></span>
-                            <span class="badge filter badge-blue active" data-color="blue"></span>
-                            <span class="badge filter badge-green" data-color="green"></span>
-                            <span class="badge filter badge-black" data-color="black"></span>
-                        </div>
-                        <div class="clearfix"></div>
-                    <div class="ripple-container"></div></a>
-                </li>
-                <li class="header-title">Images</li>
-                <li>
-                    <a class="img-holder switch-trigger" href="javascript:void(0)">
-                        <img src="./assets/img/sidebar-1.jpg" alt="">
-                    </a>
-                </li>
-                <li>
-                    <a class="img-holder switch-trigger" href="javascript:void(0)">
-                        <img src="./assets/img/sidebar-2.jpg" alt="">
-                    <div class="ripple-container"></div></a>
-                </li>
-                <li>
-                    <a class="img-holder switch-trigger" href="javascript:void(0)">
-                        <img src="./assets/img/sidebar-3.jpg" alt="">
-                    </a>
-                </li>
-                <li class="active">
-                    <a class="img-holder switch-trigger" href="javascript:void(0)">
-                        <img src="./assets/img/sidebar-4.jpg" alt="">
-                    </a>
-                </li>
-            </ul>
-        </div>
-    </div> -->
+  <div class="sidebar" data-color="blue" data-background-color="white">
+    <app-sidebar></app-sidebar>
+    <div class="sidebar-background"></div>
+  </div>
+  <div class="main-panel">
+    <app-navbar></app-navbar>
+    <router-outlet></router-outlet>
+    <app-footer></app-footer>
+  </div>
 </div>

+ 20 - 7
src/app/layouts/admin/admin.component.spec.ts

@@ -1,16 +1,21 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from "@angular/core/testing";
 
-import { AdminComponent } from './admin.component';
+import { AdminComponent } from "./admin.component";
+import { By } from "@angular/platform-browser";
+import { RouterOutlet, RouterLinkWithHref } from "@angular/router";
+import { NO_ERRORS_SCHEMA } from "@angular/core";
+import { RouterTestingModule } from "@angular/router/testing";
 
-describe('AdminComponent', () => {
+describe("AdminComponent", () => {
   let component: AdminComponent;
   let fixture: ComponentFixture<AdminComponent>;
 
   beforeEach(async(() => {
     TestBed.configureTestingModule({
-      declarations: [ AdminComponent ]
-    })
-    .compileComponents();
+      declarations: [AdminComponent],
+      imports: [RouterTestingModule.withRoutes([])],
+      schemas: [NO_ERRORS_SCHEMA]
+    }).compileComponents();
   }));
 
   beforeEach(() => {
@@ -19,7 +24,15 @@ describe('AdminComponent', () => {
     fixture.detectChanges();
   });
 
-  it('should create', () => {
+  it("should create", () => {
     expect(component).toBeTruthy();
   });
+
+  it("Debe de tener un router-outlet", () => {
+    const fixture = TestBed.createComponent(AdminComponent);
+
+    const debugElement = fixture.debugElement.query(By.directive(RouterOutlet));
+
+    expect(debugElement).not.toBeNull();
+  });
 });

+ 119 - 123
src/app/layouts/admin/admin.component.ts

@@ -1,161 +1,157 @@
-import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
-import { Location, LocationStrategy, PathLocationStrategy, PopStateEvent } from '@angular/common';
-import { filter, map } from 'rxjs/operators';
-import { Subscription } from 'rxjs/Subscription';
+import { Component, OnInit, ViewChild, AfterViewInit } from "@angular/core";
+import {
+  Location,
+  LocationStrategy,
+  PathLocationStrategy,
+  PopStateEvent
+} from "@angular/common";
+import { filter, map } from "rxjs/operators";
+import { Subscription } from "rxjs/Subscription";
 
 //import { NavbarComponent } from '../../components/navbar/navbar.component';
-import { Router, NavigationEnd, NavigationStart } from '@angular/router';
-import PerfectScrollbar from 'perfect-scrollbar';
+import { Router, NavigationEnd, NavigationStart } from "@angular/router";
 import * as $ from "jquery";
 
 @Component({
-  selector: 'app-admin',
-  templateUrl: './admin.component.html',
-  styleUrls: ['./admin.component.scss']
+  selector: "app-admin",
+  templateUrl: "./admin.component.html",
+  styleUrls: ["./admin.component.scss"]
 })
 export class AdminComponent implements OnInit {
   private _router: Subscription;
   private lastPoppedUrl: string;
   private yScrollStack: number[] = [];
 
-  constructor( public location: Location, private router: Router) {}
+  constructor(public location: Location, private router: Router) {}
 
   ngOnInit() {
-      const isWindows = navigator.platform.indexOf('Win') > -1 ? true : false;
-
-      if (isWindows && !document.getElementsByTagName('body')[0].classList.contains('sidebar-mini')) {
-          // if we are on windows OS we activate the perfectScrollbar function
-
-          document.getElementsByTagName('body')[0].classList.add('perfect-scrollbar-on');
-      } else {
-          document.getElementsByTagName('body')[0].classList.remove('perfect-scrollbar-off');
+    const isWindows = navigator.platform.indexOf("Win") > -1 ? true : false;
+
+    const elemMainPanel = <HTMLElement>document.querySelector(".main-panel");
+    const elemSidebar = <HTMLElement>(
+      document.querySelector(".sidebar .sidebar-wrapper")
+    );
+
+    this.location.subscribe((ev: PopStateEvent) => {
+      this.lastPoppedUrl = ev.url;
+    });
+    this.router.events.subscribe((event: any) => {
+      if (event instanceof NavigationStart) {
+        if (event.url != this.lastPoppedUrl)
+          this.yScrollStack.push(window.scrollY);
+      } else if (event instanceof NavigationEnd) {
+        if (event.url == this.lastPoppedUrl) {
+          this.lastPoppedUrl = undefined;
+          window.scrollTo(0, this.yScrollStack.pop());
+        } else window.scrollTo(0, 0);
       }
-      const elemMainPanel = <HTMLElement>document.querySelector('.main-panel');
-      const elemSidebar = <HTMLElement>document.querySelector('.sidebar .sidebar-wrapper');
-
-      this.location.subscribe((ev:PopStateEvent) => {
-          this.lastPoppedUrl = ev.url;
-      });
-       this.router.events.subscribe((event:any) => {
-          if (event instanceof NavigationStart) {
-             if (event.url != this.lastPoppedUrl)
-                 this.yScrollStack.push(window.scrollY);
-         } else if (event instanceof NavigationEnd) {
-             if (event.url == this.lastPoppedUrl) {
-                 this.lastPoppedUrl = undefined;
-                 window.scrollTo(0, this.yScrollStack.pop());
-             } else
-                 window.scrollTo(0, 0);
-         }
-      });
+    });
 
-      this._router = this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => {
-           elemMainPanel.scrollTop = 0;
-           elemSidebar.scrollTop = 0;
+    this._router = this.router.events
+      .pipe(filter(event => event instanceof NavigationEnd))
+      .subscribe((event: NavigationEnd) => {
+        elemMainPanel.scrollTop = 0;
+        elemSidebar.scrollTop = 0;
       });
-      if (window.matchMedia(`(min-width: 960px)`).matches && !this.isMac()) {
-          let ps = new PerfectScrollbar(elemMainPanel);
-          ps = new PerfectScrollbar(elemSidebar);
-      }
-
-      const window_width = $(window).width();
-      let $sidebar = $('.sidebar');
-      let $sidebar_responsive = $('body > .navbar-collapse');
-      let $sidebar_img_container = $sidebar.find('.sidebar-background');
-
 
-      if(window_width > 767){
-          if($('.fixed-plugin .dropdown').hasClass('show-dropdown')){
-              $('.fixed-plugin .dropdown').addClass('open');
-          }
+    const window_width = $(window).width();
+    let $sidebar = $(".sidebar");
+    let $sidebar_responsive = $("body > .navbar-collapse");
+    let $sidebar_img_container = $sidebar.find(".sidebar-background");
 
+    if (window_width > 767) {
+      if ($(".fixed-plugin .dropdown").hasClass("show-dropdown")) {
+        $(".fixed-plugin .dropdown").addClass("open");
       }
+    }
 
-      $('.fixed-plugin a').click(function(event){
-        // Alex if we click on switch, stop propagation of the event, so the dropdown will not be hide, otherwise we set the  section active
-          if($(this).hasClass('switch-trigger')){
-              if(event.stopPropagation){
-                  event.stopPropagation();
-              }
-              else if(window.event){
-                 window.event.cancelBubble = true;
-              }
-          }
-      });
-
-      $('.fixed-plugin .badge').click(function(){
-          let $full_page_background = $('.full-page-background');
-
-
-          $(this).siblings().removeClass('active');
-          $(this).addClass('active');
-
-          var new_color = $(this).data('color');
-
-          if($sidebar.length !== 0){
-              $sidebar.attr('data-color', new_color);
-          }
-
-          if($sidebar_responsive.length != 0){
-              $sidebar_responsive.attr('data-color',new_color);
-          }
-      });
-
-      $('.fixed-plugin .img-holder').click(function(){
-          let $full_page_background = $('.full-page-background');
+    $(".fixed-plugin a").click(function(event) {
+      // Alex if we click on switch, stop propagation of the event, so the dropdown will not be hide, otherwise we set the  section active
+      if ($(this).hasClass("switch-trigger")) {
+        if (event.stopPropagation) {
+          event.stopPropagation();
+        } else if (window.event) {
+          window.event.cancelBubble = true;
+        }
+      }
+    });
 
-          $(this).parent('li').siblings().removeClass('active');
-          $(this).parent('li').addClass('active');
+    $(".fixed-plugin .badge").click(function() {
+      let $full_page_background = $(".full-page-background");
 
+      $(this)
+        .siblings()
+        .removeClass("active");
+      $(this).addClass("active");
 
-          //var new_image = $(this).find("img").attr('src');
+      var new_color = $(this).data("color");
 
-          if($sidebar_img_container.length !=0 ){
-              $sidebar_img_container.fadeOut('fast', function(){
-                 //$sidebar_img_container.css('background-image','url("' + new_image + '")');
-                 $sidebar_img_container.fadeIn('fast');
-              });
-          }
+      if ($sidebar.length !== 0) {
+        $sidebar.attr("data-color", new_color);
+      }
 
-          if($full_page_background.length != 0){
+      if ($sidebar_responsive.length != 0) {
+        $sidebar_responsive.attr("data-color", new_color);
+      }
+    });
+
+    $(".fixed-plugin .img-holder").click(function() {
+      let $full_page_background = $(".full-page-background");
+
+      $(this)
+        .parent("li")
+        .siblings()
+        .removeClass("active");
+      $(this)
+        .parent("li")
+        .addClass("active");
+
+      //var new_image = $(this).find("img").attr('src');
+
+      if ($sidebar_img_container.length != 0) {
+        $sidebar_img_container.fadeOut("fast", function() {
+          //$sidebar_img_container.css('background-image','url("' + new_image + '")');
+          $sidebar_img_container.fadeIn("fast");
+        });
+      }
 
-              $full_page_background.fadeOut('fast', function(){
-                 //$full_page_background.css('background-image','url("' + new_image + '")');
-                 $full_page_background.fadeIn('fast');
-              });
-          }
+      if ($full_page_background.length != 0) {
+        $full_page_background.fadeOut("fast", function() {
+          //$full_page_background.css('background-image','url("' + new_image + '")');
+          $full_page_background.fadeIn("fast");
+        });
+      }
 
-          if($sidebar_responsive.length != 0){
-              //$sidebar_responsive.css('background-image','url("' + new_image + '")');
-          }
-      });
+      if ($sidebar_responsive.length != 0) {
+        //$sidebar_responsive.css('background-image','url("' + new_image + '")');
+      }
+    });
   }
   ngAfterViewInit() {
-      this.runOnRouteChange();
+    this.runOnRouteChange();
   }
-  isMaps(path){
-      var titlee = this.location.prepareExternalUrl(this.location.path());
-      titlee = titlee.slice( 1 );
-      if(path == titlee){
-          return false;
-      }
-      else {
-          return true;
-      }
+  isMaps(path) {
+    var titlee = this.location.prepareExternalUrl(this.location.path());
+    titlee = titlee.slice(1);
+    if (path == titlee) {
+      return false;
+    } else {
+      return true;
+    }
   }
   runOnRouteChange(): void {
     if (window.matchMedia(`(min-width: 960px)`).matches && !this.isMac()) {
-      const elemMainPanel = <HTMLElement>document.querySelector('.main-panel');
-      const ps = new PerfectScrollbar(elemMainPanel);
-      ps.update();
+      const elemMainPanel = <HTMLElement>document.querySelector(".main-panel");
     }
   }
   isMac(): boolean {
-      let bool = false;
-      if (navigator.platform.toUpperCase().indexOf('MAC') >= 0 || navigator.platform.toUpperCase().indexOf('IPAD') >= 0) {
-          bool = true;
-      }
-      return bool;
+    let bool = false;
+    if (
+      navigator.platform.toUpperCase().indexOf("MAC") >= 0 ||
+      navigator.platform.toUpperCase().indexOf("IPAD") >= 0
+    ) {
+      bool = true;
+    }
+    return bool;
   }
-
 }

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä