From e810ce1e5e68b145682ff537b5a4dc93f73d6daa Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Sun, 21 Jul 2024 17:30:55 -0600 Subject: [PATCH] Loan Repayment Schedule with Export to PDF option --- package-lock.json | 175 +++++++++++++++++- package.json | 7 +- .../original-schedule-tab.component.html | 56 +++--- .../original-schedule-tab.component.ts | 13 +- .../repayment-schedule-tab.component.html | 115 ++++++++---- .../repayment-schedule-tab.component.scss | 16 +- .../repayment-schedule-tab.component.ts | 64 ++++++- src/app/loans/models/loan-account.model.ts | 67 +++++++ ...deposit-product-settings-step.component.ts | 6 + ...deposit-product-settings-step.component.ts | 6 + src/assets/styles/_colours.scss | 2 +- src/assets/translations/cs-CS.json | 1 + src/assets/translations/de-DE.json | 1 + src/assets/translations/en-US.json | 1 + src/assets/translations/es-MX.json | 1 + src/assets/translations/fr-FR.json | 1 + src/assets/translations/it-IT.json | 1 + src/assets/translations/ko-KO.json | 1 + src/assets/translations/lt-LT.json | 1 + src/assets/translations/lv-LV.json | 1 + src/assets/translations/ne-NE.json | 1 + src/assets/translations/pt-PT.json | 1 + src/assets/translations/sw-SW.json | 1 + src/environments/.env.ts | 4 +- 24 files changed, 455 insertions(+), 88 deletions(-) diff --git a/package-lock.json b/package-lock.json index 58db47e10..3177ffd6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mifosx-web-app", - "version": "0.0.0", + "version": "0.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mifosx-web-app", - "version": "0.0.0", + "version": "0.10.0", "hasInstallScript": true, "license": "MPL-2.0", "dependencies": { @@ -35,8 +35,11 @@ "@swimlane/ngx-graph": "^8.0.2", "@tailwindcss/forms": "^0.5.4", "chart.js": "3.0.0-alpha", - "d3": "^7.6.1", + "d3": "^7.9.0", + "html2canvas": "^1.4.1", "install": "^0.13.0", + "jspdf": "^2.5.1", + "jspdf-autotable": "^3.8.2", "lodash": "4.17.21", "moment": "^2.29.4", "ngx-mat-select-search": "5.0.0", @@ -2483,7 +2486,6 @@ "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -4396,6 +4398,12 @@ "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", "dev": true }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "optional": true + }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", @@ -5215,7 +5223,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, "bin": { "atob": "bin/atob.js" }, @@ -5438,6 +5445,14 @@ "node": ">=0.10.0" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -5765,6 +5780,17 @@ "https-proxy-agent": "^2.2.1" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -6054,6 +6080,25 @@ } ] }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -6936,6 +6981,17 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/core-js": { + "version": "3.37.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", + "integrity": "sha512-Xn6qmxrQZyB0FFY8E3bgRXei3lWDJHhvI+u0q9TKIYM49G8pAr0FgnnrFRAmsbptZL1yxRADVXn+x5AGsbBfyw==", + "hasInstallScript": true, + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.37.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz", @@ -7161,6 +7217,14 @@ "postcss": "^8.4" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", @@ -8530,7 +8594,7 @@ "version": "2.4.3", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz", "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==", - "dev": true + "devOptional": true }, "node_modules/domutils": { "version": "2.8.0", @@ -9745,6 +9809,11 @@ "pend": "~1.2.0" } }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -10924,6 +10993,18 @@ "node": ">=4" } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/htmlhint": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-1.1.4.tgz", @@ -12467,6 +12548,31 @@ "node >= 0.2.0" ] }, + "node_modules/jspdf": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", + "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", + "dependencies": { + "@babel/runtime": "^7.14.0", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.4.8" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf-autotable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.2.tgz", + "integrity": "sha512-zW1ix99/mtR4MbIni7IqvrpfHmuTaICl6iv6wqjRN86Nxtwaw/QtOeDbpXqYSzHIJK9JvgtLM283sc5x+ipkJg==", + "peerDependencies": { + "jspdf": "^2.5.1" + } + }, "node_modules/jsprim": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", @@ -15158,7 +15264,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "devOptional": true }, "node_modules/picocolors": { "version": "1.0.0", @@ -16903,6 +17009,15 @@ "node": ">=4" } }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -17241,8 +17356,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -17647,6 +17761,15 @@ "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -18899,6 +19022,15 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, "node_modules/state-toggle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", @@ -19952,6 +20084,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", @@ -20611,6 +20752,14 @@ "node": "*" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -21437,6 +21586,14 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", diff --git a/package.json b/package.json index 15519a497..0f734ef3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mifosx-web-app", - "version": "0.0.0", + "version": "0.10.0", "description": "MifosX Web App is the default web application built on top of the Fineract platform for the Mifos user community leveraging the popular Angular framework.", "keywords": [ "mifos", @@ -54,8 +54,11 @@ "@swimlane/ngx-graph": "^8.0.2", "@tailwindcss/forms": "^0.5.4", "chart.js": "3.0.0-alpha", - "d3": "^7.6.1", + "d3": "^7.9.0", + "html2canvas": "^1.4.1", "install": "^0.13.0", + "jspdf": "^2.5.1", + "jspdf-autotable": "^3.8.2", "lodash": "4.17.21", "moment": "^2.29.4", "ngx-mat-select-search": "5.0.0", diff --git a/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.html b/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.html index d24edf076..123887ad9 100644 --- a/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.html +++ b/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.html @@ -2,64 +2,70 @@ + + + + + + - + - - - - - - - - + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.ts b/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.ts index 8c483016e..4334a20ff 100644 --- a/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.ts +++ b/src/app/loans/loans-view/original-schedule-tab/original-schedule-tab.component.ts @@ -1,17 +1,20 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { Currency } from 'app/shared/models/general.model'; @Component({ selector: 'mifosx-original-schedule-tab', templateUrl: './original-schedule-tab.component.html', styleUrls: ['./original-schedule-tab.component.scss'] }) -export class OriginalScheduleTabComponent implements OnInit { +export class OriginalScheduleTabComponent { /** Loan Details Data */ originalScheduleDetails: any; /** Columns to be displayed in original schedule table. */ - displayedColumns: string[] = ['date', 'principalDue', 'balanceOfLoan', 'interest', 'fees', 'penalties', 'outstanding']; + displayedColumns: string[] = ['number', 'date', 'balanceOfLoan', 'principalDue', 'interest', 'fees', 'penalties', 'outstanding']; + + currency: Currency | null = null; /** * Retrieves the loans with associations data from `resolve`. @@ -19,11 +22,9 @@ export class OriginalScheduleTabComponent implements OnInit { */ constructor(private route: ActivatedRoute) { this.route.parent.data.subscribe((data: { loanDetailsData: any }) => { + this.currency = data.loanDetailsData.currency; this.originalScheduleDetails = data.loanDetailsData.originalSchedule; }); } - ngOnInit() { - } - } diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html index 1c682d24c..148fc9d5b 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.html @@ -1,6 +1,11 @@
+
+ +
-
# {{(idx + 1)}}   {{"labels.inputs.Date" | translate}} {{"labels.inputs.Date" | translate}} {{ ele.dueDate | dateFormat}} {{"labels.inputs.Total" | translate}} {{"labels.inputs.Principal Due" | translate}} {{ ele.principalDue | formatNumber }} {{ originalScheduleDetails.totalPrincipalExpected | formatNumber }} {{"labels.inputs.Balance Of Loan" | translate}} {{ ele.principalLoanBalanceOutstanding | formatNumber }} {{"labels.inputs.Balance Of Loan" | translate}} {{ ele.principalLoanBalanceOutstanding | formatNumber }}   {{"labels.inputs.Principal Due" | translate}} {{ ele.principalDue | formatNumber }} {{ originalScheduleDetails.totalPrincipalExpected | currency:currency.code:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Interest" | translate}} {{ ele.interestOriginalDue | formatNumber}} {{ originalScheduleDetails.totalInterestCharged | formatNumber }} {{"labels.inputs.Interest" | translate}} {{ ele.interestOriginalDue | formatNumber}} {{ originalScheduleDetails.totalInterestCharged | currency:currency.code:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Fees" | translate}} {{ ele.feeChargesDue | formatNumber}} {{ originalScheduleDetails.totalFeeChargesCharged | formatNumber }} {{"labels.inputs.Fees" | translate}} {{ ele.feeChargesDue | formatNumber}} {{ originalScheduleDetails.totalFeeChargesCharged | currency:currency.code:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Penalties" | translate}} {{ ele.penaltyChargesDue | formatNumber}} {{ originalScheduleDetails.totalPenaltyChargesCharged | formatNumber }} {{"labels.inputs.Penalties" | translate}} {{ ele.penaltyChargesDue | formatNumber}} {{ originalScheduleDetails.totalPenaltyChargesCharged | currency:currency.code:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Outstanding" | translate}} {{ ele.totalOutstandingForPeriod | formatNumber}} {{ originalScheduleDetails.totalRepaymentExpected | formatNumber }} {{"labels.inputs.Outstanding" | translate}} {{ ele.totalOutstandingForPeriod | formatNumber}} {{ originalScheduleDetails.totalRepaymentExpected | currency:currency.code:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Loan Amount and Balance" | translate}} {{"labels.inputs.Loan Amount and Balance" | translate}} {{"labels.inputs.Total Cost of Loan" | translate}} {{"labels.inputs.Total Cost of Loan" | translate}} {{"labels.inputs.Installment Totals" | translate}} {{"labels.inputs.Installment Totals" | translate}}
+
@@ -16,14 +21,16 @@ - - + + - - + + @@ -36,63 +43,82 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -107,7 +133,8 @@ - + @@ -115,18 +142,22 @@ - + - + - + - + + @@ -134,7 +165,7 @@
# {{"labels.inputs.Date" | translate}} {{ ele.dueDate | dateFormat}} {{ ele.dueDate | dateFormat}} + {{"labels.inputs.Paid Date" | translate}} {{ ele.obligationsMetOnDate | dateFormat}} {{ ele.obligationsMetOnDate | + dateFormat}} {{"labels.inputs.Balance Of Loan" | translate}} {{ ele.principalLoanBalanceOutstanding | formatNumber }} {{ + ele.principalLoanBalanceOutstanding | formatNumber }}   {{"labels.inputs.Principal Due" | translate}} {{ ele.principalDue | formatNumber }} {{ repaymentScheduleDetails.totalPrincipalExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.principalDue | + formatNumber }} {{ + repaymentScheduleDetails.totalPrincipalExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Interest" | translate}} {{ ele.interestOriginalDue | formatNumber}} {{ repaymentScheduleDetails.totalInterestCharged | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.interestOriginalDue + | formatNumber}} {{ repaymentScheduleDetails.totalInterestCharged | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Fees" | translate}} {{ ele.feeChargesDue | formatNumber}} {{ repaymentScheduleDetails.totalFeeChargesCharged | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.feeChargesDue | + formatNumber}} {{ repaymentScheduleDetails.totalFeeChargesCharged | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Penalties" | translate}} {{ ele.penaltyChargesDue | formatNumber}} {{ repaymentScheduleDetails.totalPenaltyChargesCharged | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.penaltyChargesDue | + formatNumber}} {{ repaymentScheduleDetails.totalPenaltyChargesCharged + | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Due" | translate}} {{ ele.totalDueForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalRepaymentExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.totalDueForPeriod | + formatNumber}} {{ repaymentScheduleDetails.totalRepaymentExpected | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Paid" | translate}} {{ ele.totalPaidForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalRepayment | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ ele.totalPaidForPeriod | + formatNumber}} {{ repaymentScheduleDetails.totalRepayment | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.In advance" | translate}} {{ ele.totalPaidInAdvanceForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalPaidInAdvance | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ + ele.totalPaidInAdvanceForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalPaidInAdvance | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Late" | translate}} {{ ele.totalPaidLateForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalPaidLate | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ + ele.totalPaidLateForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalPaidLate | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Waived" | translate}} {{ ele.totalWaivedForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalWaived | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ + ele.totalWaivedForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalWaived | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Outstanding" | translate}} {{ ele.totalOutstandingForPeriod | formatNumber}} {{ repaymentScheduleDetails.totalOutstanding | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ repaymentScheduleDetails.totalOutstanding | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Loan Amount and Balance" | translate}} {{"labels.inputs.Loan Amount and Balance" + | translate}} {{"labels.inputs.Total Cost of Loan" | translate}} {{"labels.inputs.Total Cost of Loan" | + translate}} {{"labels.inputs.Installment Totals" | translate}} {{"labels.inputs.Installment Totals" | + translate}}
-
+
@@ -147,31 +178,35 @@ - + - + - + - + - + @@ -184,17 +219,19 @@ {{ ele.totalDueForPeriod | formatNumber}} - + - + @@ -205,4 +242,4 @@ - + \ No newline at end of file diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss index 0dc256e14..77139400e 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss @@ -2,7 +2,7 @@ table { width: 100%; - margin: 3% 0%; + margin: 2% 0%; } .container { @@ -23,4 +23,16 @@ table { .downpayment { color: $status-downpayment; -} \ No newline at end of file +} + +.paid { + color: $state-done; +} + +.current { + color: $status-active; +} + +.overdued { + color: $status-matured; +} diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts index 12fab2aed..b00505cb1 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.ts @@ -1,5 +1,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; +import { Dates } from 'app/core/utils/dates'; +import { RepaymentSchedulePeriod } from 'app/loans/models/loan-account.model'; +import { SettingsService } from 'app/settings/settings.service'; + +import {jsPDF, jsPDFOptions} from 'jspdf'; +import autoTable from 'jspdf-autotable'; @Component({ selector: 'mifosx-repayment-schedule-tab', @@ -26,17 +32,23 @@ export class RepaymentScheduleTabComponent implements OnInit { /** Form functions event */ @Output() editPeriod = new EventEmitter(); + businessDate: Date = new Date(); + /** * Retrieves the loans with associations data from `resolve`. * @param {ActivatedRoute} route Activated Route. */ - constructor(private route: ActivatedRoute) { + constructor(private route: ActivatedRoute, + private settingsService: SettingsService, + private dates: Dates + ) { this.route.parent.data.subscribe((data: { loanDetailsData: any }) => { if (data.loanDetailsData) { this.currencyCode = data.loanDetailsData.currency.code; } this.loanDetailsDataRepaymentSchedule = data.loanDetailsData ? data.loanDetailsData.repaymentSchedule : []; }); + this.businessDate = this.settingsService.businessDate; } ngOnInit() { @@ -46,7 +58,14 @@ export class RepaymentScheduleTabComponent implements OnInit { this.isWaived = this.repaymentScheduleDetails.totalWaived > 0; } - installmentStyle(installment: any): string { + installmentStyle(installment: RepaymentSchedulePeriod): string { + if (installment.complete) { + return 'paid'; + } + const isCurrent: string = this.isCurrent(installment); + if (isCurrent !== '') { + return isCurrent; + } if (installment.isAdditional) { return 'additional'; } else if (installment.downPaymentPeriod) { @@ -55,4 +74,45 @@ export class RepaymentScheduleTabComponent implements OnInit { return ''; } + isCurrent(installment: RepaymentSchedulePeriod): string { + if (!installment.fromDate) { + return ''; + } else { + const fromDate = this.dates.parseDate(installment.fromDate); + const dueDate = this.dates.parseDate(installment.dueDate); + if (fromDate <= this.businessDate && this.businessDate < dueDate) { + return 'current'; + } + if (this.businessDate > dueDate) { + return 'overdued'; + } + } + return ''; + } + + exportToPDF() { + const businessDate = this.dates.formatDate(this.settingsService.businessDate, Dates.DEFAULT_DATEFORMAT); + const fileName = `repaymentschedule-${businessDate}.pdf`; + + const options: jsPDFOptions = { + orientation: 'l', + unit: 'in', + format: 'letter', + precision: 2, + compress: true, + putOnlyUsedFonts: true + }; + const pdf = new jsPDF(options); + + autoTable(pdf, { + html: '#repaymentSchedule', + bodyStyles: {lineColor: [0, 0, 0]}, + styles: { + fontSize: 8, + cellWidth: 'auto', + halign: 'center' + }}); + pdf.save(fileName); + } + } diff --git a/src/app/loans/models/loan-account.model.ts b/src/app/loans/models/loan-account.model.ts index 9bda04802..5a4882715 100644 --- a/src/app/loans/models/loan-account.model.ts +++ b/src/app/loans/models/loan-account.model.ts @@ -1,3 +1,4 @@ +import { Currency } from 'app/shared/models/general.model'; export interface DelinquencyRange { id: number; @@ -49,3 +50,69 @@ export interface DelinquencyPausePeriod { pausePeriodStart: number[]; pausePeriodEnd: number[]; } + + +export interface RepaymentSchedule { + currency: Currency; + loanTermInDays: number; + totalPrincipalDisbursed: number; + totalPrincipalExpected: number; + totalPrincipalPaid: number; + totalInterestCharged: number; + totalFeeChargesCharged: number; + totalPenaltyChargesCharged: number; + totalWaived: number; + totalWrittenOff: number; + totalRepaymentExpected: number; + totalRepayment: number; + totalPaidInAdvance: number; + totalPaidLate: number; + totalOutstanding: number; + totalCredits: number; + periods: RepaymentSchedulePeriod[]; +} + +export interface RepaymentSchedulePeriod { + dueDate: number[]; + principalDisbursed?: number; + principalLoanBalanceOutstanding: number; + feeChargesDue: number; + feeChargesPaid: number; + feeChargesOutstanding: number; + totalOriginalDueForPeriod: number; + totalDueForPeriod: number; + totalPaidForPeriod: number; + totalOutstandingForPeriod: number; + totalOverdue?: number; + totalActualCostOfLoanForPeriod: number; + totalCredits: number; + period?: number; + fromDate?: number[]; + complete?: boolean; + isAdditional?: boolean; + downPaymentPeriod?: boolean; + daysInPeriod?: number; + principalOriginalDue?: number; + principalDue?: number; + principalPaid?: number; + principalWrittenOff?: number; + principalOutstanding?: number; + interestOriginalDue?: number; + interestDue?: number; + interestPaid?: number; + interestWaived?: number; + interestWrittenOff?: number; + interestOutstanding?: number; + feeChargesWaived?: number; + feeChargesWrittenOff?: number; + penaltyChargesDue?: number; + penaltyChargesPaid?: number; + penaltyChargesWaived?: number; + penaltyChargesWrittenOff?: number; + penaltyChargesOutstanding?: number; + totalPaidInAdvanceForPeriod?: number; + totalPaidLateForPeriod?: number; + totalWaivedForPeriod?: number; + totalWrittenOffForPeriod?: number; + totalInstallmentAmountForPeriod?: number; +} diff --git a/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-settings-step/fixed-deposit-product-settings-step.component.ts b/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-settings-step/fixed-deposit-product-settings-step.component.ts index 9a0c51f1b..32d73ec34 100644 --- a/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-settings-step/fixed-deposit-product-settings-step.component.ts +++ b/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-settings-step/fixed-deposit-product-settings-step.component.ts @@ -48,6 +48,12 @@ export class FixedDepositProductSettingsStepComponent implements OnInit { 'withHoldTax': this.fixedDepositProductsTemplate.withHoldTax }); } + + if (this.fixedDepositProductsTemplate.withHoldTax) { + this.fixedDepositProductSettingsForm.patchValue({ + 'taxGroupId': this.fixedDepositProductsTemplate.taxGroup ? this.fixedDepositProductsTemplate.taxGroup.id : '' + }); + } } createFixedDepositProductSettingsForm() { diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts index c2c1de14e..17c938674 100644 --- a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts @@ -47,6 +47,12 @@ export class RecurringDepositProductSettingsStepComponent implements OnInit { 'withHoldTax': this.recurringDepositProductsTemplate.withHoldTax }); } + + if (this.recurringDepositProductsTemplate.withHoldTax) { + this.recurringDepositProductSettingsForm.patchValue({ + 'taxGroupId': this.recurringDepositProductsTemplate.taxGroup ? this.recurringDepositProductsTemplate.taxGroup.id : '' + }); + } } createrecurringDepositProductSettingsForm() { diff --git a/src/assets/styles/_colours.scss b/src/assets/styles/_colours.scss index ad61dd323..32eaa6ff4 100644 --- a/src/assets/styles/_colours.scss +++ b/src/assets/styles/_colours.scss @@ -63,7 +63,7 @@ $highlight: $belize-hole; $accent: $peter-river; //Status Colors Defined Here -$status-active: #00ce00; +$status-active: #5cb85c; $status-inactive: #666f73; $status-deleted: #000000; $status-pending: #ffa500; diff --git a/src/assets/translations/cs-CS.json b/src/assets/translations/cs-CS.json index 06d53d84f..dbd28e612 100644 --- a/src/assets/translations/cs-CS.json +++ b/src/assets/translations/cs-CS.json @@ -576,6 +576,7 @@ "Specified due date": "Specified due date", "Installment Fee": "Installment Fee", "Overdue Fees": "Overdue Fees", + "Overdraft Fee": "Poplatek za přečerpání", "Tranche Disbursement": "Tranche Disbursement", "Savings Activation": "Savings Activation", "Saving No Activity Fee": "Ušetříte žádný poplatek za aktivitu", diff --git a/src/assets/translations/de-DE.json b/src/assets/translations/de-DE.json index 48f7f9cc5..b77b766f0 100644 --- a/src/assets/translations/de-DE.json +++ b/src/assets/translations/de-DE.json @@ -576,6 +576,7 @@ "Specified due date": "Angegebenes Fälligkeitsdatum", "Installment Fee": "Ratenzahlungsgebühr", "Overdue Fees": "Überfällige Gebühren", + "Overdraft Fee": "Überziehungsgebühr", "Tranche Disbursement": "Tranchenauszahlung", "Savings Activation": "Sparaktivierung", "Saving No Activity Fee": "Sparen Sie keine Aktivitätsgebühr", diff --git a/src/assets/translations/en-US.json b/src/assets/translations/en-US.json index d21b39f30..4bb7e2143 100644 --- a/src/assets/translations/en-US.json +++ b/src/assets/translations/en-US.json @@ -576,6 +576,7 @@ "Specified due date": "Specified due date", "Installment Fee": "Installment Fee", "Overdue Fees": "Overdue Fees", + "Overdraft Fee": "Overdraft Fee", "Tranche Disbursement": "Tranche Disbursement", "Savings Activation": "Savings Activation", "Saving No Activity Fee": "Saving No Activity Fee", diff --git a/src/assets/translations/es-MX.json b/src/assets/translations/es-MX.json index 1e9c8bfdd..81971b0f9 100644 --- a/src/assets/translations/es-MX.json +++ b/src/assets/translations/es-MX.json @@ -576,6 +576,7 @@ "Specified due date": "Fecha de Vencimiento", "Installment Fee": "Cuota de pago", "Overdue Fees": "Cuotas vencidas", + "Overdraft Fee": "Cargo por sobregiro", "Tranche Disbursement": "Multiple Desembolso", "Savings Activation": "Activación de Cuenta", "Saving No Activity Fee": "Ahorro sin Actividad", diff --git a/src/assets/translations/fr-FR.json b/src/assets/translations/fr-FR.json index 1339c3dd6..1ee1c9e78 100644 --- a/src/assets/translations/fr-FR.json +++ b/src/assets/translations/fr-FR.json @@ -576,6 +576,7 @@ "Specified due date": "Date d'échéance spécifiée", "Installment Fee": "Frais de versement", "Overdue Fees": "Frais de retard", + "Overdraft Fee": "Frais de découvert", "Tranche Disbursement": "Décaissement des tranches", "Savings Activation": "Activation de l'épargne", "Saving No Activity Fee": "Économiser sans frais d'activité", diff --git a/src/assets/translations/it-IT.json b/src/assets/translations/it-IT.json index 8d4b09642..5d4cbfcec 100644 --- a/src/assets/translations/it-IT.json +++ b/src/assets/translations/it-IT.json @@ -576,6 +576,7 @@ "Specified due date": "Data di scadenza specificata", "Installment Fee": "Commissione di rata", "Overdue Fees": "Commissioni scadute", + "Overdraft Fee": "Commissione di scoperto", "Tranche Disbursement": "Erogazione della tranche", "Savings Activation": "Attivazione del risparmio", "Saving No Activity Fee": "Risparmio senza costi di attività", diff --git a/src/assets/translations/ko-KO.json b/src/assets/translations/ko-KO.json index 09d7650e7..182808e8d 100644 --- a/src/assets/translations/ko-KO.json +++ b/src/assets/translations/ko-KO.json @@ -576,6 +576,7 @@ "Specified due date": "지정된 마감일", "Installment Fee": "할부 수수료", "Overdue Fees": "연체 수수료", + "Overdraft Fee": "초과인월 수수료", "Tranche Disbursement": "트랜치 지급", "Savings Activation": "저축 활성화", "Saving No Activity Fee": "활동비 절약", diff --git a/src/assets/translations/lt-LT.json b/src/assets/translations/lt-LT.json index 392d62447..687c4ffc7 100644 --- a/src/assets/translations/lt-LT.json +++ b/src/assets/translations/lt-LT.json @@ -576,6 +576,7 @@ "Specified due date": "Nurodytas terminas", "Installment Fee": "Įmokos mokestis", "Overdue Fees": "Pradelsti mokesčiai", + "Overdraft Fee": "Overdrafto mokestis", "Tranche Disbursement": "Dalies išmokėjimas", "Savings Activation": "Taupymo aktyvinimas", "Saving No Activity Fee": "Sutaupykite jokios veiklos mokesčio", diff --git a/src/assets/translations/lv-LV.json b/src/assets/translations/lv-LV.json index 73c775bea..50a998172 100644 --- a/src/assets/translations/lv-LV.json +++ b/src/assets/translations/lv-LV.json @@ -576,6 +576,7 @@ "Specified due date": "Norādīts izpildes datums", "Installment Fee": "Nomaksas maksa", "Overdue Fees": "Nokavējuma maksas", + "Overdraft Fee": "Overdrafta maksa", "Tranche Disbursement": "Daļas izmaksa", "Savings Activation": "Uzkrājumu aktivizēšana", "Saving No Activity Fee": "Ietaupot bezdarbības maksu", diff --git a/src/assets/translations/ne-NE.json b/src/assets/translations/ne-NE.json index fc61f702e..bc5c3e5b9 100644 --- a/src/assets/translations/ne-NE.json +++ b/src/assets/translations/ne-NE.json @@ -576,6 +576,7 @@ "Specified due date": "तोकिएको म्याद मिति", "Installment Fee": "किस्ता शुल्क", "Overdue Fees": "अतिदेय शुल्क", + "Overdraft Fee": "ओभरड्राफ्ट शुल्क", "Tranche Disbursement": "किस्ता वितरण", "Savings Activation": "बचत सक्रियता", "Saving No Activity Fee": "कुनै गतिविधि शुल्क बचत गर्दै", diff --git a/src/assets/translations/pt-PT.json b/src/assets/translations/pt-PT.json index 7d636ee35..6fdfc01a4 100644 --- a/src/assets/translations/pt-PT.json +++ b/src/assets/translations/pt-PT.json @@ -576,6 +576,7 @@ "Specified due date": "Data de vencimento especificada", "Installment Fee": "Taxa de parcelamento", "Overdue Fees": "Taxas vencidas", + "Overdraft Fee": "Taxa de cheque especial", "Tranche Disbursement": "Desembolso da Tranche", "Savings Activation": "Ativação de poupança", "Saving No Activity Fee": "Economizando sem taxa de atividade", diff --git a/src/assets/translations/sw-SW.json b/src/assets/translations/sw-SW.json index 797279f96..7dc727dff 100644 --- a/src/assets/translations/sw-SW.json +++ b/src/assets/translations/sw-SW.json @@ -576,6 +576,7 @@ "Specified due date": "Tarehe ya mwisho iliyoainishwa", "Installment Fee": "Ada ya Ufungaji", "Overdue Fees": "Ada Zilizochelewa", + "Overdraft Fee": "Ada ya Overdraft", "Tranche Disbursement": "Utoaji wa Tranche", "Savings Activation": "Uanzishaji wa Akiba", "Saving No Activity Fee": "Haihifadhi Ada ya Shughuli", diff --git a/src/environments/.env.ts b/src/environments/.env.ts index 97ca46b13..1fd11c72d 100644 --- a/src/environments/.env.ts +++ b/src/environments/.env.ts @@ -2,8 +2,8 @@ /* tslint:disable */ export default { 'mifos_x': { - 'version': '240706', - 'hash': '71b9b7d7' + 'version': '240721', + 'hash': 'd39a6d8a' }, 'allow_switching_backend_instance': true };
{{"labels.inputs.Date" | translate}} {{ ele.dueDate | dateFormat}} {{"labels.inputs.Balance Of Loan" | translate}} {{ ele.principalLoanBalanceOutstanding | formatNumber }} {{ ele.principalLoanBalanceOutstanding | formatNumber }} +   {{"labels.inputs.Principal Due" | translate}} {{ ele.principalDue | formatNumber }} {{ repaymentScheduleDetails.totalPrincipalExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ + repaymentScheduleDetails.totalPrincipalExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Interest" | translate}} {{ ele.interestOriginalDue | formatNumber}} {{ repaymentScheduleDetails.totalInterestCharged | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ repaymentScheduleDetails.totalInterestCharged | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Fees" | translate}} {{ ele.feeChargesDue | formatNumber}} {{ repaymentScheduleDetails.totalFeeChargesCharged | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ repaymentScheduleDetails.totalFeeChargesCharged | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ repaymentScheduleDetails.totalRepaymentExpected | currency:currencyCode:'symbol-narrow':'1.2-2' }} {{ repaymentScheduleDetails.totalRepaymentExpected | + currency:currencyCode:'symbol-narrow':'1.2-2' }} {{"labels.inputs.Actions" | translate}} -