diff --git a/angular.json b/angular.json index d377ff63..1b519384 100644 --- a/angular.json +++ b/angular.json @@ -182,5 +182,8 @@ } } } + }, + "cli": { + "analytics": false } } diff --git a/env.sample b/env.sample index 9ee78a51..132e58cc 100644 --- a/env.sample +++ b/env.sample @@ -1,33 +1,36 @@ PH_OPS_BACKEND_SERVER_URL=https://paymenthub.qa.oneacrefund.org/opsapp/api/v1 +export PH_OPS_BATCH_SIGNATURE=12345677899 +export PH_OPS_BULK_CONNECTOR_URL=https://paymenthub.qa.oneacrefund.org PH_VOU_BACKEND_SERVER_URL=https://paymenthub.qa.oneacrefund.org/opsapp/api/v1 +export PH_VOU_CALLBACK_URL=https://webhook.site/ PH_ACT_BACKEND_SERVER_URL=https://paymenthub.qa.oneacrefund.org/opsapp/api/v1 -PH_PLATFORM_TENANT_ID=phdefault +export PH_PLATFORM_TENANT_ID=phdefault -PH_PLATFORM_TENANT_IDS=phdefault +export PH_PLATFORM_TENANT_IDS=phdefault -PH_REGISTERING_INSTITUTION_ID=SocialInstitution +export PH_REGISTERING_INSTITUTION_ID=SocialInstitution -PH_AUTH_ENABLED=true +export PH_AUTH_ENABLED=false -PH_OAUTH_ENABLED=false +export PH_OAUTH_ENABLED=false -PH_OAUTH_TYPE=keycloak +export PH_OAUTH_TYPE=keycloak -PH_OAUTH_SERVER_URL=https://ops-bk.sandbox.fynarfin.io +export PH_OAUTH_SERVER_URL=https://paymenthub.qa.oneacrefund.org/opsapp/api/v1 -PH_OAUTH_REALM=paymenthub +export PH_OAUTH_REALM=paymenthub -PH_OAUTH_CLIENT_ID=opsapp +export PH_OAUTH_CLIENT_ID=opsapp -PH_OAUTH_CLIENT_SECRET=Y2xpZW50Og== +export PH_OAUTH_CLIENT_SECRET=Y2xpZW50Og= -PH_OAUTH_BASIC_AUTH=true +export PH_OAUTH_BASIC_AUTH=true -PH_OAUTH_BASIC_AUTH_TOKEN=Y2xpZW50Og== +export PH_OAUTH_BASIC_AUTH_TOKEN=Y2xpZW50Og== -PH_DEFAULT_LANGUAGE=en-US +export PH_DEFAULT_LANGUAGE=en -PH_SUPPORTED_LANGUAGES=en-US,fr-FR +export PH_SUPPORTED_LANGUAGES=en,fr,es diff --git a/package.json b/package.json index 66c91ba5..fd88fb89 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "ng": "ng", "build": "npm run env -s && ng build --configuration production --output-hashing=none", "build:prod": "node --max-old-space-size=16384 ./node_modules/@angular/cli/bin/ng build --configuration production --output-hashing=none --base-href=\"/ph-ee-operations-web/\"", - "start": "npm run env -s && ng serve --aot --proxy-config proxy.conf.js", + "start": "npm run env -s && ng serve --aot", "serve:sw": "npm run build -s && npx http-server ./dist -p 4200", "lint": "ng lint && stylelint \"src/**/*.scss\" --syntax scss && htmlhint \"src\" --config .htmlhintrc", "test": "npm run env -s && ng test", @@ -48,15 +48,18 @@ "@swimlane/ngx-charts": "20.0.1", "angular-archwizard": "5.0.0", "core-js": "2.5.0", + "js-sha3": "^0.9.3", "jwt-decode": "^2.2.0", "keycloak-angular": "^14.1.0", "keycloak-js": "^22.0.3", "lodash": "4.17.21", - "moment": "^2.29.4", "ngx-csv-parser": "^1.3.1", + "ngx-file-drop": "^16.0.0", + "node-forge": "^1.3.1", "rxjs": "7.8.0", "sass": "^1.47.0", "tslib": "^2.0.0", + "xlsx": "^0.18.5", "xng-breadcrumb": "10.0.0", "zone.js": "~0.13.1" }, @@ -73,12 +76,12 @@ "@types/jwt-decode": "^2.2.1", "@types/lodash": "4.14.132", "@types/node": "^12.11.1", + "@types/node-forge": "^1.3.11", "@types/uuid": "^9.0.7", "codelyzer": "6.0.0", "daisyui": "^3.6.5", "hads": "1.7.3", "htmlhint": "0.11.0", - "https-proxy-agent": "5.0.0", "jasmine-core": "~3.5.0", "jasmine-spec-reporter": "~5.0.0", "karma": "~6.3.16", diff --git a/proxy.conf.js b/proxy.conf.js deleted file mode 100644 index a4b91a36..00000000 --- a/proxy.conf.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const HttpsProxyAgent = require('https-proxy-agent'); - -/* - * API proxy configuration. - * This allows you to proxy HTTP request like `http.get('/api/stuff')` to another server/port. - * This is especially useful during app development to avoid CORS issues while running a local server. - * For more details and options, see https://github.com/angular/angular-cli#proxy-to-backend - */ -const proxyConfig = [ - { - context: '/oauth', - pathRewrite: { '^/oauth': 'oauth' }, - target: 'http://localhost:8080', - changeOrigin: true, - secure: false - } -]; - -/* - * Configures a corporate proxy agent for the API proxy if needed. - */ -function setupForCorporateProxy(proxyConfig) { - if (!Array.isArray(proxyConfig)) { - proxyConfig = [proxyConfig]; - } - - const proxyServer = process.env.http_proxy || process.env.HTTP_PROXY; - let agent = null; - - if (proxyServer) { - console.log(`Using corporate proxy server: ${proxyServer}`); - agent = new HttpsProxyAgent(proxyServer); - proxyConfig.forEach(entry => { entry.agent = agent; }); - } - - return proxyConfig; -} - -module.exports = setupForCorporateProxy(proxyConfig); diff --git a/proxy.conf.json b/proxy.conf.json deleted file mode 100644 index 413928c7..00000000 --- a/proxy.conf.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "/opsapp": { - "target": "https://ops-bk.sandbox.fynarfin.io", - "secure": true, - "changeOrigin": true - } - } \ No newline at end of file diff --git a/src/app/account-mapper/account-mapper-routing.module.ts b/src/app/account-mapper/account-mapper-routing.module.ts index be3f7eb4..9010c72b 100644 --- a/src/app/account-mapper/account-mapper-routing.module.ts +++ b/src/app/account-mapper/account-mapper-routing.module.ts @@ -1,16 +1,15 @@ -import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; -import { Route } from "app/core/route/route.service"; -import { extract } from "app/core/i18n/i18n.service"; -import { AccountMapperComponent } from "./account-mapper/account-mapper.component"; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { Route } from 'app/core/route/route.service'; +import { AccountMapperComponent } from './account-mapper/account-mapper.component'; const routes: Routes = [ Route.withShell([ { - path: "account-mapper", + path: 'account-mapper', component: AccountMapperComponent, - data: { title: extract("Account Mapper"), breadcrumb: "Account Mapper" }, + data: { title: 'Account Mapper', breadcrumb: 'Account Mapper' }, children: [ ] } diff --git a/src/app/account-mapper/account-mapper/account-mapper.component.html b/src/app/account-mapper/account-mapper/account-mapper.component.html index ced28026..09f75a0a 100644 --- a/src/app/account-mapper/account-mapper/account-mapper.component.html +++ b/src/app/account-mapper/account-mapper/account-mapper.component.html @@ -4,7 +4,7 @@ -

Filters

+

{{"labels.inputs.Filters" | translate}}

@@ -12,23 +12,23 @@

Filters

- Financial Institution + {{"labels.inputs.Financial Institution" | translate}} - Functional ID + {{"labels.inputs.Functional ID" | translate}} - Financial Address + {{"labels.inputs.Financial Address" | translate}}
@@ -43,41 +43,41 @@

Filters

- - + + - - + + - - + + - + - + + + + + +
Government Entity {{ - item.registeringInstitutionId }} - {{"labels.inputs.Government Entity" | translate}} {{item.registeringInstitutionId }} Financial Institution - {{ item.bankingInstitutionCode }} - {{"labels.inputs.Financial Institution" | translate}} {{ item.bankingInstitutionCode }} Functional ID - {{ item.payeeIdentity }} - {{"labels.inputs.Functional ID" | translate}} {{ item.payeeIdentity }} Financial Address {{"labels.inputs.Financial Address" | translate}} {{"labels.inputs.Payment Modality" | translate}} {{paymentModalityDescription(item.paymentModality)}}
- + + diff --git a/src/app/account-mapper/account-mapper/account-mapper.component.ts b/src/app/account-mapper/account-mapper/account-mapper.component.ts index b234803c..37ce742b 100644 --- a/src/app/account-mapper/account-mapper/account-mapper.component.ts +++ b/src/app/account-mapper/account-mapper/account-mapper.component.ts @@ -1,7 +1,6 @@ -import { Component, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { AccountMapperService } from '../services/account-mapper.service'; import { UntypedFormControl } from '@angular/forms'; -import { TransactionsDataSource } from 'app/payment-hub/transactions/dataSource/transactions.datasource'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; @@ -13,7 +12,7 @@ import { Dates } from 'app/core/utils/dates'; templateUrl: './account-mapper.component.html', styleUrls: ['./account-mapper.component.scss'] }) -export class AccountMapperComponent { +export class AccountMapperComponent implements OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -28,14 +27,13 @@ export class AccountMapperComponent { financialAddress = new UntypedFormControl(); /** Columns to be displayed in transactions table. */ - displayedColumns: string[] = ['governmentEntity', 'financialInstitution', 'functionalId', 'financialAddress']; + displayedColumns: string[] = ['governmentEntity', 'financialInstitution', 'functionalId', 'financialAddress', 'paymentModality']; /** Data source for transactions table. */ dataSource = new MatTableDataSource(); - totalRows: number = 0; - currentPage: number = 0; - - pageSize = 50; + totalRows = 0; + currentPage = 0; + pageSize = 10; isLoading = false; accountsData: AccountData; @@ -52,6 +50,8 @@ export class AccountMapperComponent { this.accountMapperService.getAccounts(this.currentPage, this.pageSize, 'requestFile', 'asc') .subscribe((accounts: AccountData) => { this.dataSource = new MatTableDataSource(accounts.content); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; this.totalRows = accounts.totalElements; this.isLoading = false; }, (error: any) => { @@ -67,11 +67,26 @@ export class AccountMapperComponent { } pageChanged(event: PageEvent) { - this.pageSize = event.pageSize; this.currentPage = event.pageIndex; + this.pageSize = event.pageSize; this.getAccounts(); } + paymentModalityDescription(value: string): string { + if (value === '0' || value === '00') { + return '(00) Bank Account'; + } else if (value === '1' || value === '01') { + return '(01) Mobile Money'; + } else if (value === '2' || value === '02') { + return '(02) Voucher'; + } else if (value === '3' || value === '03') { + return '(03) Digital Wallet'; + } else if (value === '4' || value === '04') { + return '(04) Proxy'; + } + return value; + } + searchAccounts(): void { } diff --git a/src/app/account-mapper/models/account-mapper.model.ts b/src/app/account-mapper/models/account-mapper.model.ts index c0af7976..44ca5881 100644 --- a/src/app/account-mapper/models/account-mapper.model.ts +++ b/src/app/account-mapper/models/account-mapper.model.ts @@ -1,4 +1,4 @@ -import { Pageable, Sort } from "app/shared/models/data.model"; +import { Pageable, Sort } from 'app/shared/models/data.model'; export interface AccountData { content: Account[]; diff --git a/src/app/account-mapper/services/account-mapper.service.ts b/src/app/account-mapper/services/account-mapper.service.ts index 6be22a1f..6cd1d3dc 100644 --- a/src/app/account-mapper/services/account-mapper.service.ts +++ b/src/app/account-mapper/services/account-mapper.service.ts @@ -16,7 +16,7 @@ export class AccountMapperService { * @returns {Observable} Users data */ getAccounts(page: number, size: number, orderBy: string, sortOrder: string): Observable { - let httpParams = new HttpParams() + const httpParams = new HttpParams() .set('page', page) .set('size', size) .set('sortOrder', sortOrder) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f831ac29..843f2a75 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -30,7 +30,7 @@ import { PaymentHubModule } from './payment-hub/paymenthub.module'; /** Main Routing Module */ import { AppRoutingModule } from './app-routing.module'; -import { DatePipe } from '@angular/common'; +import { DatePipe, LocationStrategy } from '@angular/common'; import { VouchersModule } from './vouchers/vouchers.module'; import { AccountMapperModule } from './account-mapper/account-mapper.module'; import { KeycloakAngularModule } from 'keycloak-angular'; @@ -48,8 +48,10 @@ import { KeycloakAngularModule } from 'keycloak-angular'; TranslateModule.forRoot({ loader: { provide: TranslateLoader, - useFactory: httpTranslateLoader, - deps: [HttpClient] + useFactory: (http: HttpClient, locationStrategy: LocationStrategy) => { + return new TranslateHttpLoader(http, `${ window.location.protocol }//${ window.location.host }${locationStrategy.getBaseHref()}assets/translations/`, '.json'); + }, + deps: [HttpClient, LocationStrategy] } }), KeycloakAngularModule, @@ -75,4 +77,4 @@ export class AppModule { } export function httpTranslateLoader(http: HttpClient) { return new TranslateHttpLoader(http, `/assets/translations/`, '.json'); -} \ No newline at end of file +} diff --git a/src/app/core/authentication/authentication.interceptor.ts b/src/app/core/authentication/authentication.interceptor.ts index 253fb88e..ebc3d798 100644 --- a/src/app/core/authentication/authentication.interceptor.ts +++ b/src/app/core/authentication/authentication.interceptor.ts @@ -3,21 +3,20 @@ import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; /** rxjs Imports */ -import { Observable, Subject, BehaviorSubject, throwError } from 'rxjs'; +import { Observable, Subject, BehaviorSubject } from 'rxjs'; import { environment } from '../../../environments/environment'; import { SettingsService } from 'app/settings/settings.service'; +import * as uuid from 'uuid'; + /** Http request options headers. */ const httpOptions = { - headers: { - } + headers: { } }; /** Authorization header. */ const authorizationHeader = 'Authorization'; -/** Two factor access token header. */ -const twoFactorAccessTokenHeader = 'Fineract-Platform-TFA-Token'; /** * Http Request interceptor to set the request headers. @@ -38,14 +37,14 @@ export class AuthenticationInterceptor implements HttpInterceptor { const url: string = request.url; if ((url.indexOf('/batches') > 0) || (url.indexOf('/transactions') > 0)) { httpOptions.headers['Platform-TenantId'] = this.settingsService.tenantIdentifier; - console.log(url); if (!url.endsWith('/batches')) { - httpOptions.headers['X-Correlation-ID'] = 'sdasdasasdasu'; + httpOptions.headers['X-Correlation-ID'] = uuid.v4(); } - delete httpOptions.headers['X-Registering-Institution-ID']; + delete httpOptions.headers['x-registering-institution-id']; + delete httpOptions.headers['X-CallbackURL']; } if ((url.indexOf('/vouchers') > 0) || (url.indexOf('/benefici') > 0)) { - httpOptions.headers['X-Registering-Institution-ID'] = environment.backend.registeringInstituionId; + httpOptions.headers['x-registering-institution-id'] = environment.backend.registeringInstituionId; delete httpOptions.headers['X-Correlation-ID']; delete httpOptions.headers['Platform-TenantId']; } diff --git a/src/app/core/authentication/authentication.service.ts b/src/app/core/authentication/authentication.service.ts index 96f2e584..a306ee49 100644 --- a/src/app/core/authentication/authentication.service.ts +++ b/src/app/core/authentication/authentication.service.ts @@ -119,7 +119,7 @@ export class AuthenticationService { this.username = loginContext.username; httpParams = httpParams.set('username', loginContext.username); httpParams = httpParams.set('password', loginContext.password); - //httpParams = httpParams.set('tenantIdentifier', loginContext.tenant); + // httpParams = httpParams.set('tenantIdentifier', loginContext.tenant); if (environment.oauth.enabled) { if (this.isOauthKeyCloak()) { return this.oauthKeycloakService.token(loginContext).pipe( @@ -133,7 +133,7 @@ export class AuthenticationService { } else { httpParams = httpParams.set('grant_type', 'password'); - if (environment.oauth.basicAuth === "true") { + if (environment.oauth.basicAuth === 'true') { this.authorizationToken = `Basic ${environment.oauth.basicAuthToken}`; } return this.http.disableApiPrefix().post(`${environment.oauth.serverUrl}/oauth/token`, {}, { params: httpParams }) @@ -162,7 +162,7 @@ export class AuthenticationService { * Sets the oauth2 token refresh time. * @param {OAuth2Token} tokenResponse OAuth2 Token details. */ - private getUserDetails(loginContext: LoginContext,tokenResponse: OAuth2Token) { + private getUserDetails(loginContext: LoginContext, tokenResponse: OAuth2Token) { if (this.isOauthKeyCloak()) { this.oauthKeycloakService.introspect(tokenResponse).subscribe((userDetails: Introspect) => { // console.log(userDetails); @@ -171,7 +171,7 @@ export class AuthenticationService { }); } else { - console.log("Not Implemented " + environment.oauth.type); + console.log('Not Implemented ' + environment.oauth.type); } } diff --git a/src/app/core/authentication/keycloak/oauth-keycloak.service.ts b/src/app/core/authentication/keycloak/oauth-keycloak.service.ts index ea011dfe..92af2717 100644 --- a/src/app/core/authentication/keycloak/oauth-keycloak.service.ts +++ b/src/app/core/authentication/keycloak/oauth-keycloak.service.ts @@ -15,12 +15,12 @@ export class OauthKeycloakService { token(loginContext: LoginContext): Observable { const httpOptions = { - headers: new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded', - }) + headers: new HttpHeaders({ + 'Content-Type': 'application/x-www-form-urlencoded' + }) }; - - const payload = new URLSearchParams() + + const payload = new URLSearchParams(); payload.set('grant_type', 'password'); payload.set('client_id', environment.oauth.clientId); if (environment.oauth.clientSecret !== '') { @@ -28,7 +28,7 @@ export class OauthKeycloakService { } payload.set('username', loginContext.username); payload.set('password', loginContext.password); - + const url: string = this.url() + '/token'; return this.http.post(url, payload.toString(), httpOptions); } @@ -36,19 +36,19 @@ export class OauthKeycloakService { refreshToken(token: OAuth2Token): Observable { const httpOptions = { - headers: new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded', - }) + headers: new HttpHeaders({ + 'Content-Type': 'application/x-www-form-urlencoded' + }) }; - - const payload = new URLSearchParams() + + const payload = new URLSearchParams(); payload.set('grant_type', 'refresh_token'); payload.set('client_id', environment.oauth.clientId); if (environment.oauth.clientSecret !== '') { payload.set('client_secret', environment.oauth.clientSecret); } payload.set('refresh_token', token.refresh_token); - + const url: string = this.url() + '/token'; return this.http.post(url, payload.toString(), httpOptions); } @@ -56,18 +56,18 @@ export class OauthKeycloakService { introspect(token: OAuth2Token): Observable { const httpOptions = { - headers: new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded', - }) + headers: new HttpHeaders({ + 'Content-Type': 'application/x-www-form-urlencoded' + }) }; - - const payload = new URLSearchParams() + + const payload = new URLSearchParams(); payload.set('client_id', environment.oauth.clientId); if (environment.oauth.clientSecret !== '') { payload.set('client_secret', environment.oauth.clientSecret); } payload.set('token', token.access_token); - + const url: string = this.url() + '/token/introspect'; return this.http.post(url, payload.toString(), httpOptions); } @@ -75,18 +75,18 @@ export class OauthKeycloakService { logout(token: OAuth2Token): Observable { const httpOptions = { - headers: new HttpHeaders({ - 'Content-Type': 'application/x-www-form-urlencoded', - }) + headers: new HttpHeaders({ + 'Content-Type': 'application/x-www-form-urlencoded' + }) }; - - const payload = new URLSearchParams() + + const payload = new URLSearchParams(); payload.set('client_id', environment.oauth.clientId); if (environment.oauth.clientSecret !== '') { payload.set('client_secret', environment.oauth.clientSecret); } payload.set('refresh_token', token.refresh_token); - + const url: string = this.url() + '/logout'; return this.http.post(url, payload.toString(), httpOptions); } diff --git a/src/app/core/authentication/o-auth2-token.model.ts b/src/app/core/authentication/o-auth2-token.model.ts index 79372674..75e267b4 100644 --- a/src/app/core/authentication/o-auth2-token.model.ts +++ b/src/app/core/authentication/o-auth2-token.model.ts @@ -40,7 +40,7 @@ export interface RealmAccess { } export interface ResourceAccess { - "realm-management": RealmAccess; + 'realm-management': RealmAccess; broker: RealmAccess; account: RealmAccess; } diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index 8fb74bfe..bbcac44c 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -32,7 +32,6 @@ import { SharedModule } from '../shared/shared.module'; import { ShellComponent } from './shell/shell.component'; import { SidenavComponent } from './shell/sidenav/sidenav.component'; import { ToolbarComponent } from './shell/toolbar/toolbar.component'; -import { BreadcrumbComponent } from './shell/breadcrumb/breadcrumb.component'; import { ContentComponent } from './shell/content/content.component'; /** @@ -51,7 +50,6 @@ import { ContentComponent } from './shell/content/content.component'; ShellComponent, SidenavComponent, ToolbarComponent, - BreadcrumbComponent, ContentComponent ], exports: [ diff --git a/src/app/core/http/http.service.ts b/src/app/core/http/http.service.ts index 92f75134..72dbf5b4 100644 --- a/src/app/core/http/http.service.ts +++ b/src/app/core/http/http.service.ts @@ -8,7 +8,6 @@ import { Observable } from 'rxjs'; /** Custom Interceptors */ import { ErrorHandlerInterceptor } from './error-handler.interceptor'; import { CacheInterceptor } from './cache.interceptor'; -// import { ApiPrefixInterceptor } from './api-prefix.interceptor'; /** * HttpClient is declared in a re-exported module, so we have to extend the original module to make it work properly. diff --git a/src/app/core/i18n/i18n.service.ts b/src/app/core/i18n/i18n.service.ts index 76273506..ec112d3c 100644 --- a/src/app/core/i18n/i18n.service.ts +++ b/src/app/core/i18n/i18n.service.ts @@ -3,29 +3,15 @@ import { Injectable } from '@angular/core'; /** Translation Imports */ import { TranslateService } from '@ngx-translate/core'; - -/** Custom Services */ -import { Logger } from '../logger/logger.service'; - -/** Initialize Logger */ -const log = new Logger('I18nService'); - -/** - * Pass-through function to mark a string for translation extraction. - * Running `npm translations:extract` will include the given string by using this. - * @param {string} s The string to extract for translation. - * @return {string} The translated string. - */ -export function extract(s: string) { - return I18nService.translate(s); -} +import { Observable } from 'rxjs'; @Injectable() export class I18nService { constructor(private translateService: TranslateService) { } - public static translate(key: string): string { - return key; + public translate(key: string): Observable { + return this.translateService.get(key); } + } diff --git a/src/app/core/route/route-reusable-strategy.ts b/src/app/core/route/route-reusable-strategy.ts index 6580d26b..de871c22 100644 --- a/src/app/core/route/route-reusable-strategy.ts +++ b/src/app/core/route/route-reusable-strategy.ts @@ -1,6 +1,6 @@ /** Angular Imports */ import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router'; -import { Injectable } from "@angular/core"; +import { Injectable } from '@angular/core'; /** * A route strategy allowing for explicit route reuse. diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.html b/src/app/core/shell/breadcrumb/breadcrumb.component.html deleted file mode 100644 index 48bb085d..00000000 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.html +++ /dev/null @@ -1,14 +0,0 @@ - diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.scss b/src/app/core/shell/breadcrumb/breadcrumb.component.scss deleted file mode 100644 index e38a7db3..00000000 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.scss +++ /dev/null @@ -1,47 +0,0 @@ -.breadcrumb-wrapper { - margin: 0 auto; - max-width: 74rem; - width: 90%; - word-wrap: break-word; - - .breadcrumb { - list-style: none; - padding: 0; - margin: 1.5rem 0; - line-height: 40px; - - .breadcrumb-title { - font-size: 1.25rem; - font-weight: 400; - } - - .separator::before { - content: ""; - border: 1.5px solid #000; - margin: 0 0.6rem; - font-size: 1.25rem; - font-weight: 400; - } - - .breadcrumb-label { - display: inline; - font-size: 1rem; - - .breadcrumb-link { - a { - text-decoration: none; - color: #0275d8; - - &:hover { - text-decoration: underline; - } - } - - &::after { - content: "/"; - margin: 0 0.4rem; - } - } - } - } -} diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.spec.ts b/src/app/core/shell/breadcrumb/breadcrumb.component.spec.ts deleted file mode 100644 index 1fddbf83..00000000 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { BreadcrumbComponent } from './breadcrumb.component'; - -describe('BreadcrumbComponent', () => { - let component: BreadcrumbComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ BreadcrumbComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(BreadcrumbComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/core/shell/breadcrumb/breadcrumb.component.ts b/src/app/core/shell/breadcrumb/breadcrumb.component.ts deleted file mode 100644 index 2665c649..00000000 --- a/src/app/core/shell/breadcrumb/breadcrumb.component.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** Angular Imports */ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; - -/** rxjs Imports */ -import { filter } from 'rxjs/operators'; - -/** Custom Model */ -import { Breadcrumb } from './breadcrumb.model'; - -/** - * Route data property to generate breadcrumb using a static string. - * - * Example- breadcrumb: 'Home' - */ -const routeDataBreadcrumb = 'breadcrumb'; -/** - * Route data property to generate breadcrumb using given route parameter name. - * - * Example- routeParamBreadcrumb: 'id' - */ -const routeParamBreadcrumb = 'routeParamBreadcrumb'; -/** - * Route data property to generate breadcrumb using resolved data property name. - * - * Use array to specify name for a nested object property. - * - * Example- routeResolveBreadcrumb: ['user', 'username'] - */ -const routeResolveBreadcrumb = 'routeResolveBreadcrumb'; -/** - * Route data property to specify whether generated breadcrumb should have a link. - * - * True by default. Specify false if a link is not required. - * - * Example- addBreadcrumbLink: false - */ -const routeAddBreadcrumbLink = 'addBreadcrumbLink'; - -/** - * Generate breadcrumbs dynamically via route configuration. - */ -@Component({ - selector: 'mifosx-breadcrumb', - templateUrl: './breadcrumb.component.html', - styleUrls: ['./breadcrumb.component.scss'] -}) -export class BreadcrumbComponent implements OnInit { - - /** Array of breadcrumbs. */ - breadcrumbs: Breadcrumb[]; - - /** - * Generates the breadcrumbs. - * @param {ActivatedRoute} activatedRoute Activated Route. - * @param {Router} router Router for navigation. - */ - constructor(private activatedRoute: ActivatedRoute, - private router: Router) { - this.generateBreadcrumbs(); - } - - ngOnInit() { - } - - /** - * Generates the array of breadcrumbs for the visited route. - */ - generateBreadcrumbs() { - const onNavigationEnd = this.router.events.pipe(filter(event => event instanceof NavigationEnd)); - - onNavigationEnd.subscribe(() => { - this.breadcrumbs = []; - let currentRoute = this.activatedRoute.root; - let currentUrl = ''; - - while (currentRoute.children.length > 0) { - const childrenRoutes = currentRoute.children; - let breadcrumbLabel: any; - let url: any; - - childrenRoutes.forEach(route => { - currentRoute = route; - breadcrumbLabel = false; - - if (route.outlet !== 'primary') { - return; - } - - const routeURL = route.snapshot.url.map(segment => segment.path).join('/'); - currentUrl += `/${routeURL}`; - - if (currentUrl === '/') { - breadcrumbLabel = 'Home'; - } - - const hasData = (route.routeConfig && route.routeConfig.data); - - if (hasData) { - if (route.snapshot.data.hasOwnProperty(routeResolveBreadcrumb) && route.snapshot.data[routeResolveBreadcrumb]) { - breadcrumbLabel = route.snapshot.data; - route.snapshot.data[routeResolveBreadcrumb].forEach((property: any) => { - breadcrumbLabel = breadcrumbLabel[property]; - }); - } else if (route.snapshot.data.hasOwnProperty(routeParamBreadcrumb) && route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb])) { - breadcrumbLabel = route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb]); - } else if (route.snapshot.data.hasOwnProperty(routeDataBreadcrumb)) { - breadcrumbLabel = route.snapshot.data[routeDataBreadcrumb]; - } - - if (route.snapshot.data.hasOwnProperty(routeAddBreadcrumbLink)) { - url = route.snapshot.data[routeAddBreadcrumbLink]; - } else { - url = currentUrl; - } - } - - const breadcrumb: Breadcrumb = { - label: breadcrumbLabel, - url: url - }; - - if (breadcrumbLabel) { - this.breadcrumbs.push(breadcrumb); - } - }); - } - }); - } - -} diff --git a/src/app/core/shell/breadcrumb/breadcrumb.model.ts b/src/app/core/shell/breadcrumb/breadcrumb.model.ts deleted file mode 100644 index 2bbc0a49..00000000 --- a/src/app/core/shell/breadcrumb/breadcrumb.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Breadcrumb model. - */ -export interface Breadcrumb { - label: string; - url: string; -} diff --git a/src/app/core/shell/content/content.component.html b/src/app/core/shell/content/content.component.html index 504f29c0..fdb074cb 100644 --- a/src/app/core/shell/content/content.component.html +++ b/src/app/core/shell/content/content.component.html @@ -1,10 +1,14 @@
- + + + {{ "labels.breadcrumbs." + breadcrumb | translate }} + + chevron_right
- + \ No newline at end of file diff --git a/src/app/core/shell/sidenav/sidenav.component.scss b/src/app/core/shell/sidenav/sidenav.component.scss index 6a62a74f..3545deae 100644 --- a/src/app/core/shell/sidenav/sidenav.component.scss +++ b/src/app/core/shell/sidenav/sidenav.component.scss @@ -43,6 +43,7 @@ width: 100%; margin: auto; color: $white; + margin-bottom: 60px; .app-logo { width: auto; @@ -53,7 +54,7 @@ .app-logo-text { width: auto; height: auto; - font-size: 2rem; + font-size: 1.3rem; font-weight: normal; } } diff --git a/src/app/core/shell/sidenav/sidenav.component.ts b/src/app/core/shell/sidenav/sidenav.component.ts index 9bd92105..d45f9b94 100644 --- a/src/app/core/shell/sidenav/sidenav.component.ts +++ b/src/app/core/shell/sidenav/sidenav.component.ts @@ -17,7 +17,7 @@ export class SidenavComponent implements OnInit { /** True if sidenav is in collapsed state. */ @Input() sidenavCollapsed: boolean; - @Output() sideNavControl: EventEmitter = new EventEmitter + @Output() sideNavControl: EventEmitter = new EventEmitter; /** Username of authenticated user. */ username: string; diff --git a/src/app/core/shell/toolbar/toolbar.component.html b/src/app/core/shell/toolbar/toolbar.component.html index 214c84f0..406334ca 100644 --- a/src/app/core/shell/toolbar/toolbar.component.html +++ b/src/app/core/shell/toolbar/toolbar.component.html @@ -22,12 +22,12 @@ - Settings + {{'labels.menus.Settings' | translate}} \ No newline at end of file diff --git a/src/app/core/shell/toolbar/toolbar.component.ts b/src/app/core/shell/toolbar/toolbar.component.ts index 6402018b..f9d5c603 100644 --- a/src/app/core/shell/toolbar/toolbar.component.ts +++ b/src/app/core/shell/toolbar/toolbar.component.ts @@ -34,7 +34,7 @@ import { AuthenticationService } from '../../authentication/authentication.servi export class ToolbarComponent implements OnInit { credentials: any; - + /** Subscription to breakpoint observer for handset. */ isHandset$: Observable = this.breakpointObserver.observe(Breakpoints.Handset) .pipe( diff --git a/src/app/directives/directives.module.ts b/src/app/directives/directives.module.ts index a17b4bb4..26151c87 100644 --- a/src/app/directives/directives.module.ts +++ b/src/app/directives/directives.module.ts @@ -17,6 +17,6 @@ import { FileDragNDropDirective } from './file-drag-ndrop/file-drag-ndrop.direct CommonModule ], declarations: [HasPermissionDirective, HasRoleDirective, FileDragNDropDirective], - exports: [HasPermissionDirective, HasRoleDirective] + exports: [HasPermissionDirective, HasRoleDirective, FileDragNDropDirective] }) export class DirectivesModule { } diff --git a/src/app/directives/file-drag-ndrop/file-drag-ndrop.directive.ts b/src/app/directives/file-drag-ndrop/file-drag-ndrop.directive.ts index 5d932ae7..6253d033 100644 --- a/src/app/directives/file-drag-ndrop/file-drag-ndrop.directive.ts +++ b/src/app/directives/file-drag-ndrop/file-drag-ndrop.directive.ts @@ -3,44 +3,32 @@ import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@ang @Directive({ selector: '[mifosxFileDragNDrop]' }) -@Directive({ - selector: '[fileDragDrop]' -}) - export class FileDragNDropDirective { - @Output() private filesChangeEmiter : EventEmitter = new EventEmitter(); - - @HostBinding('style.background') private background = '#eee'; - @HostBinding('style.border') private borderStyle = '2px dashed'; - @HostBinding('style.border-color') private borderColor = '#696D7D'; - @HostBinding('style.border-radius') private borderRadius = '5px'; - - constructor() { } + @HostBinding('class.fileover') fileOver: boolean; + @Output() fileDropped = new EventEmitter(); - @HostListener('dragover', ['$event']) public onDragOver(evt: any){ + // Dragover listener + @HostListener('dragover', ['$event']) onDragOver(evt: any) { evt.preventDefault(); evt.stopPropagation(); - this.background = 'lightgray'; - this.borderColor = 'cadetblue'; - this.borderStyle = '3px solid'; + this.fileOver = true; } - @HostListener('dragleave', ['$event']) public onDragLeave(evt: any){ + // Dragleave listener + @HostListener('dragleave', ['$event']) public onDragLeave(evt: any) { evt.preventDefault(); evt.stopPropagation(); - this.background = '#eee'; - this.borderColor = '#696D7D'; - this.borderStyle = '2px dashed'; + this.fileOver = false; } - @HostListener('drop', ['$event']) public onDrop(evt: any){ + // Drop listener + @HostListener('drop', ['$event']) public ondrop(evt: any) { evt.preventDefault(); evt.stopPropagation(); - this.background = '#eee'; - this.borderColor = '#696D7D'; - this.borderStyle = '2px dashed'; - let files = evt.dataTransfer.files; - let valid_files : Array = files; - this.filesChangeEmiter.emit(valid_files); + this.fileOver = false; + const files = evt.dataTransfer.files; + if (files.length > 0) { + this.fileDropped.emit(files); + } } } diff --git a/src/app/directives/has-role/has-role.directive.ts b/src/app/directives/has-role/has-role.directive.ts index 7047fe61..cc88c155 100644 --- a/src/app/directives/has-role/has-role.directive.ts +++ b/src/app/directives/has-role/has-role.directive.ts @@ -7,8 +7,8 @@ import { environment } from 'environments/environment'; }) export class HasRoleDirective { - public static ADMIN_ROLE = "admin"; - public static OPERATOR_ROLE = "operator"; + public static ADMIN_ROLE = 'admin'; + public static OPERATOR_ROLE = 'operator'; /** User Roles */ private userRoles: any[]; @@ -22,7 +22,7 @@ export class HasRoleDirective { constructor(private templateRef: TemplateRef, private viewContainer: ViewContainerRef, private authenticationService: AuthenticationService) { - let userDetails = this.authenticationService.userDetails; + const userDetails = this.authenticationService.userDetails; if (environment.auth.enabled === 'false') { this.userRoles = [HasRoleDirective.ADMIN_ROLE]; } else { diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 1f50a349..33a39f3d 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -16,26 +16,26 @@ export class HomeComponent { sections: Section[]; - constructor() { + constructor() { this.sections = [ { - label: 'Payment Hub', + label: 'Payment Hub', routeTo: ['paymenthub'], roleName: 'operations', icon: 'money-bill-alt', active: false - }, + }, { - label: 'Vouchers', - routeTo: ['vouchers'], - roleName: 'vouchers', - icon: 'ticket', + label: 'Vouchers', + routeTo: ['vouchers'], + roleName: 'vouchers', + icon: 'ticket', active: false - }, + }, { - label: 'Account Management', - routeTo: ['account-mapper'], - roleName: 'account-mapper', + label: 'Account Management', + routeTo: ['account-mapper'], + roleName: 'account-mapper', icon: 'users', active: false } diff --git a/src/app/home/home.module.ts b/src/app/home/home.module.ts index 6a13d444..1888cfb7 100644 --- a/src/app/home/home.module.ts +++ b/src/app/home/home.module.ts @@ -20,7 +20,7 @@ import { DirectivesModule } from 'app/directives/directives.module'; imports: [ SharedModule, HomeRoutingModule, - TranslateModule.forRoot(), + TranslateModule, DirectivesModule ], declarations: [ diff --git a/src/app/login/login-routing.module.ts b/src/app/login/login-routing.module.ts index 1b9246ff..407f3571 100644 --- a/src/app/login/login-routing.module.ts +++ b/src/app/login/login-routing.module.ts @@ -2,9 +2,6 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -/** Transalation Imports */ -import { extract } from '../core/i18n/i18n.service'; - /** Custom Components */ import { LoginComponent } from './login.component'; @@ -13,7 +10,7 @@ const routes: Routes = [ { path: 'login', component: LoginComponent, - data: { title: extract('Login') } + data: { title: 'Login' } } ]; diff --git a/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.html b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.html new file mode 100644 index 00000000..fd27d053 --- /dev/null +++ b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.html @@ -0,0 +1,94 @@ +
+ +
+ +
+
+ +
+ + + +
+ +
+ +
+ + {{"labels.inputs.Institution Id" | translate}} + + + + {{"labels.inputs.Program Id" | translate}} + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
# {{(idx + 1)}} {{"labels.inputs.Request" | translate}} {{ batch.requestId }} {{"labels.inputs.Credit Party" | translate}} {{ batch.creditParty[0].key }} {{ batch.creditParty[0].value }} {{"labels.inputs.Debit Party" | translate}} {{ batch.debitParty[0].key }} {{ batch.debitParty[0].value }} {{"labels.inputs.SubType" | translate}} {{"labels.inputs.Payment Mode" | translate}} {{ batch.paymentMode }} {{"labels.inputs.Currency" | translate}} {{ batch.currency }} {{"labels.inputs.Amount" | translate}} {{ batch.amount | number }} {{"labels.inputs.Description" | translate}} {{ batch.descriptionText }}
+ + + +
+ + +
+
+
\ No newline at end of file diff --git a/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.scss b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.spec.ts b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.spec.ts new file mode 100644 index 00000000..d5a03eab --- /dev/null +++ b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BatchesBulkImportComponent } from './batches-bulk-import.component'; + +describe('BatchesBulkImportComponent', () => { + let component: BatchesBulkImportComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [BatchesBulkImportComponent] + }); + fixture = TestBed.createComponent(BatchesBulkImportComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.ts b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.ts new file mode 100644 index 00000000..8281ab86 --- /dev/null +++ b/src/app/payment-hub/batches-bulk-import/batches-bulk-import.component.ts @@ -0,0 +1,123 @@ +import { Component, OnInit } from '@angular/core'; +import { MatTableDataSource } from '@angular/material/table'; +import { AlertService } from 'app/core/alert/alert.service'; +import { NgxCsvParser } from 'ngx-csv-parser'; + +import * as XLSX from 'xlsx'; +import { BatchesService } from '../batches/batches.service'; +import { SettingsService } from 'app/settings/settings.service'; +import { BatchInstruction } from '../batches/model/batch.model'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { environment } from 'environments/environment'; + +import { sha3_256 } from 'js-sha3'; +import * as Forge from 'node-forge'; +import * as uuid from 'uuid'; + +@Component({ + selector: 'mifosx-batches-bulk-import', + templateUrl: './batches-bulk-import.component.html', + styleUrls: ['./batches-bulk-import.component.scss'] +}) +export class BatchesBulkImportComponent implements OnInit { + createBatchForm: UntypedFormGroup; + + files: File[] = []; + batchInstructions: BatchInstruction[] = []; + + displayedColumns: string[] = ['rowId', 'requestId', 'CreditParty', 'DebitParty', 'subType', 'paymentMode', 'currency', 'amount', 'description']; + dataSource = new MatTableDataSource(); + + totalRows = 0; + pageSize = 10; + isLoading = false; + + constructor(private alertService: AlertService, + private csvParse: NgxCsvParser, + private formBuilder: UntypedFormBuilder, + private batchesService: BatchesService, + private settingsService: SettingsService) { } + + ngOnInit(): void { + this.createBatchForm = this.formBuilder.group({ + 'institutionId': [environment.backend.registeringInstituionId, Validators.required], + 'programId': ['', Validators.required] + }); + } + + onFileChange(file: File): void { + this.processFiles(file); + } + + deleteFile(f: any) { + this.files = this.files.filter((w: any) => w.name !== f.name); + this.alertService.alert({ type: 'Voucher File Upload', message: 'Successfully delete!' }); + } + + isFileAdded(): boolean { + return (this.files.length > 0); + } + + processFiles(file: File): void { + this.isLoading = true; + this.csvParse.parse(file, { header: true, delimiter: ',' }) + .pipe().subscribe((results: Array) => { + this.batchInstructions = []; + results.forEach((item: any) => { + this.batchInstructions.push({ + requestId: item['Request'], + creditParty: [{key: item['CreditParty Key'], value: item['CreditParty Value']}], + debitParty: [{key: item['DebitParty Key'], value: item['DebitParty Value']}], + paymentMode: item['Payment Mode'], + currency: item['Currency'], + amount: item['Amount'], + descriptionText: item['Description'] || null + }); + }); + // subType: item['SubType'] || null, + this.files.push(file); + this.totalRows = this.batchInstructions.length; + + this.dataSource = new MatTableDataSource(this.batchInstructions); + this.isLoading = false; + }); + this.alertService.alert({ type: 'Voucher File Upload', message: 'Successfully parsed!' }); + + } + + downloadTemplate(): void { + const fileName = `Batch_Template.xls`; + const data: any[] = []; + const columns: string[] = ['Request', 'CreditParty Key', 'CreditParty Value', 'DebitParty Key', 'DebitParty Value', 'SubType', 'Payment Mode', 'Currency', 'Amount', 'Description']; + const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, {header: columns}); + const wb: XLSX.WorkBook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, 'batches'); + XLSX.writeFile(wb, fileName); + } + + sendData(): void { + const institutionId: string = this.createBatchForm.value.institutionId; + const programId: string = this.createBatchForm.value.programId; + const correlationID: string = uuid.v4(); + + const payload = `${correlationID}:${this.settingsService.tenantIdentifier}:${JSON.stringify(this.batchInstructions)}`; + const hashSHA3_256: any = sha3_256(payload); + console.log(environment.backend.signatureBatchKey.replace(/\\n/g, '\n')); + const rsa = Forge.pki.publicKeyFromPem(environment.backend.signatureBatchKey.replace(/\\n/g, '\n')); + const signature: string = window.btoa(rsa.encrypt(hashSHA3_256)); + console.log(signature); + + this.batchesService.createBatch(correlationID, institutionId, programId, signature, payload).subscribe((response: any) => { + console.log(response); + }); + } + + clearData(): void { + this.batchInstructions = []; + this.dataSource = new MatTableDataSource(this.batchInstructions); + this.totalRows = 0; + this.files = []; + this.createBatchForm.patchValue({'programId': ''}); + this.createBatchForm.markAsUntouched(); + } +} diff --git a/src/app/payment-hub/batches/batches.component.html b/src/app/payment-hub/batches/batches.component.html index 60664c05..0cec12ab 100644 --- a/src/app/payment-hub/batches/batches.component.html +++ b/src/app/payment-hub/batches/batches.component.html @@ -4,22 +4,23 @@ -

Filters

+

{{"labels.inputs.Filters" | translate}}

+
- From Date + {{"labels.inputs.From Date" | translate}} - To Date + {{"labels.inputs.To Date" | translate}} @@ -28,25 +29,25 @@

Filters

- Source Ministry + {{"labels.inputs.Source Ministry" | translate}} - Batch Reference Number + {{"labels.inputs.Batch Reference Number" | translate}} - Bulk Amount - + {{"labels.inputs.Bulk Amount" | translate}} +
@@ -58,38 +59,38 @@

Filters

- + - + - + - + - + - +
Batch Reference Number {{"labels.inputs.Batch Reference Number" | translate}} Start Time {{"labels.inputs.Start Time" | translate}} {{ convertTimestampToUTCDate(item.startedAt) | dateFormat }} Completed Time {{"labels.inputs.Completed Time" | translate}} {{ convertTimestampToUTCDate(item.completedAt) | dateFormat }} Source Ministry {{"labels.inputs.Source Ministry" | translate}} {{item.payerFsp}} Amount {{"labels.inputs.Amount" | translate}} {{ item.totalAmount | number }} Status {{"labels.inputs.Status" | translate}} diff --git a/src/app/payment-hub/batches/batches.component.ts b/src/app/payment-hub/batches/batches.component.ts index cc873d5b..e113ae5f 100644 --- a/src/app/payment-hub/batches/batches.component.ts +++ b/src/app/payment-hub/batches/batches.component.ts @@ -39,8 +39,8 @@ export class BatchesComponent implements OnInit { dataSource = new MatTableDataSource(); batchesData: Batch; - totalRows: number = 0; - currentPage: number = 0; + totalRows = 0; + currentPage = 0; pageSize = 50; isLoading = false; @@ -94,8 +94,6 @@ export class BatchesComponent implements OnInit { this.router.navigate(['..', 'sub-batches', batchId], { relativeTo: this.route }); } - searchBatches(): void { - - } + searchBatches(): void { } } diff --git a/src/app/payment-hub/batches/batches.service.ts b/src/app/payment-hub/batches/batches.service.ts index cdb91410..e45223a1 100644 --- a/src/app/payment-hub/batches/batches.service.ts +++ b/src/app/payment-hub/batches/batches.service.ts @@ -1,22 +1,26 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { SettingsService } from 'app/settings/settings.service'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; + @Injectable({ providedIn: 'root' }) export class BatchesService { apiPrefix: string = environment.backend.operations; + bulkConnectorOps: string = environment.backend.bulkConnectorOps; - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, + private settingsService: SettingsService) { } /** * @returns {Observable} Users data */ getBatches(page: number, size: number, orderBy: string, sortOrder: string): Observable { - let httpParams = new HttpParams() + const httpParams = new HttpParams() .set('page', page) .set('size', size) .set('sortOrder', sortOrder) @@ -24,4 +28,18 @@ export class BatchesService { return this.http.get(this.apiPrefix + '/batches', { params: httpParams }); } + + createBatch(correlationID: string, institutionId: string, programId: string, signature: string, payload: any): Observable { + const httpParams = new HttpParams() + .set('type', 'raw'); + const headers = new HttpHeaders() + .append('X-CorrelationID', correlationID) + .append('Platform-TenantId', this.settingsService.tenantIdentifier) + .append('X-Signature', signature) + .append('X-CallbackURL', environment.backend.voucherCallbackUrl) + .append('X-Registering-Institution-Id', institutionId) + .append('X-Program-Id', programId); + return this.http.post(this.bulkConnectorOps + '/batchtransactions', payload, { params: httpParams, headers: headers }); + } + } diff --git a/src/app/payment-hub/batches/model/batch.model.ts b/src/app/payment-hub/batches/model/batch.model.ts index ec58ae14..5e378e89 100644 --- a/src/app/payment-hub/batches/model/batch.model.ts +++ b/src/app/payment-hub/batches/model/batch.model.ts @@ -19,9 +19,9 @@ export interface BatchData { failed: number; completed: number; totalAmount: number | null; - ongoingAmount: null, - failedAmount: null, - completedAmount: null, + ongoingAmount: null; + failedAmount: null; + completedAmount: null; result_file: string; resultGeneratedAt: string; note: string; @@ -35,4 +35,20 @@ export interface BatchData { correlationId: string; approvedAmount: string | null; approvedCount: string | null; -} \ No newline at end of file +} + +export interface BatchInstruction { + requestId: string; + creditParty: BatchParty[]; + debitParty: BatchParty[]; + paymentMode: string; + currency: string; + amount: number; + // subType: string | null; + descriptionText: string | null; +} + +export interface BatchParty { + key: string; + value: string; +} diff --git a/src/app/payment-hub/filter-selector/filter-selector.component.ts b/src/app/payment-hub/filter-selector/filter-selector.component.ts index f95cd1a2..4b589759 100644 --- a/src/app/payment-hub/filter-selector/filter-selector.component.ts +++ b/src/app/payment-hub/filter-selector/filter-selector.component.ts @@ -10,16 +10,15 @@ export class FilterSelectorComponent implements OnInit { sections: Section[]; - constructor() { - - } + constructor() { } ngOnInit(): void { this.sections = [ - {label: 'Main Batches', routeTo: ['paymenthub', 'batches'], active: true}, - {label: 'Sub Batches', routeTo: ['paymenthub', 'sub-batches'], active: false}, + {label: 'Main Batches', routeTo: ['paymenthub', 'batches'], active: true}, + {label: 'Create Batch', routeTo: ['paymenthub', 'bulk-import'], active: false}, + {label: 'Sub Batches', routeTo: ['paymenthub', 'sub-batches'], active: false}, {label: 'Transfers', routeTo: ['paymenthub', 'transfers'], active: false} - ]; + ]; } setActive(s: Section): void { diff --git a/src/app/payment-hub/filter-selector/section-model.ts b/src/app/payment-hub/filter-selector/section-model.ts index e07c26fe..76cd7661 100644 --- a/src/app/payment-hub/filter-selector/section-model.ts +++ b/src/app/payment-hub/filter-selector/section-model.ts @@ -1,7 +1,7 @@ export interface Section { label: string; - routeTo: string[] - roleName?: string, + routeTo: string[]; + roleName?: string; icon?: string; active: boolean; -} \ No newline at end of file +} diff --git a/src/app/payment-hub/paymenthub-routing.module.ts b/src/app/payment-hub/paymenthub-routing.module.ts index ae753f0b..cda4824d 100644 --- a/src/app/payment-hub/paymenthub-routing.module.ts +++ b/src/app/payment-hub/paymenthub-routing.module.ts @@ -1,33 +1,31 @@ /** TODO: Separate routing into feature modules for cleaner accounting module. */ /** Angular Imports */ -import { NgModule } from "@angular/core"; -import { Routes, RouterModule } from "@angular/router"; +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; /** Routing Imports */ -import { Route } from "../core/route/route.service"; - -/** Translation Imports */ -import { extract } from "../core/i18n/i18n.service"; +import { Route } from '../core/route/route.service'; /** Custom Components */ -import { TransactionDetailsComponent } from "./transactions/transaction-details.component"; -import { PaymentHubComponent } from "./paymenthub.component"; +import { TransactionDetailsComponent } from './transactions/transaction-details.component'; +import { PaymentHubComponent } from './paymenthub.component'; -import { CurrenciesResolver } from "./transactions/resolver/currencies.resolver"; -import { TransactionResolver } from "./transactions/resolver/transaction.resolver"; -import { DfspResolver } from "./transactions/resolver/dfsp.resolver"; -import { BatchesComponent } from "./batches/batches.component"; -import { SubBatchesComponent } from "./sub-batches/sub-batches.component"; -import { TransfersComponent } from "./transfers/transfers.component"; +import { CurrenciesResolver } from './transactions/resolver/currencies.resolver'; +import { TransactionResolver } from './transactions/resolver/transaction.resolver'; +import { DfspResolver } from './transactions/resolver/dfsp.resolver'; +import { BatchesComponent } from './batches/batches.component'; +import { SubBatchesComponent } from './sub-batches/sub-batches.component'; +import { TransfersComponent } from './transfers/transfers.component'; +import { BatchesBulkImportComponent } from './batches-bulk-import/batches-bulk-import.component'; /** Payment HUB Routes */ const routes: Routes = [ Route.withShell([ { - path: "paymenthub", + path: 'paymenthub', component: PaymentHubComponent, - data: { title: extract("Payment Hub EE"), breadcrumb: "Payment Hub EE" }, + data: { title: 'Payment Hub EE', breadcrumb: 'Payment Hub EE' }, children: [ { path: '', @@ -35,12 +33,17 @@ const routes: Routes = [ pathMatch: 'full' }, { - path: "batches", + path: 'batches', data: { breadcrumb: {alias: 'Batches'} }, component: BatchesComponent }, { - path: "sub-batches", + path: 'bulk-import', + data: { breadcrumb: {alias: 'Batch Bulk Import'} }, + component: BatchesBulkImportComponent, + }, + { + path: 'sub-batches', data: { breadcrumb: {alias: 'SubBatches'} }, children: [ { @@ -48,26 +51,26 @@ const routes: Routes = [ component: SubBatchesComponent, }, { - path: ":batchId", + path: ':batchId', data: { breadcrumb: {alias: 'SubBatches'} }, component: SubBatchesComponent } ] }, { - path: "transfers", + path: 'transfers', data: { breadcrumb: {alias: 'Transfers'} }, component: TransfersComponent, }, { - path: "transactions", + path: 'transactions', children: [ { - path: "", + path: '', component: TransfersComponent, }, { - path: "view/:id", + path: 'view/:id', component: TransactionDetailsComponent, data: { breadcrumb: {alias: 'View Transaction'} }, resolve: { diff --git a/src/app/payment-hub/paymenthub.component.scss b/src/app/payment-hub/paymenthub.component.scss index 9f565f0a..9c437b74 100644 --- a/src/app/payment-hub/paymenthub.component.scss +++ b/src/app/payment-hub/paymenthub.component.scss @@ -1,5 +1,5 @@ .container { - width: 80%; + width: 90%; } .payment-hub-ee-wrap { diff --git a/src/app/payment-hub/paymenthub.module.ts b/src/app/payment-hub/paymenthub.module.ts index abc40629..7c01f03a 100644 --- a/src/app/payment-hub/paymenthub.module.ts +++ b/src/app/payment-hub/paymenthub.module.ts @@ -1,23 +1,26 @@ /** Angular Imports */ -import { NgModule } from "@angular/core"; +import { NgModule } from '@angular/core'; /** Custom Modules */ -import { SharedModule } from "../shared/shared.module"; -import { PaymentHubRoutingModule } from "./paymenthub-routing.module"; -import { PipesModule } from "../pipes/pipes.module"; +import { SharedModule } from '../shared/shared.module'; +import { PaymentHubRoutingModule } from './paymenthub-routing.module'; +import { PipesModule } from '../pipes/pipes.module'; /** Custom Components */ -import { IncomingTransactionsComponent } from "./transactions/incoming/incoming-transactions.component"; -import { OutgoingTransactionsComponent } from "./transactions/outgoing/outgoing-transactions.component"; -import { PaymentHubComponent } from "./paymenthub.component"; -import { TransactionDetailsComponent } from "./transactions/transaction-details.component"; -import { BpmnDialogComponent } from "./transactions/bpmn-dialog/bpmn-dialog.component"; -import { RetryResolveDialogComponent } from "./transactions/retry-resolve-dialog/retry-resolve-dialog.component"; +import { IncomingTransactionsComponent } from './transactions/incoming/incoming-transactions.component'; +import { OutgoingTransactionsComponent } from './transactions/outgoing/outgoing-transactions.component'; +import { PaymentHubComponent } from './paymenthub.component'; +import { TransactionDetailsComponent } from './transactions/transaction-details.component'; +import { BpmnDialogComponent } from './transactions/bpmn-dialog/bpmn-dialog.component'; +import { RetryResolveDialogComponent } from './transactions/retry-resolve-dialog/retry-resolve-dialog.component'; import { FilterSelectorComponent } from './filter-selector/filter-selector.component'; import { BatchesComponent } from './batches/batches.component'; import { SubBatchesComponent } from './sub-batches/sub-batches.component'; -import { DirectivesModule } from "app/directives/directives.module"; +import { DirectivesModule } from 'app/directives/directives.module'; import { TransfersComponent } from './transfers/transfers.component'; +import { BatchesBulkImportComponent } from './batches-bulk-import/batches-bulk-import.component'; +import { TranslateModule } from '@ngx-translate/core'; +import { ViewTransferDetailsComponent } from './transfers/view-transfer-details/view-transfer-details.component'; /** * Payment HUB Module * @@ -41,6 +44,8 @@ import { TransfersComponent } from './transfers/transfers.component'; BatchesComponent, SubBatchesComponent, TransfersComponent, + BatchesBulkImportComponent, + ViewTransferDetailsComponent, ] }) export class PaymentHubModule {} diff --git a/src/app/payment-hub/sub-batches/sub-batches.component.html b/src/app/payment-hub/sub-batches/sub-batches.component.html index 3097fbe1..0ca91c33 100644 --- a/src/app/payment-hub/sub-batches/sub-batches.component.html +++ b/src/app/payment-hub/sub-batches/sub-batches.component.html @@ -4,7 +4,7 @@ -

Filters

+

{{"labels.inputs.Filters" | translate}}

@@ -12,7 +12,7 @@

Filters

- From Date + {{"labels.inputs.From Date" | translate}} @@ -20,7 +20,7 @@

Filters

- To Date + {{"labels.inputs.To Date" | translate}} @@ -29,29 +29,29 @@

Filters

- Source Ministry + {{"labels.inputs.Source Ministry" | translate}} - Batch Reference Number + {{"labels.inputs.Batch Reference Number" | translate}} - Bulk Amount - + {{"labels.inputs.Bulk Amount" | translate}} + - Payer FSP + {{"labels.inputs.Payer FSP" | translate}} @@ -64,42 +64,42 @@

Filters

- + - + - + - + - + - + - + diff --git a/src/app/payment-hub/sub-batches/sub-batches.component.ts b/src/app/payment-hub/sub-batches/sub-batches.component.ts index 7e04f55c..09b62876 100644 --- a/src/app/payment-hub/sub-batches/sub-batches.component.ts +++ b/src/app/payment-hub/sub-batches/sub-batches.component.ts @@ -36,16 +36,15 @@ export class SubBatchesComponent implements OnInit { batchesData: Batch; - page: number = 0; - size: number = 100; + page = 0; + size = 100; batchId: string | null = null; constructor(private route: ActivatedRoute, private router: Router, private dates: Dates, - private subBatchesService: SubBatchesService) { - + private subBatchesService: SubBatchesService) { this.route.params.subscribe(params => { this.batchId = params['batchId']; }); diff --git a/src/app/payment-hub/sub-batches/sub-batches.service.ts b/src/app/payment-hub/sub-batches/sub-batches.service.ts index a597f91c..573c5334 100644 --- a/src/app/payment-hub/sub-batches/sub-batches.service.ts +++ b/src/app/payment-hub/sub-batches/sub-batches.service.ts @@ -16,7 +16,7 @@ export class SubBatchesService { * @returns {Observable} Users data */ getSubBatches(batchId: string, page: number, size: number, orderBy: string, sortOrder: string): Observable { - let httpParams = new HttpParams() + const httpParams = new HttpParams() .set('page', page) .set('size', size) .set('sortOrder', sortOrder) diff --git a/src/app/payment-hub/transactions/bpmn-dialog/bpmn-dialog.component.ts b/src/app/payment-hub/transactions/bpmn-dialog/bpmn-dialog.component.ts index 71154b42..2a5abcb9 100644 --- a/src/app/payment-hub/transactions/bpmn-dialog/bpmn-dialog.component.ts +++ b/src/app/payment-hub/transactions/bpmn-dialog/bpmn-dialog.component.ts @@ -12,8 +12,8 @@ export class BpmnDialogComponent implements OnInit { datasource: any; constructor(public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any) { - this.datasource = data.datasource; + @Inject(MAT_DIALOG_DATA) public data: any) { + this.datasource = data.datasource; } ngOnInit() { diff --git a/src/app/payment-hub/transactions/helper/date-format.helper.ts b/src/app/payment-hub/transactions/helper/date-format.helper.ts index a120f731..b40a7038 100644 --- a/src/app/payment-hub/transactions/helper/date-format.helper.ts +++ b/src/app/payment-hub/transactions/helper/date-format.helper.ts @@ -1,8 +1,3 @@ -import { NativeDateAdapter } from '@angular/material/core'; -import { MatDateFormats } from '@angular/material/core'; -/** import { NgxMatDateFormats } from '@angular-material-components/datetime-picker'; -*/ - export function formatDate(date: Date): string { const year = date.getFullYear(); const month = '0' + (date.getMonth() + 1); @@ -32,15 +27,3 @@ export function formatUTCDate(date: Date): string { // Will display time in 2020-04-10 18:04:36Z format return year + '-' + month.substr(-2) + '-' + day.substr(-2) + 'T' + hours.substr(-2) + ':' + minutes.substr(-2) + ':' + seconds.substr(-2); } - -/** -* export const CUSTOM_MOMENT_FORMATS: NgxMatDateFormats = { -* parse: { -* dateInput: "l, LTS" -* }, -* display: { -* dateInput: "YYYY-MM-DD HH:mm:ss", -* monthYearLabel: 'Y', dateA11yLabel: 'LL', monthYearA11yLabel: 'MMMM Y' -* } -* }; -*/ \ No newline at end of file diff --git a/src/app/payment-hub/transactions/helper/transaction.helper.ts b/src/app/payment-hub/transactions/helper/transaction.helper.ts index 198e7cfe..a9a896c6 100644 --- a/src/app/payment-hub/transactions/helper/transaction.helper.ts +++ b/src/app/payment-hub/transactions/helper/transaction.helper.ts @@ -19,4 +19,4 @@ export const transactionStatusData = [ value: 'UNKNOWN', hidden: true } -]; \ No newline at end of file +]; diff --git a/src/app/payment-hub/transactions/retry-resolve-dialog/retry-resolve-dialog.component.ts b/src/app/payment-hub/transactions/retry-resolve-dialog/retry-resolve-dialog.component.ts index fdfbce56..a4586446 100644 --- a/src/app/payment-hub/transactions/retry-resolve-dialog/retry-resolve-dialog.component.ts +++ b/src/app/payment-hub/transactions/retry-resolve-dialog/retry-resolve-dialog.component.ts @@ -30,4 +30,4 @@ export class RetryResolveDialogComponent implements OnInit { this.dialogRef.close(); } } -} \ No newline at end of file +} diff --git a/src/app/payment-hub/transactions/transaction-details.component.ts b/src/app/payment-hub/transactions/transaction-details.component.ts index 1a58d0eb..562cc2fb 100644 --- a/src/app/payment-hub/transactions/transaction-details.component.ts +++ b/src/app/payment-hub/transactions/transaction-details.component.ts @@ -14,7 +14,7 @@ import { DfspEntry } from './model/dfsp.model'; import { transactionStatusData as statuses } from './helper/transaction.helper'; /** Dialog Components */ -import { BpmnDialogComponent } from './bpmn-dialog/bpmn-dialog.component' +import { BpmnDialogComponent } from './bpmn-dialog/bpmn-dialog.component'; import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; import { RetryResolveDialogComponent } from './retry-resolve-dialog/retry-resolve-dialog.component'; @@ -59,7 +59,7 @@ export class TransactionDetailsComponent implements OnInit { dfspEntriesData: DfspEntry[]; transactionStatusData = statuses; tasks: Array = []; - counter: number = 0; + counter = 0; expandedElement: Array = []; /** * @param {TransactionsService} transactionsService Transactions Service. diff --git a/src/app/payment-hub/transfers/model/transfer.model.ts b/src/app/payment-hub/transfers/model/transfer.model.ts index 5f198542..67e5d43c 100644 --- a/src/app/payment-hub/transfers/model/transfer.model.ts +++ b/src/app/payment-hub/transfers/model/transfer.model.ts @@ -1,4 +1,4 @@ -import { Pageable, Sort } from "app/shared/models/data.model"; +import { Pageable, Sort } from 'app/shared/models/data.model'; export interface TransferData { content: Transfer[]; @@ -19,25 +19,25 @@ export interface Transfer { workflowInstanceKey: number; transactionId: string; startedAt: number; - completedAt: null; + completedAt: number; status: string; - statusDetail: null; - payeeDfspId: null; - payeePartyId: null; - payeePartyIdType: null; - payeeFee: null; - payeeFeeCurrency: null; - payeeQuoteCode: null; - payerDfspId: null; - payerPartyId: null; - payerPartyIdType: null; - payerFee: null; - payerFeeCurrency: null; - payerQuoteCode: null; - amount: null; - currency: null; + statusDetail: string; + payeeDfspId: string; + payeePartyId: string; + payeePartyIdType: string; + payeeFee: number; + payeeFeeCurrency: string; + payeeQuoteCode: string; + payerDfspId: string; + payerPartyId: string; + payerPartyIdType: string; + payerFee: number; + payerFeeCurrency: string; + payerQuoteCode: string; + amount: number; + currency: string; direction: string; - errorInformation: null; - batchId: null; + errorInformation: string; + batchId: string; clientCorrelationId: string; } diff --git a/src/app/payment-hub/transfers/transfers.component.html b/src/app/payment-hub/transfers/transfers.component.html index 32da718c..94ff2f97 100644 --- a/src/app/payment-hub/transfers/transfers.component.html +++ b/src/app/payment-hub/transfers/transfers.component.html @@ -4,7 +4,7 @@ -

Filters

+

{{"labels.inputs.Filters" | translate }}

@@ -13,7 +13,7 @@

Filters

- From Date + {{"labels.inputs.From Date" | translate }} @@ -21,7 +21,7 @@

Filters

- To Date + {{"labels.inputs.To Date" | translate }} @@ -29,56 +29,56 @@

Filters

- Transaction Type + {{"labels.inputs.Transaction Type" | translate }} -
- -
- Source Ministry + {{"labels.inputs.Source Ministry" | translate }} - Source Financial Institution + {{"labels.inputs.Source Financial Institution" | translate }} - Source Account Number + {{"labels.inputs.Source Account Number" | translate }} - Amount - + {{"labels.inputs.Amount" | translate }} +
- Destination Account Number - + {{"labels.inputs.Destination Account Number" | translate }} + - Destination Financial Institution + {{"labels.inputs.Destination Financial Institution" | translate }} - Transaction Reference Number + {{"labels.inputs.Transaction Reference Number" | translate }} +
+ +
@@ -91,50 +91,50 @@

Filters

Batch Reference Number {{"labels.inputs.Batch Reference Number" | translate}} Start Time {{"labels.inputs.Start Time" | translate}} {{ formatDate(convertTimestampToUTCDate(item.startedAt)) }} Completed Time {{"labels.inputs.Completed Time" | translate}} {{ formatDate(convertTimestampToUTCDate(item.completedAt)) }} Source Ministry {{"labels.inputs.Source Ministry" | translate}} {{ shortenValue(item.transactionId) }} Bulk Amount {{"labels.inputs.Bulk Amount" | translate}} {{ item.amount | number }} Payer FSP {{"labels.inputs.Payer FSP" | translate}} {{ item.payerFSP }} Status {{"labels.inputs.Status" | translate}} {{ item.status }}
- + - + - + - + - - + + - + - + - +
Batch Reference Number {{"labels.inputs.Batch Reference Number" | translate }} Start Time {{"labels.inputs.Start Time" | translate }} {{ convertTimestampToUTCDate(transaction.startedAt) | dateFormat }} Completed Time {{"labels.inputs.Completed Time" | translate }} {{ convertTimestampToUTCDate(transaction.completedAt) | dateFormat }} Source Ministry {{"labels.inputs.Source Ministry" | translate }} Bulk Amount {{ transaction.amount | number }} {{"labels.inputs.Bulk Amount" | translate }} {{ transaction.amount | formatNumber }} Payer FSP {{"labels.inputs.Payer FSP" | translate }} {{ transaction.payerDfspId }} Status {{"labels.inputs.Status" | translate }} {{ transaction.status }}
diff --git a/src/app/payment-hub/transfers/transfers.component.ts b/src/app/payment-hub/transfers/transfers.component.ts index ced50367..8200d5fb 100644 --- a/src/app/payment-hub/transfers/transfers.component.ts +++ b/src/app/payment-hub/transfers/transfers.component.ts @@ -6,6 +6,8 @@ import { TransfersService } from './transfers.service'; import { Transfer, TransferData } from './model/transfer.model'; import { UntypedFormControl } from '@angular/forms'; import { MatSort } from '@angular/material/sort'; +import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog'; +import { ViewTransferDetailsComponent } from './view-transfer-details/view-transfer-details.component'; @Component({ selector: 'mifosx-transfers', @@ -48,13 +50,14 @@ export class TransfersComponent implements OnInit { /** Data source for transactions table. */ dataSource = new MatTableDataSource(); - totalRows: number = 0; - currentPage: number = 0; + totalRows = 0; + currentPage = 0; pageSize = 50; isLoading = false; constructor(private dates: Dates, + private dialog: MatDialog, private transfersService: TransfersService) { } ngOnInit(): void { @@ -63,9 +66,16 @@ export class TransfersComponent implements OnInit { getBatches(): void { this.isLoading = true; - this.transfersService.getTransfers(this.currentPage, this.pageSize, 'requestFile', 'asc') + this.transfersService.getTransfers(this.currentPage, this.pageSize) .subscribe((transfers: TransferData) => { + const content: Transfer[] = []; + transfers.content.forEach((t: Transfer) => { + t.amount = t.amount * 1; + + }); this.dataSource = new MatTableDataSource(transfers.content); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; this.totalRows = transfers.totalElements; this.isLoading = false; }, (error: any) => { @@ -95,8 +105,11 @@ export class TransfersComponent implements OnInit { return 'red'; } - searchTransactions(): void { - - } + searchTransactions(): void { } + viewTransfer(transfer: Transfer): void { + this.dialog.open(ViewTransferDetailsComponent, { + data: { transfer: transfer } + }); + } } diff --git a/src/app/payment-hub/transfers/transfers.service.ts b/src/app/payment-hub/transfers/transfers.service.ts index db410058..bf366d1c 100644 --- a/src/app/payment-hub/transfers/transfers.service.ts +++ b/src/app/payment-hub/transfers/transfers.service.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; @@ -15,14 +15,14 @@ export class TransfersService { */ constructor(private http: HttpClient) { } - getTransfers(page: number, size: number, orderBy: string, sortOrder: string): Observable { - let httpParams = new HttpParams() + getTransfers(page: number, size: number): Observable { + const httpParams = new HttpParams() .set('page', page) - .set('size', size) - .set('sortOrder', sortOrder) - .set('orderBy', orderBy); + .set('size', size); + const headers = new HttpHeaders() + .set('Platform-TenantId', environment.tenant); - return this.http.get(this.apiPrefix + '/transfers', { params: httpParams }); + return this.http.get(this.apiPrefix + '/transfers', { params: httpParams, headers: headers }); } } diff --git a/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.html b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.html new file mode 100644 index 00000000..a78b6e3f --- /dev/null +++ b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.html @@ -0,0 +1,91 @@ +

{{ 'labels.heading.View Transfer' | translate }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ 'labels.inputs.ID' | translate }}{{ transfer.id }}
{{ 'labels.inputs.Transaction ID' | translate }} +
{{ 'labels.inputs.Batch ID' | translate }}
{{ 'labels.inputs.Client Correlation ID' | translate }}
{{ 'labels.inputs.Amount' | translate }}{{ transfer.amount | formatNumber }} {{ transfer.currency }}
{{ 'labels.inputs.Direction' | translate }}{{ transfer.direction }}
{{ 'labels.inputs.Payee Dfsp' | translate }}{{ transfer.payeeDfspId }}
{{ 'labels.inputs.Payee Fee' | translate }}{{ transfer.payeeFee | formatNumber }} {{transfer.payeeFeeCurrency }}
{{ 'labels.inputs.Payee Party' | translate }}{{transfer.payeePartyIdType}} : {{ transfer.payeePartyId }}
{{ 'labels.inputs.Payer Dfsp' | translate }}{{ transfer.payerDfspId }}
{{ 'labels.inputs.Payee Fee' | translate }}{{ transfer.payeeFee | formatNumber }} {{transfer.payeeFeeCurrency }}
{{ 'labels.inputs.Payer Party' | translate }}{{transfer.payerPartyIdType}} : {{ transfer.payerPartyId }}
{{ 'labels.inputs.Status' | translate }} + {{ transfer.status }} +
{{ 'labels.inputs.Start Time' | translate }}{{ convertTimestampToUTCDate(transfer.startedAt) }}
{{ 'labels.inputs.Completed Time' | translate }}{{ convertTimestampToUTCDate(transfer.completedAt) }}
+ +
+ + + + \ No newline at end of file diff --git a/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.scss b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.scss new file mode 100644 index 00000000..6943cd63 --- /dev/null +++ b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.scss @@ -0,0 +1,16 @@ +table { + th { + text-align: left; + font-weight: 500; + padding: 0 0.4rem 0 0; + + &.header { + text-align: center; + padding: 0.4rem 0.4rem 0 0; + } + } + + td { + padding: 0 0.4rem 0 0; + } +} \ No newline at end of file diff --git a/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.spec.ts b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.spec.ts new file mode 100644 index 00000000..00f03c89 --- /dev/null +++ b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ViewTransferDetailsComponent } from './view-transfer-details.component'; + +describe('ViewTransferDetailsComponent', () => { + let component: ViewTransferDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ViewTransferDetailsComponent] + }); + fixture = TestBed.createComponent(ViewTransferDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.ts b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.ts new file mode 100644 index 00000000..ee145692 --- /dev/null +++ b/src/app/payment-hub/transfers/view-transfer-details/view-transfer-details.component.ts @@ -0,0 +1,37 @@ +import { Component, Inject } from '@angular/core'; +import { MatLegacyDialogRef as MatDialogRef, MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA } from '@angular/material/legacy-dialog'; +import { Dates } from 'app/core/utils/dates'; +import { Transfer } from '../model/transfer.model'; + +@Component({ + selector: 'mifosx-view-transfer-details', + templateUrl: './view-transfer-details.component.html', + styleUrls: ['./view-transfer-details.component.scss'] +}) +export class ViewTransferDetailsComponent { + + transfer: Transfer; + + constructor(private dates: Dates, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any) { + this.transfer = data.transfer; + } + + convertTimestampToUTCDate(timestamp: any) { + if (!timestamp) { + return undefined; + } + return this.dates.formatUTCDate(new Date(timestamp)); + } + + status(item: Transfer): string { + if (item.status === 'COMPLETED') { + return 'green'; + } else if (item.status === 'ON_GOING') { + return 'yellow'; + } + return 'red'; + } + +} diff --git a/src/app/pipes/format-number.pipe.spec.ts b/src/app/pipes/format-number.pipe.spec.ts new file mode 100644 index 00000000..8d2eeac3 --- /dev/null +++ b/src/app/pipes/format-number.pipe.spec.ts @@ -0,0 +1,8 @@ +import { FormatNumberPipe } from './format-number.pipe'; + +describe('FormatNumberPipe', () => { + it('create an instance', () => { + const pipe = new FormatNumberPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/src/app/pipes/format-number.pipe.ts b/src/app/pipes/format-number.pipe.ts new file mode 100644 index 00000000..583025d2 --- /dev/null +++ b/src/app/pipes/format-number.pipe.ts @@ -0,0 +1,27 @@ +import { DecimalPipe } from '@angular/common'; +import { Pipe, PipeTransform } from '@angular/core'; +import { SettingsService } from 'app/settings/settings.service'; + +@Pipe({ + name: 'formatNumber' +}) +export class FormatNumberPipe implements PipeTransform { + + constructor(private decimalFormat: DecimalPipe, + private settingsService: SettingsService) { + } + + transform(value: string | number, ...args: unknown[]): string { + if (value === 0) { + return '0.00'; + } + if (!value) { + return ''; + } + const locale = this.settingsService.language.code; + const decimals = this.settingsService.decimals; + const format = `1.${decimals}-${decimals}`; + return this.decimalFormat.transform(value, format, locale); + } + +} diff --git a/src/app/pipes/pipes.module.ts b/src/app/pipes/pipes.module.ts index 528343f5..785cb0ce 100644 --- a/src/app/pipes/pipes.module.ts +++ b/src/app/pipes/pipes.module.ts @@ -1,17 +1,17 @@ import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; +import { CommonModule, DecimalPipe } from '@angular/common'; import { StatusLookupPipe } from './status-lookup.pipe'; import { FindPipe } from './find.pipe'; -import { PrettyPrintPipe } from './pretty-print.pipe'; import { DateFormatPipe } from './date-format.pipe'; import { ExternalIdentifierPipe } from './external-identifier.pipe'; +import { FormatNumberPipe } from './format-number.pipe'; @NgModule({ imports: [ CommonModule ], - declarations: [StatusLookupPipe, FindPipe, PrettyPrintPipe, DateFormatPipe, ExternalIdentifierPipe], - providers: [StatusLookupPipe, FindPipe, PrettyPrintPipe, DateFormatPipe, ExternalIdentifierPipe], - exports: [StatusLookupPipe, FindPipe, PrettyPrintPipe, DateFormatPipe, ExternalIdentifierPipe] + declarations: [StatusLookupPipe, FindPipe, DateFormatPipe, ExternalIdentifierPipe, FormatNumberPipe], + providers: [StatusLookupPipe, FindPipe, DateFormatPipe, ExternalIdentifierPipe, FormatNumberPipe, DecimalPipe], + exports: [StatusLookupPipe, FindPipe, DateFormatPipe, ExternalIdentifierPipe, FormatNumberPipe] }) export class PipesModule { } diff --git a/src/app/pipes/pretty-print.pipe.spec.ts b/src/app/pipes/pretty-print.pipe.spec.ts deleted file mode 100644 index ed06db00..00000000 --- a/src/app/pipes/pretty-print.pipe.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PrettyPrintPipe } from './pretty-print.pipe'; - -describe('PrettyPrintPipe', () => { - it('create an instance', () => { - const pipe = new PrettyPrintPipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/src/app/pipes/pretty-print.pipe.ts b/src/app/pipes/pretty-print.pipe.ts deleted file mode 100644 index 92f353e7..00000000 --- a/src/app/pipes/pretty-print.pipe.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'prettyPrint' -}) -export class PrettyPrintPipe implements PipeTransform { - - transform(val: any) { - var s=""; - var tb=0; - val=String(val); - //console.log(val.length); - var i=0; - for(i=0;i",""); - } - return s; - } - -} diff --git a/src/app/settings/settings-routing.module.ts b/src/app/settings/settings-routing.module.ts index db7d17c9..e4888ac8 100644 --- a/src/app/settings/settings-routing.module.ts +++ b/src/app/settings/settings-routing.module.ts @@ -5,9 +5,6 @@ import { Routes, RouterModule } from '@angular/router'; /** Routing Imports */ import { Route } from '../core/route/route.service'; -/** Translation Imports */ -import { extract } from '../core/i18n/i18n.service'; - /** Custom Components */ import { SettingsComponent } from './settings.component'; @@ -17,7 +14,7 @@ const routes: Routes = [ { path: 'settings', component: SettingsComponent, - data: { title: extract('Settings'), breadcrumb: 'Settings' } + data: { title: 'Settings', breadcrumb: 'Settings' } } ]) ]; diff --git a/src/app/settings/settings.service.ts b/src/app/settings/settings.service.ts index 30c5a37f..dcc37665 100644 --- a/src/app/settings/settings.service.ts +++ b/src/app/settings/settings.service.ts @@ -42,7 +42,7 @@ export class SettingsService { } setDefaultLanguage() { - const defaultLanguage = environment.defaultLanguage ? environment.defaultLanguage : 'en-US'; + const defaultLanguage = environment.defaultLanguage ? environment.defaultLanguage : 'en'; this.setLanguage({ name: defaultLanguage, code: defaultLanguage.substring(0, 2) diff --git a/src/app/shared/drag-drop-file/drag-drop-file.component.html b/src/app/shared/drag-drop-file/drag-drop-file.component.html new file mode 100644 index 00000000..f8b765c5 --- /dev/null +++ b/src/app/shared/drag-drop-file/drag-drop-file.component.html @@ -0,0 +1,9 @@ +
+ + + {{"labels.texts.Drag and Drop the CSV input file, or" | translate}} + + + +
\ No newline at end of file diff --git a/src/app/shared/drag-drop-file/drag-drop-file.component.scss b/src/app/shared/drag-drop-file/drag-drop-file.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/shared/drag-drop-file/drag-drop-file.component.spec.ts b/src/app/shared/drag-drop-file/drag-drop-file.component.spec.ts new file mode 100644 index 00000000..d31b5523 --- /dev/null +++ b/src/app/shared/drag-drop-file/drag-drop-file.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DragDropFileComponent } from './drag-drop-file.component'; + +describe('DragDropFileComponent', () => { + let component: DragDropFileComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [DragDropFileComponent] + }); + fixture = TestBed.createComponent(DragDropFileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/drag-drop-file/drag-drop-file.component.ts b/src/app/shared/drag-drop-file/drag-drop-file.component.ts new file mode 100644 index 00000000..83f38128 --- /dev/null +++ b/src/app/shared/drag-drop-file/drag-drop-file.component.ts @@ -0,0 +1,43 @@ +import { Component, EventEmitter, Output } from '@angular/core'; +import { NgxFileDropEntry } from 'ngx-file-drop'; + +@Component({ + selector: 'mifosx-drag-drop-file', + templateUrl: './drag-drop-file.component.html', + styleUrls: ['./drag-drop-file.component.scss'] +}) +export class DragDropFileComponent { + + @Output() onFileChange = new EventEmitter(); + + public files: NgxFileDropEntry[] = []; + + public dropped(files: NgxFileDropEntry[]) { + this.files = files; + for (const droppedFile of files) { + + // Is it a file? + if (droppedFile.fileEntry.isFile) { + const fileEntry = droppedFile.fileEntry as FileSystemFileEntry; + fileEntry.file((file: File) => { + + // Here you can access the real file + // console.log(droppedFile.relativePath, file); + this.onFileChange.emit(file); + }); + } else { + // It was a directory (empty directories are added, otherwise only files) + const fileEntry = droppedFile.fileEntry as FileSystemDirectoryEntry; + console.log(droppedFile.relativePath, fileEntry); + } + } + } + + public fileOver(event: any) { + // console.log(event); + } + + public fileLeave(event: any) { + // console.log(event); + } +} diff --git a/src/app/shared/icons.module.ts b/src/app/shared/icons.module.ts index a6e247d9..1ed2f34b 100644 --- a/src/app/shared/icons.module.ts +++ b/src/app/shared/icons.module.ts @@ -2,9 +2,7 @@ import { NgModule } from '@angular/core'; /** Angular Font Awesome Imports */ -import { FontAwesomeModule, FaIconLibrary} from '@fortawesome/angular-fontawesome'; -import { library } from '@fortawesome/fontawesome-svg-core'; -import { faFilter, fas } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faAnchor, faArchive, @@ -24,14 +22,17 @@ import { faChevronLeft, faChevronRight, faCircle, + faHeartBroken, faClock, faCloud, faCog, faCogs, faCommentAlt, + faCopy, faDollarSign, faEdit, faEnvelope, + faExchange, faExclamationCircle, faExclamationTriangle, faEye, @@ -51,6 +52,7 @@ import { faLock, faLockOpen, faMinusCircle, + faMinus, faMoneyBillAlt, faMoneyCheck, faPencilAlt, @@ -69,7 +71,6 @@ import { faTachometerAlt, faTag, faTags, - faRedo, faTimesCircle, faTrash, faUndo, @@ -78,6 +79,7 @@ import { faUser, faUsers, faUserShield, + faUserTie, faDownload, faUpload, faCloudDownloadAlt, @@ -85,102 +87,33 @@ import { faTimes, faStickyNote, faStop, - faAngleDown, - faAngleUp, - faTicket, -} from '@fortawesome/free-solid-svg-icons'; - -/** Add icons to the library for convenient access in other components. */ -library.add( - faAnchor, - faArchive, - faArrowLeft, - faArrowRight, - faBars, - faBell, - faBook, - faBriefcase, - faBuilding, - faCalendar, - faCalendarAlt, - faChartBar, - faCheck, - faCheckCircle, - faChevronDown, - faChevronLeft, - faChevronRight, - faCircle, - faClock, - faCloud, - faCog, - faCogs, - faCommentAlt, - faDollarSign, - faEdit, - faEnvelope, - faExclamationCircle, - faExclamationTriangle, - faEye, - faEyeSlash, - faFile, - faFileAlt, - faFileUpload, - faFileWord, - faFillDrip, - faHandHoldingUsd, - faHome, - faKey, - faLink, - faList, - faListUl, - faLocationArrow, - faLock, - faLockOpen, - faMinusCircle, - faMoneyBillAlt, - faMoneyCheck, - faPencilAlt, - faPlay, - faPlus, - faPlusCircle, - faQuestionCircle, - faRandom, - faRoad, - faSearch, - faShieldAlt, - faSignOutAlt, - faSitemap, - faSync, - faTable, - faTachometerAlt, - faTag, - faTags, - faRedo, - faTimesCircle, - faTrash, - faUndo, - faUniversity, - faUserCircle, - faUser, - faUsers, - faUserShield, - faDownload, - faUpload, - faCloudDownloadAlt, - faCloudUploadAlt, - faTimes, - faStickyNote, - faStop, - faAngleDown, - faAngleUp, - faUserCircle, - faTicket, - faFileAlt, + faBan, + faBolt, + faLaptop, + faDonate, + faMoneyBill, + faChartLine, + faPen, + faFlag, + faArrowUp, + faArrowDown, + faFolderOpen, + faIdBadge, + faAddressCard, + faKeyboard, + faInfo, + faTasks, + faCoins, + faPiggyBank, + faFileExcel, + faFileExport, + faCalculator, + faCalendarCheck, + faPause, faFilter, - faUpload, - faFileUpload, - fas, -); + faPaperPlane, + faTicket +} from '@fortawesome/free-solid-svg-icons'; /** * Icons Module @@ -190,8 +123,122 @@ library.add( @NgModule({ exports: [FontAwesomeModule] }) -export class IconsModule { +export class IconsModule { + constructor(library: FaIconLibrary) { - library.addIconPacks(fas); -} + library.addIcons( + faAnchor, + faArchive, + faArrowLeft, + faArrowRight, + faBan, + faBars, + faBell, + faBook, + faBriefcase, + faBuilding, + faCalculator, + faCalendar, + faCalendarAlt, + faCalendarCheck, + faChartBar, + faCheck, + faCheckCircle, + faChevronDown, + faChevronLeft, + faChevronRight, + faCircle, + faHeartBroken, + faClock, + faCloud, + faCog, + faCogs, + faCommentAlt, + faCopy, + faDollarSign, + faEdit, + faEnvelope, + faExchange, + faExclamationCircle, + faExclamationTriangle, + faEye, + faEyeSlash, + faFile, + faFileAlt, + faFileUpload, + faFileWord, + faFileExcel, + faFileExport, + faFillDrip, + faFilter, + faHandHoldingUsd, + faHome, + faKey, + faLink, + faList, + faListUl, + faLocationArrow, + faLock, + faLockOpen, + faMinus, + faMinusCircle, + faMoneyBillAlt, + faMoneyCheck, + faPause, + faPencilAlt, + faPlay, + faPlus, + faPlusCircle, + faQuestionCircle, + faRandom, + faRoad, + faSearch, + faShieldAlt, + faSignOutAlt, + faSitemap, + faSync, + faTable, + faTachometerAlt, + faTag, + faTags, + faTimesCircle, + faTrash, + faUndo, + faUniversity, + faUserCircle, + faUser, + faUsers, + faUserShield, + faUserTie, + faDownload, + faUpload, + faCloudDownloadAlt, + faCloudUploadAlt, + faTimes, + faStickyNote, + faStop, + faBan, + faBolt, + faLaptop, + faDonate, + faMoneyBill, + faChartLine, + faPen, + faFlag, + faArrowUp, + faArrowDown, + faFolderOpen, + faIdBadge, + faAddressCard, + faKeyboard, + faInfo, + faTasks, + faCoins, + faPiggyBank, + faBars, + faPaperPlane, + faTicket + ); + } + } diff --git a/src/app/shared/language-selector/language-selector.component.ts b/src/app/shared/language-selector/language-selector.component.ts index f72f38f8..4c37aa76 100644 --- a/src/app/shared/language-selector/language-selector.component.ts +++ b/src/app/shared/language-selector/language-selector.component.ts @@ -27,18 +27,17 @@ export class LanguageSelectorComponent implements OnInit { * @param {TranslateService} translateService Translate Service. */ constructor(private translateService: TranslateService, - private settingsService: SettingsService) { - this.languageSelector.patchValue(this.currentLanguage); - } + private settingsService: SettingsService) { } - ngOnInit() { } + ngOnInit() { + this.languageSelector = new UntypedFormControl(this.currentLanguage); + } /** * Sets a new language to be used by the application. * @param {string} language New language. */ setLanguage() { - console.log(this.languageSelector.value); this.translateService.use(this.languageSelector.value); this.settingsService.setLanguage({ name: '', code: this.languageSelector.value.substring(0, 2) }); } @@ -48,7 +47,7 @@ export class LanguageSelectorComponent implements OnInit { * @returns {string} Current language. */ get currentLanguage(): string { - return this.translateService.currentLang; + return this.translateService.currentLang || this.settingsService.language.code; } /** diff --git a/src/app/shared/list-item/list-item.component.html b/src/app/shared/list-item/list-item.component.html index 8cbda2ff..5ea937d0 100644 --- a/src/app/shared/list-item/list-item.component.html +++ b/src/app/shared/list-item/list-item.component.html @@ -1,6 +1,6 @@

- {{ section.label }} + {{ 'labels.menus.' + section.label | translate }}

\ No newline at end of file diff --git a/src/app/shared/list-item/list-item.component.scss b/src/app/shared/list-item/list-item.component.scss index becbdd8a..59a55014 100644 --- a/src/app/shared/list-item/list-item.component.scss +++ b/src/app/shared/list-item/list-item.component.scss @@ -4,7 +4,7 @@ border-radius: 15px; border: $border-size solid $mid-grey; height: 110px; - width: 280px; + width: 260px; vertical-align: middle; margin: 15px; padding-top: 15px; diff --git a/src/app/shared/list-item/list-item.component.ts b/src/app/shared/list-item/list-item.component.ts index 354af294..d21b7c3f 100644 --- a/src/app/shared/list-item/list-item.component.ts +++ b/src/app/shared/list-item/list-item.component.ts @@ -13,7 +13,7 @@ export class ListItemComponent { @Input() classFormat: string; @Input() classFormatTitle: string; @Input() icon: string | null; - @Output() sectionChange = new EventEmitter
(); + @Output() sectionChange = new EventEmitter
(); constructor(private router: Router) { } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 00f41b94..1acd3d94 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -22,6 +22,8 @@ import { IdentifierComponent } from './identifier/identifier.component'; import { PipesModule } from 'app/pipes/pipes.module'; import { BreadcrumbModule, BreadcrumbService } from 'xng-breadcrumb'; import { NgxCsvParserModule } from 'ngx-csv-parser'; +import { DragDropFileComponent } from './drag-drop-file/drag-drop-file.component'; +import { NgxFileDropModule } from 'ngx-file-drop'; /** * Shared Module @@ -37,7 +39,8 @@ import { NgxCsvParserModule } from 'ngx-csv-parser'; PipesModule, TranslateModule, BreadcrumbModule, - NgxCsvParserModule + NgxCsvParserModule, + NgxFileDropModule ], declarations: [ FormfieldComponent, @@ -49,7 +52,8 @@ import { NgxCsvParserModule } from 'ngx-csv-parser'; ThemePickerComponent, ListItemComponent, TenantSelectorComponent, - IdentifierComponent + IdentifierComponent, + DragDropFileComponent ], exports: [ FileUploadComponent, @@ -66,7 +70,9 @@ import { NgxCsvParserModule } from 'ngx-csv-parser'; TenantSelectorComponent, IdentifierComponent, BreadcrumbModule, - NgxCsvParserModule + NgxCsvParserModule, + NgxFileDropModule, + DragDropFileComponent ], providers: [ BreadcrumbService diff --git a/src/app/system/system-routing.module.ts b/src/app/system/system-routing.module.ts index 44d155da..ef5baf76 100644 --- a/src/app/system/system-routing.module.ts +++ b/src/app/system/system-routing.module.ts @@ -3,7 +3,6 @@ import { NgModule } from '@angular/core'; /** Routing Imports */ import { Routes, RouterModule } from '@angular/router'; import { Route } from '../core/route/route.service'; -import { extract } from '../core/i18n/i18n.service'; /** Component Imports */ import { SystemComponent } from './system.component'; @@ -22,7 +21,7 @@ const routes: Routes = [ Route.withShell([ { path: 'system', - data: { title: extract('System'), breadcrumb: 'System' }, + data: { title: 'System', breadcrumb: 'System' }, children: [ { path: '', @@ -30,7 +29,7 @@ const routes: Routes = [ }, { path: 'roles-and-permissions', - data: { title: extract('Roles and Permissions'), breadcrumb: 'Roles and Permissions' }, + data: { title: 'Roles and Permissions', breadcrumb: 'Roles and Permissions' }, children: [ { path: '', @@ -42,13 +41,13 @@ const routes: Routes = [ { path: 'add', component: AddRoleComponent, - data: { title: extract('Add Role'), breadcrumb: 'Add' } + data: { title: 'Add Role', breadcrumb: 'Add' } } ] }, { path: 'audit-trails', - data: { title: extract('Audit Trails'), breadcrumb: 'Audit Trails' }, + data: { title: 'Audit Trails', breadcrumb: 'Audit Trails' }, children: [ { path: '', @@ -60,7 +59,7 @@ const routes: Routes = [ { path: ':id', component: ViewAuditComponent, - data: { title: extract('View Audit'), routeParamBreadcrumb: 'id' }, + data: { title: 'View Audit', routeParamBreadcrumb: 'id' }, resolve: { auditTrail: AuditTrailResolver } diff --git a/src/app/users/users-routing.module.ts b/src/app/users/users-routing.module.ts index 04540b1f..7a5f25ba 100644 --- a/src/app/users/users-routing.module.ts +++ b/src/app/users/users-routing.module.ts @@ -5,9 +5,6 @@ import { Routes, RouterModule } from '@angular/router'; /** Routing Imports */ import { Route } from '../core/route/route.service'; -/** Translation Imports */ -import { extract } from '../core/i18n/i18n.service'; - /** Custom Components */ import { UsersComponent } from './users.component'; import { CreateUserComponent } from './create-user/create-user.component'; @@ -23,7 +20,7 @@ const routes: Routes = [ Route.withShell([ { path: 'users', - data: { title: extract('Users'), breadcrumb: 'Users' }, + data: { title: 'Users', breadcrumb: 'Users' }, children: [ { path: '', @@ -35,14 +32,14 @@ const routes: Routes = [ { path: 'create', component: CreateUserComponent, - data: { title: extract('Create User'), breadcrumb: 'Create User' }, + data: { title: 'Create User', breadcrumb: 'Create User' }, resolve: { usersTemplate: UsersTemplateResolver } }, { path: ':id', - data: { title: extract('View User'), routeResolveBreadcrumb: ['user', 'username'] }, + data: { title: 'View User', routeResolveBreadcrumb: ['user', 'username'] }, resolve: { user: UserResolver }, diff --git a/src/app/vouchers/models/vouchers-model.ts b/src/app/vouchers/models/vouchers-model.ts index 60409f64..fd9e2d92 100644 --- a/src/app/vouchers/models/vouchers-model.ts +++ b/src/app/vouchers/models/vouchers-model.ts @@ -1,4 +1,4 @@ -import { Pageable, Sort } from "app/shared/models/data.model"; +import { Pageable, Sort } from 'app/shared/models/data.model'; export interface VoucherData { content: Voucher[]; @@ -27,7 +27,7 @@ export interface Status { } export interface VoucherInstruction { - instructionId: string; + instructionID: string; groupCode: string; currency: string; amount: number; diff --git a/src/app/vouchers/services/vouchers.service.ts b/src/app/vouchers/services/vouchers.service.ts index e4639e80..ac9550d6 100644 --- a/src/app/vouchers/services/vouchers.service.ts +++ b/src/app/vouchers/services/vouchers.service.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpParams } from '@angular/common/http'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from 'environments/environment'; import { Observable } from 'rxjs'; @@ -16,17 +16,18 @@ export class VouchersService { * @returns {Observable} Users data */ getVouchers(page: number, size: number, orderBy: string, sortOrder: string): Observable { - let httpParams = new HttpParams() + const httpParams = new HttpParams() .set('page', page) - .set('size', size) - .set('sortOrder', sortOrder) - .set('orderBy', orderBy); + .set('size', size); return this.http.get(this.apiPrefix + '/vouchers', { params: httpParams }); } - createVoucher(payload: any): Observable { - return this.http.post(this.apiPrefix + '/vouchers', payload); + createVoucher(callbackUrl: string, payload: any): Observable { + const headers = new HttpHeaders() + .append('x-callbackurl', callbackUrl); + + return this.http.post(this.apiPrefix + '/vouchers', payload, {headers: headers}); } } diff --git a/src/app/vouchers/voucher-management/voucher-management.component.html b/src/app/vouchers/voucher-management/voucher-management.component.html index 88d1cfd3..cd8987cf 100644 --- a/src/app/vouchers/voucher-management/voucher-management.component.html +++ b/src/app/vouchers/voucher-management/voucher-management.component.html @@ -4,7 +4,7 @@ -

Filters

+

{{"labels.inputs.Filters" | translate}}

@@ -12,7 +12,7 @@

Filters

- Date Voucher Created + {{"labels.inputs.Date Voucher Created" | translate}} @@ -21,29 +21,29 @@

Filters

- Serial Number + {{"labels.inputs.Serial Number" | translate}} - Government Entity + {{"labels.inputs.Government Entity" | translate}} - Functional ID + {{"labels.inputs.Functional ID" | translate}} - Status + {{"labels.inputs.Status" | translate}}
@@ -57,30 +57,30 @@

Filters

- + - - + + - - + + - + - + diff --git a/src/app/vouchers/voucher-management/voucher-management.component.ts b/src/app/vouchers/voucher-management/voucher-management.component.ts index 6a3c221c..343397d3 100644 --- a/src/app/vouchers/voucher-management/voucher-management.component.ts +++ b/src/app/vouchers/voucher-management/voucher-management.component.ts @@ -33,13 +33,13 @@ export class VoucherManagementComponent implements OnInit { status = new UntypedFormControl(); /** Columns to be displayed in transactions table. */ - displayedColumns: string[] = ['serialNumber', 'createdAt', 'governmentEntity', 'functionalId', 'status']; + displayedColumns: string[] = ['serialNumber', 'createdDate', 'registeringInstitutionId', 'functionalId', 'status']; /** Data source for transactions table. */ dataSource = new MatTableDataSource(); vouchersData: VoucherData; - totalRows: number = 0; - currentPage: number = 0; + totalRows = 0; + currentPage = 0; pageSize = 50; isLoading = false; diff --git a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.html b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.html index db077e54..dd48844d 100644 --- a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.html +++ b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.html @@ -1,76 +1,92 @@
-
-
-
-
- - -
-
-
-
- +
+ +
+
+ +
-
+ -
Serial Number {{"labels.inputs.Serial Number" | translate}} Date Voucher {{"labels.inputs.Date Voucher" | translate}} {{ convertTimestampToUTCDate(item.createdDate) | dateFormat }} Government Entity {{"labels.inputs.Government Entity" | translate}} {{ item.registeringInstitutionId }} Functional ID {{"labels.inputs.Functional ID" | translate}} Status {{"labels.inputs.Status" | translate}} {{ validateStatus(item.status) }}
+
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# {{(idx + 1)}} Instruction Id - - Group Code {{ voucher.groupCode }} Currency {{ voucher.currency }} Amount {{ voucher.amount | number }} Expiry {{ voucher.expiry }} Functional Id - - Description {{ voucher.narration }}
- - - -
- -
+
+ +
+ + {{"labels.inputs.Request Id" | translate}} + + + + {{"labels.inputs.URL" | translate}} + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
# {{(idx + 1)}} {{"labels.inputs.Instruction Id" | translate }} + + {{"labels.inputs.Group Code" | translate }} {{ voucher.groupCode }} {{"labels.inputs.Currency" | translate }} {{ voucher.currency }} {{"labels.inputs.Amount" | translate }} {{ voucher.amount | number }} {{"labels.inputs.Expiry" | translate }} {{ voucher.expiry }} {{"labels.inputs.Functional Id" | translate }} + + {{"labels.inputs.Description" | translate }} {{ voucher.narration }}
+ + + +
+ +
-
+ + \ No newline at end of file diff --git a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.scss b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.scss index 863ca07d..55e25139 100644 --- a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.scss +++ b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.scss @@ -1,6 +1,46 @@ @import 'theme/theme'; +.dropzone { + padding: 2rem; + text-align: center; + border: dashed 1px #979797; + position: relative; + margin: 0 auto; + height: 200px; + display: table; + + width: 100%; + height: 200px; + background-color: #eee; + + input { + opacity: 0; + position: absolute; + z-index: 2; + width: 100%; + height: 100%; + top: 0; + left: 0; + } + + label { + color: black; + width: 183px; + height: 44px; + border-radius: 21.5px; + background-color: transparent; + padding: 8px 16px; + } + + h3 { + font-size: 20px; + font-weight: 600; + color: #38424c; + } +} + .option { + height: inherit; border-radius: 15px; background-color: $mid-grey; border: $border-size solid $mid-grey; @@ -20,19 +60,10 @@ } } -.option:hover { - background-color: $primary; - .title { - color: $white; - fa-icon { - color: $white; - } - } -} - .text-wrapper { display: table-cell; vertical-align: middle; + width: 100%; } .centered { @@ -40,30 +71,22 @@ text-align: center; } -.dropzone { - height: 200px; - display: table; - width: 100%; - background-color: #eee; - border: dotted 1px #aaa; -} - -input[type="file"]{ +input[type="file"] { display: none; } -.textLink{ +.textLink { background-color: $primary; - color:#fff; + color: white; padding: 10px; border-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } -.textLink::before{ +.textLink::before { content: "\f093"; - font-weight: 900; - color: #fff; - font-size: large; - margin-right: 10px; + font-weight: 900; + color: #fff; + font-size: large; + margin-right: 10px; } \ No newline at end of file diff --git a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.ts b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.ts index 1fe48dad..b08de74f 100644 --- a/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.ts +++ b/src/app/vouchers/vouchers-bulk-import/vouchers-bulk-import.component.ts @@ -1,58 +1,61 @@ -import { Component } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { AlertService } from 'app/core/alert/alert.service'; -import { VoucherInstruction } from '../models/vouchers-model'; import { NgxCsvParser } from 'ngx-csv-parser'; import { MatTableDataSource } from '@angular/material/table'; -import { v4 as uuid } from 'uuid'; import { VouchersService } from '../services/vouchers.service'; +import * as XLSX from 'xlsx'; +import { VoucherInstruction } from '../models/vouchers-model'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { environment } from 'environments/environment'; +import { MatSort } from '@angular/material/sort'; + @Component({ selector: 'mifosx-vouchers-bulk-import', templateUrl: './vouchers-bulk-import.component.html', styleUrls: ['./vouchers-bulk-import.component.scss'] }) -export class VouchersBulkImportComponent { - files: any[] = []; +export class VouchersBulkImportComponent implements OnInit { + + /** Paginator for table. */ + @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; + /** Sorter for reports table. */ + @ViewChild(MatSort, { static: true }) sort: MatSort; + + createVoucherForm: UntypedFormGroup; + voucherInstructions: VoucherInstruction[] = []; + files: File[] = []; + requestID: string; + batchID: string; + displayedColumns: string[] = ['rowId', 'instructionId', 'groupCode', 'currency', 'amount', 'expiry', 'functionalId', 'narration']; dataSource = new MatTableDataSource(); totalRows = 0; - pageSize = 10; + currentPage = 1; isLoading = false; constructor(private alertService: AlertService, private csvParse: NgxCsvParser, - private vouchersService: VouchersService) { } - - onFileChange(fileList: File[]): void { - this.isLoading = true; - this.files = Object.keys(fileList).map(key => fileList[key]); - this.csvParse.parse(this.files[0], {header: true, delimiter: ','}) - .pipe().subscribe((results: Array) => { - this.voucherInstructions = []; - results.forEach((item: any) => { - this.voucherInstructions.push({ - instructionId: item['Instruction Id'], - groupCode: item['Voucher Group Code'], - currency: item['Currency'], - amount: item['Amount'], - expiry: item['Expiry'], - functionalId: item['Payee Functional Id'], - narration: item['Narration'] || null - }); - }); - this.totalRows = this.voucherInstructions.length; + private vouchersService: VouchersService, + private formBuilder: UntypedFormBuilder) { } - this.dataSource = new MatTableDataSource(this.voucherInstructions); - this.isLoading = false; + ngOnInit(): void { + this.createVoucherForm = this.formBuilder.group({ + 'callbackUrl': [environment.backend.voucherCallbackUrl, Validators.required], + 'requestId': [this.generateID(12), Validators.required] }); - this.alertService.alert({ type: 'Voucher File Upload', message: 'Successfully parsed!' }); + } + + onFileChange(file: File): void { + this.processFiles(file); } deleteFile(f: any) { - this.files = this.files.filter(function (w) { return w.name != f.name }); + this.files = this.files.filter((w: any) => w.name !== f.name); this.alertService.alert({ type: 'Voucher File Upload', message: 'Successfully delete!' }); } @@ -60,16 +63,89 @@ export class VouchersBulkImportComponent { return (this.files.length > 0); } + processFiles(file: File): void { + this.isLoading = true; + this.csvParse.parse(file, { header: true, delimiter: ',' }) + .pipe().subscribe((results: Array) => { + this.voucherInstructions = []; + results.forEach((item: any) => { + this.voucherInstructions.push({ + instructionID: item['Instruction Id'], + groupCode: item['Voucher Group Code'], + currency: item['Currency'], + amount: item['Amount'], + expiry: item['Expiry'], + functionalId: item['Payee Functional Id'], + narration: item['Narration'] || null + }); + }); + this.files.push(file); + this.totalRows = this.voucherInstructions.length; + + this.dataSource = new MatTableDataSource(this.voucherInstructions); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + this.batchID = this.generateID(12); + this.isLoading = false; + }); + this.alertService.alert({ type: 'Voucher File Upload', message: 'Successfully parsed!' }); + } + + generateID(n: number): string { + const add = 1; + let max = 12 - add; + + if (n > max) { + return this.generateID(max) + this.generateID(n - max); + } + + max = Math.pow(10, n + add); + const min = max / 10; // Math.pow(10, n) basically + const number = Math.floor(Math.random() * (max - min + 1)) + min; + return ('' + number).substring(add); + } + + downloadTemplate(): void { + const fileName = `Vouchers_Template.xls`; + const data: any[] = []; + const columns: string[] = ['Instruction Id', 'Group Code', 'Currency', 'Amount', 'Expiry', 'Functional Id']; + const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, { header: columns }); + const wb: XLSX.WorkBook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, 'vouchers'); + XLSX.writeFile(wb, fileName); + } + sendData(): void { + const requestId: string = this.createVoucherForm.value.requestId; + const callbackUrl: string = this.createVoucherForm.value.callbackUrl; + const payload = { - requestID: uuid(), - batchID: uuid(), + requestID: requestId, + batchID: this.batchID, voucherInstructions: this.voucherInstructions }; - console.log(payload); - this.vouchersService.createVoucher(payload).subscribe((response: any) => { - console.log(response); + this.vouchersService.createVoucher(callbackUrl, payload).subscribe((response: any) => { + const msg = response.responseDescription + '\n Request Id: ' + response.requestID; + this.alertService.alert({ type: 'Voucher File Upload', message: msg }); + this.clearData(); }); } + clearData(): void { + this.voucherInstructions = []; + this.dataSource = new MatTableDataSource(this.voucherInstructions); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + this.totalRows = 0; + this.files = []; + this.createVoucherForm.patchValue({ + 'requestId': this.generateID(12), + 'callbackUrl': environment.backend.voucherCallbackUrl + }); + } + + pageChanged(event: PageEvent) { + this.paginator.pageSize = event.pageSize; + this.currentPage = event.pageIndex; + } } diff --git a/src/app/vouchers/vouchers-routing.module.ts b/src/app/vouchers/vouchers-routing.module.ts index 1959970e..770adba7 100644 --- a/src/app/vouchers/vouchers-routing.module.ts +++ b/src/app/vouchers/vouchers-routing.module.ts @@ -1,18 +1,17 @@ -import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; -import { Route } from "app/core/route/route.service"; -import { VouchersComponent } from "./vouchers/vouchers.component"; -import { extract } from "app/core/i18n/i18n.service"; -import { VoucherManagementComponent } from "./voucher-management/voucher-management.component"; -import { VouchersBulkImportComponent } from "./vouchers-bulk-import/vouchers-bulk-import.component"; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { Route } from 'app/core/route/route.service'; +import { VouchersComponent } from './vouchers/vouchers.component'; +import { VoucherManagementComponent } from './voucher-management/voucher-management.component'; +import { VouchersBulkImportComponent } from './vouchers-bulk-import/vouchers-bulk-import.component'; const routes: Routes = [ Route.withShell([ { - path: "vouchers", + path: 'vouchers', component: VouchersComponent, - data: { title: extract("Voucher Management"), breadcrumb: "Voucher Management" }, + data: { title: 'Voucher Management', breadcrumb: 'Voucher Management' }, children: [ { path: '', diff --git a/src/app/vouchers/vouchers-section-filter/vouchers-section-filter.component.ts b/src/app/vouchers/vouchers-section-filter/vouchers-section-filter.component.ts index 4a17c2af..af86e3dd 100644 --- a/src/app/vouchers/vouchers-section-filter/vouchers-section-filter.component.ts +++ b/src/app/vouchers/vouchers-section-filter/vouchers-section-filter.component.ts @@ -10,15 +10,13 @@ export class VouchersSectionFilterComponent implements OnInit { sections: Section[]; - constructor() { - - } + constructor() { } ngOnInit(): void { this.sections = [ - {label: 'Vouchers', routeTo: ['vouchers', 'voucher-management'], active: true}, - {label: 'Create Vouchers', routeTo: ['vouchers', 'bulk-import'], active: false}, - ]; + { label: 'Vouchers', routeTo: ['vouchers', 'voucher-management'], active: true }, + { label: 'Create Vouchers', routeTo: ['vouchers', 'bulk-import'], active: false }, + ]; } setActive(s: Section): void { diff --git a/src/app/web-app.component.ts b/src/app/web-app.component.ts index 7ec51973..0d716b7d 100644 --- a/src/app/web-app.component.ts +++ b/src/app/web-app.component.ts @@ -22,6 +22,7 @@ import { AlertService } from './core/alert/alert.service'; /** Custom Models */ import { Alert } from './core/alert/alert.model'; import { SettingsService } from './settings/settings.service'; +import { I18nService } from './core/i18n/i18n.service'; /** Initialize Logger */ const log = new Logger('PHEE'); @@ -36,6 +37,8 @@ const log = new Logger('PHEE'); }) export class WebAppComponent implements OnInit { + i18nService: I18nService; + /** * @param {Router} router Router for navigation. * @param {ActivatedRoute} activatedRoute Activated Route. @@ -75,6 +78,8 @@ export class WebAppComponent implements OnInit { } log.debug('init'); + this.i18nService = new I18nService(this.translateService); + // Setup translations this.translateService.addLangs(environment.supportedLanguages.split(',')); log.debug(environment.defaultLanguage); @@ -95,10 +100,13 @@ export class WebAppComponent implements OnInit { mergeMap(route => route.data) ) .subscribe(event => { - const title = event['title']; - if (title) { - this.titleService.setTitle(`${this.translateService.instant(title)} | Payment Hub`); + let title = event['title']; + if (!title) { + title = 'APP_NAME'; } + this.i18nService.translate(title).subscribe((titleTranslated: any) => { + this.titleService.setTitle(titleTranslated); + }); }); // Setup theme @@ -127,7 +135,6 @@ export class WebAppComponent implements OnInit { // this.settingsService.setServers(environment.serverUrls.split(',')); // Set the Tenant Identifier(s) list from the env var this.settingsService.setTenantIdentifier(environment.tenant || 'phdefault'); - } } diff --git a/src/assets/configuration.properties b/src/assets/configuration.properties deleted file mode 100644 index d023a514..00000000 --- a/src/assets/configuration.properties +++ /dev/null @@ -1,6 +0,0 @@ -oauth.enabled false -oauth.serverUrl https://ops-bk.sandbox.fynarfin.io -oauth.basicAuth true -oauth.basicAuthToken Y2xpZW50Og== -serverUrl https://ops-bk.sandbox.fynarfin.io -auth.tenant gorilla diff --git a/src/assets/env.template.js b/src/assets/env.template.js index b0e13cd9..8b6a128e 100644 --- a/src/assets/env.template.js +++ b/src/assets/env.template.js @@ -3,7 +3,11 @@ // BackEnd Environment variables window["env"]["serverApiUrlOps"] = '$PH_OPS_BACKEND_SERVER_URL'; + window["env"]["signatureBatchKey"] = '$PH_OPS_BATCH_KEY'; + window["env"]["bulkConnectorOps"] = '$PH_OPS_BULK_CONNECTOR_URL'; + window["env"]["serverApiUrlVou"] = '$PH_VOU_BACKEND_SERVER_URL'; + window["env"]["callbackUrlVou"] = '$PH_VOU_CALLBACK_URL'; window["env"]["serverApiUrlAct"] = '$PH_ACT_BACKEND_SERVER_URL'; window["env"]["registeringInstitutionId"] = '$PH_REGISTERING_INSTITUTION_ID'; diff --git a/src/assets/styles/_content.scss b/src/assets/styles/_content.scss index 04adcef2..0b56c828 100644 --- a/src/assets/styles/_content.scss +++ b/src/assets/styles/_content.scss @@ -21,3 +21,7 @@ .blue { color: blue; } + +mat-dialog-container { + min-width: 600px; +} \ No newline at end of file diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index 5c00dcfe..d25d7313 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -1,131 +1,117 @@ { - "APP_NAME": "Payment Hub", - "Logged in as": "Logged in as", - "Remember me": "Remember me", - "not_found_subtitle": "Oops.. Looks like this page doesn't exist.", + "APP_NAME": "PHEE - Operations Management", "languages": { "en": "English", - "fr": "French", - "es": "Spanish" + "es": "Spanish", + "fr": "French" }, "labels": { "breadcrumbs": { - "Home": "Home" + "home": "Home", + "batches": "Batches", + "Payment Hub EE": "Payment Hub EE", + "bulk-import": "Bulk Import", + "sub-batches": "Sub Batches", + "transfers": "Transfers", + "Voucher Management": "Voucher Management", + "voucher-management": "Voucher Management", + "Account Mapper": "Account Mapper" }, "buttons": { - "Dashboard": "Dashboard", - "Add": "Add", - "Back": "Back", - "Close": "Close", - "Next": "Next", "Login": "Login", - "Create User": "Create User" + "Forgot Password?": "Forgot Password?", + "Cancel": "Cancel", + "Download Template": "Download Template", + "Send Data": "Send Data", + "Clear Data": "Clear Data", + "Browse Files": "Browse Files", + "Search": "Search", + "Close": "Close" + }, + "errors": { + "Username or password incorrect.": "Username or password incorrect" }, - "commons": { - "is required": "is required" + "heading": { + "View Transfer": "View Transfer" }, "inputs": { + "ID": "ID", + "Transaction ID": "Transaction ID", + "Payer Party": "Payer Party", "Tenant": "Tenant", - "Language": "Language", - "Server": "Server", - "Url": "Url", - "Login": "Login", - "Logout": "Logout", "Username": "Username", "Password": "Password", - "Remember me": "Remember me", - "Filter": "Filter", - "products": { - "loan": { - "Amortization": "Amortization", - "amortizationType": { - "Equal installments": "Equal installments", - "Equal principal payments": "Equal principal payments" - }, - "Is Equal Amortization?": "Is Equal Amortization?" - } - } - }, - "links": { - "Contribute": "Contribute", - "Resources": "Resources", - "Community": "Community", - "User Manual": "User Manual", - "Functional Specifications": "Functional Specifications", - "Developer Zone": "Developer Zone", - "User Group": "User Group", - "Developer Group": "Developer Group", - "IRC": "IRC", - "Key Design Principles": "Key Design Principles", - "Working with Code": "Working with Code", - "Donate": "Donate", - "Forgot Password?": "Forgot Password?" + "Language": "Language", + "Group Code": "Group Code", + "Expiry": "Expiry", + "Request Id": "Request Id", + "URL": "URL", + "Functional Id": "Functional Id", + "Instruction Id": "Instruction Id", + "Institution Id": "Institution Id", + "Program Id": "Program Id", + "Description": "Description", + "Amount": "Amount", + "Currency": "Currency", + "Payment Mode": "Payment Mode", + "SubType": "SubType", + "Credit Party": "Credit Party", + "Debit Party": "Debit Party", + "Request": "Request", + "Filters": "Filters", + "Date Voucher": "Date Voucher", + "Date Voucher Created": "Date Voucher Created", + "Serial Number": "Serial Number", + "Government Entity": "Government Entity", + "Functional ID": "Functional ID", + "Status": "Status", + "From Date": "From Date", + "To Date": "To Date", + "Source Ministry": "Source Ministry", + "Batch Reference Number": "Batch Reference Number", + "Bulk Amount": "Bulk Amount", + "Start Time": "Start Time", + "Completed Time": "Completed Time", + "Payer FSP": "Payer FSP", + "Transaction Type": "Transaction Type", + "Source Financial Institution": "Source Financial Institution", + "Source Account Number": "Source Account Number", + "Destination Account Number": "Destination Account Number", + "Destination Financial Institution": "Destination Financial Institution", + "Transaction Reference Number": "Transaction Reference Number", + "Batch ID": "Batch ID", + "Client Correlation ID": "Client Correlation ID", + "Direction": "Direction", + "Payee Dfsp": "Payee Dfsp", + "Payee Fee": "Payee Fee", + "Payee Party": "Payee Party", + "Payer Dfsp": "Payer Dfsp", + "Financial Address": "Financial Address", + "Financial Institution": "Financial Institution", + "Payment Modality": "Payment Modality" }, "menus": { - "Institution": "Institution", - "Accounting": "Accounting", - "Breadcrumbs": "Breadcrumbs", - "Reports": "Reports", - "Admin": "Admin", - "Self Service": "Self Service", - "Configuration Wizard": "Configuration Wizard", - "Clients": "Clients", - "Groups": "Groups", - "Centers": "Centers", - "All": "All", - "Loans": "Loans", - "Savings": "Savings", - "Funds": "Funds", - "XBRL": "XBRL", - "Users": "Users", - "Organization": "Organization", - "System": "System", - "Products": "Products", - "Templates": "Templates", - "User Management": "User Management", - "App Configuration": "App Configuration", - "Task Management": "Task Management", - "Help": "Help", - "Profile": "Profile", + "Login": "Login", + "Logout": "Logout", "Settings": "Settings", "Sign Out": "Sign Out", - "Global Search": "Global Search", - "Language Selector": "Language Selector", - "Theme Picker": "Theme Picker", - "Application Menu": "Application Menu", - "User Panel": "User Panel", - "Frequently Accessed": "Frequently Accessed", "Dashboard": "Dashboard", - "Navigation": "Navigation", - "Frequent Postings": "Frequent Postings", - "Create Journal Entry": "Create Journal Entry", - "Chart of Accounts": "Chart of Accounts", - "Notifications": "Notifications", - "Main Items": "Main Items", - "Checker Inbox and Tasks": "Checker Inbox and Tasks", - "Individual Collection Sheet": "Individual Collection Sheet", - "Keyboard Shortcuts": "Keyboard Shortcuts" - }, - "placeholders": { - "Add new server": "Add new server", - "Search Activity": "Search Activity" + "Vouchers": "Vouchers", + "Create Vouchers": "Create Vouchers", + "Payment Hub": "Payment Hub", + "Account Management": "Account Management", + "Main Batches": "Main Batches", + "Create Batch": "Create Batch", + "Sub Batches": "Sub Batches", + "Transfers": "Transfers" }, "texts": { - "Welcome": "Welcome", + "Logged in as": "Logged in as", + "About": "About", + "Home": "Home", + "Remember me": "Remember me", "Version": "Version", - "by": "by", - "Login into Tenant": "Login into Tenant" + "Drag and Drop the CSV input file, or": "Drag and Drop the CSV input file, or" } - }, - "errors": { - "inputs": { - "Password is required": "Password is required", - "Username is required": "Username is required", - "Username or password incorrect.": "Username or password incorrect" - } - }, - "tooltips": { - "Settings": "Settings", - "Sign Out": "Sign Out" } } diff --git a/src/environments/environment.kubernetes.ts b/src/environments/environment.kubernetes.ts index 01d72a8d..89a6cb3f 100644 --- a/src/environments/environment.kubernetes.ts +++ b/src/environments/environment.kubernetes.ts @@ -4,24 +4,24 @@ // The list of which env maps to which file can be found in `.angular-cli.json`. // `.env.ts` is generated by the `npm run env` command -import env from "./.env"; +import env from './.env'; export let environment = { - name: "kubernetes", + name: 'kubernetes', production: false, version: env.npm_package_version, - serverUrl: "", + serverUrl: '', oauth: { - enabled: "true", // For connecting to Mifos X using OAuth2 Authentication change the value to true - serverUrl: "https://paymenthub.qa.oneacrefund.org/opsapp", - basicAuth: "true", + enabled: 'true', // For connecting to Mifos X using OAuth2 Authentication change the value to true + serverUrl: 'https://paymenthub.qa.oneacrefund.org/opsapp', + basicAuth: 'true', basicAuthToken: 'Y2xpZW50Og==' }, - defaultLanguage: "en-US", - supportedLanguages: ["en-US", "fr-FR"], - externalConfigurationFile: "configuration.properties", // When provided, the external configuration file content will override this environment settings based on naming conventions + defaultLanguage: 'en-US', + supportedLanguages: ['en-US', 'fr-FR'], + externalConfigurationFile: 'configuration.properties', // When provided, the external configuration file content will override this environment settings based on naming conventions auth: { enabled: false, - tenant: "phdefault" + tenant: 'phdefault' } }; diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 70b16581..4b36bc78 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -4,26 +4,29 @@ // The list of which env maps to which file can be found in `.angular-cli.json`. // `.env.ts` is generated by the `npm run env` command -import env from "./.env"; +import env from './.env'; export let environment = { - name: "prod", + name: 'prod', production: true, version: env.phee.version, backend: { - operations: window['env']['serverApiUrlOps'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - vouchers: window['env']['serverApiUrlVou'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - account: window['env']['serverApiUrlAct'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - registeringInstituionId: window['env']['registeringInstitutionId'] || "default", + operations: window['env']['serverApiUrlOps'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + signatureBatchKey: window['env']['signatureBatchKey'] || '', + bulkConnectorOps: window['env']['bulkConnectorOps'] || 'https://bulk-connector-demo.sandbox.fynarfin.io', + vouchers: window['env']['serverApiUrlVou'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + voucherCallbackUrl: window['env']['callbackUrlVou'] || 'https://webhook.site/', + account: window['env']['serverApiUrlAct'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + registeringInstituionId: window['env']['registeringInstitutionId'] || 'default', }, oauth: { // For connecting to Mifos X using OAuth2 Authentication change the value to true - enabled: window['env']['oauthEnabled'] || false, - type: window['env']['oauthType'] || "keycloak", - serverUrl: window['env']['oauthServerUrl'] || "https://paymenthub.qa.oneacrefund.org/opsapp", - realm: window['env']['oauthRealm'] || "paymenthub", - clientId: window['env']['oauthClientId'] || "opsapp", - clientSecret: window['env']['oauthClientSecret'] || "", + enabled: window['env']['oauthEnabled'] || false, + type: window['env']['oauthType'] || 'keycloak', + serverUrl: window['env']['oauthServerUrl'] || 'https://paymenthub.qa.oneacrefund.org/opsapp', + realm: window['env']['oauthRealm'] || 'paymenthub', + clientId: window['env']['oauthClientId'] || 'opsapp', + clientSecret: window['env']['oauthClientSecret'] || '', basicAuth: window['env']['oauthBasicAuth'] || true, basicAuthToken: window['env']['oauthBasicAuthToken'] || 'Y2xpZW50Og==' }, @@ -32,6 +35,6 @@ export let environment = { }, tenant: window['env']['platformTenantId'] || 'phdefault', tenants: window['env']['platformTenantIds'] || 'phdefault', - defaultLanguage: window['env']['defaultLanguage'] || "en", - supportedLanguages: window['env']['supportedLanguages'] || ["en", "fr"] + defaultLanguage: window['env']['defaultLanguage'] || 'en', + supportedLanguages: window['env']['supportedLanguages'] || ['en', 'fr'] }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index a398bb52..2ae63496 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,26 +4,29 @@ // The list of which env maps to which file can be found in `.angular-cli.json`. // `.env.ts` is generated by the `npm run env` command -import env from "./.env"; +import env from './.env'; export let environment = { - name: "dev", + name: 'dev', production: false, - version: env.phee.version + "-dev", + version: env.phee.version + '-dev', backend: { - operations: window['env']['serverApiUrlOps'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - vouchers: window['env']['serverApiUrlVou'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - account: window['env']['serverApiUrlAct'] || "https://paymenthub.qa.oneacrefund.org/opsapp/api/v1", - registeringInstituionId: window['env']['registeringInstitutionId'] || "default", + operations: window['env']['serverApiUrlOps'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + signatureBatchKey: window['env']['signatureBatchKey'] || '', + bulkConnectorOps: window['env']['bulkConnectorOps'] || 'https://bulk-connector-demo.sandbox.fynarfin.io', + vouchers: window['env']['serverApiUrlVou'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + voucherCallbackUrl: window['env']['callbackUrlVou'] || 'https://webhook.site/', + account: window['env']['serverApiUrlAct'] || 'https://paymenthub.qa.oneacrefund.org/opsapp/api/v1', + registeringInstituionId: window['env']['registeringInstitutionId'] || 'default', }, oauth: { // For connecting to Mifos X using OAuth2 Authentication change the value to true - enabled: window['env']['oauthEnabled'] || false, - type: window['env']['oauthType'] || "keycloak", - serverUrl: window['env']['oauthServerUrl'] || "https://paymenthub.qa.oneacrefund.org/opsapp", - realm: window['env']['oauthRealm'] || "paymenthub", - clientId: window['env']['oauthClientId'] || "opsapp", - clientSecret: window['env']['oauthClientSecret'] || "", + enabled: window['env']['oauthEnabled'] || false, + type: window['env']['oauthType'] || 'keycloak', + serverUrl: window['env']['oauthServerUrl'] || 'https://paymenthub.qa.oneacrefund.org/opsapp', + realm: window['env']['oauthRealm'] || 'paymenthub', + clientId: window['env']['oauthClientId'] || 'opsapp', + clientSecret: window['env']['oauthClientSecret'] || '', basicAuth: window['env']['oauthBasicAuth'] || true, basicAuthToken: window['env']['oauthBasicAuthToken'] || 'Y2xpZW50Og==' }, @@ -32,6 +35,6 @@ export let environment = { }, tenant: window['env']['platformTenantId'] || 'phdefault', tenants: window['env']['platformTenantIds'] || 'phdefault', - defaultLanguage: window['env']['defaultLanguage'] || "en", - supportedLanguages: window['env']['supportedLanguages'] || ["en", "fr"] + defaultLanguage: window['env']['defaultLanguage'] || 'en', + supportedLanguages: window['env']['supportedLanguages'] || ['en', 'fr'] }; diff --git a/src/translations/en-US.json b/src/translations/en-US.json deleted file mode 100644 index 9730f0f4..00000000 --- a/src/translations/en-US.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "APP_NAME": "Payment Hub EE - Operations Management", - "languages": { - "en-US": "English", - "fr-FR": "French" - }, - "labels": { - "buttons": { - "Login": "Login", - "Forgot Password?": "Forgot Password?", - "Cancel": "Cancel" - }, - "errors": { - "Username or password incorrect.": "Username or password incorrect" - }, - "inputs": { - "Tenant": "Tenant", - "Username": "Username", - "Password": "Password", - "Language": "Language" - }, - "menus": { - "Login": "Login", - "Logout": "Logout" - - }, - "texts": { - "Logged in as": "Logged in as", - "About": "About", - "Home": "Home", - "Remember me": "Remember me", - "Version": "Version" - } - } -} diff --git a/src/translations/fr-FR.json b/src/translations/fr-FR.json deleted file mode 100644 index d235f82e..00000000 --- a/src/translations/fr-FR.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "APP_NAME": "MifosX", - "About": "A propos", - "Home": "Accueil", - "Logged in as": "Connecté en tant que", - "Login": "Connexion", - "Logout": "Déconnexion", - "Password": "Mot de passe", - "Password is required": "Mot de passe requis", - "Username": "Identifiant", - "Username is required": "Identifiant requis", - "Username or password incorrect.": "Identifiant ou mot de passe incorrect", - "Remember me": "Rester connecté", - "Version": "Version" -}