Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[87] - Enhancements to Payment Hub Operations Web #98

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ xcuserdata/
*.sublime-workspace

# IDE - VSCode
.vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
Expand Down
16 changes: 16 additions & 0 deletions env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export PH_VOU_CALLBACK_URL=https://webhook.site/

PH_ACT_BACKEND_SERVER_URL=https://paymenthub.qa.oneacrefund.org/opsapp/api/v1

export PH_G2P_PAYMENT_CONFIG_URL=https://gateway.mifos.community/v1.0/g2p-payment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variables to which backend service must point?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new service containing g2p configuration with operations like fetch govt entity, fsps , programs and g2p config.
Basically previously the g2p config was coming from a yaml file under budget account

https://github.com/openMF/ph-ee-bulk-processor/blob/9bf984fcf16105081ff53936f72405814ef8ba71/src/main/resources/application.yaml#L160-L161C1
So I have developed a new API as suggested by my mentor for it so we can configure it properly instead of changing the yaml file.

Currently it's working independently as a new service
In future we need to connect it with payment bulk processing


export PH_PLATFORM_TENANT_ID=phdefault

export PH_PLATFORM_TENANT_IDS=phdefault
Expand All @@ -27,10 +29,24 @@ export PH_OAUTH_CLIENT_ID=opsapp

export PH_OAUTH_CLIENT_SECRET=Y2xpZW50Og=

export PH_OAUTH_CLIENT_UUUID=Y2xpZW50Og=

export PH_OAUTH_BASIC_AUTH=true

export PH_OAUTH_BASIC_AUTH_TOKEN=Y2xpZW50Og==

export PH_JBPM_API_URL=http://localhost:8180/kie-server/services/rest/server
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is the helm chart that must be deployed to this endpoint? Why it is pointing to localhost instead of a DNS of the API Gateway?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in the frontend we needed some tool for handling maker checker process of user creation so we have used a buisness process management called JBPM.


export PH_JBPM_CONTAINER_ID=PaymentHubEE_1.0.0-SNAPSHOT

export PH_JBPM_CREDENTIALS_ADMIN_MAKER=Y2xpZW50Og==
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add instructions to create the secrets on K8s?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are environment variables required for using jbpm rest api services


export PH_JBPM_CREDENTIALS_ADMIN_CHECKER=Y2xpZW50Og==
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add instructions to create the secrets on K8s?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dipandhali2021 can you do this?


export PH_JBPM_CREDENTIALS_BOTH=Y2xpZW50Og==

export PH_GRAFANA_DASHBOARD_URL=http://localhost:3000/d/keycloak/keycloak-metrics?orgId=1&refresh=5s&theme=light&kiosk=tv&fullscreen=true&refresh=5s&from=now-5m&to=now

export PH_DEFAULT_LANGUAGE=en

export PH_SUPPORTED_LANGUAGES=en,fr,es
52 changes: 43 additions & 9 deletions src/app/account-mapper/account-mapper-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,55 @@
/** Angular Imports */
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

/** Custom Services */
import { Route } from 'app/core/route/route.service';
import { AccountMapperComponent } from './account-mapper/account-mapper.component';

/** Custom Components */
import { AccountMapperComponent } from './account-mapper/account-mapper.component';
import { BeneficiariesComponent } from './beneficiaries/beneficiaries.component';
import { CreateBeneficiariesComponent } from './create-beneficiaries/create-beneficiaries.component';

/**
* Account Mapper Routes
*/
const routes: Routes = [
Route.withShell([
Route.withShell([
{
path: 'dashboard',
children: [
{
path: 'account-mapper',
component: AccountMapperComponent,
data: { title: 'Account Mapper', breadcrumb: 'Account Mapper' },
children: [
]
}
])
path: 'account-mapper',
component: AccountMapperComponent,
data: { title: 'Account Mapper', breadcrumb: 'Account Mapper' },
children: [
{
path: "",
redirectTo: "beneficiaries",
pathMatch: "full",
},
{
path: "beneficiaries",
component: BeneficiariesComponent,
data: { breadcrumb: { skip: true } },
},
{
path: "create-beneficiaries",
component: CreateBeneficiariesComponent,
data: { breadcrumb: { skip: true } },
},
],
},
],
},
]),
];

/**
* Account Mapper Routing Module
*
* Configures the routes for the Account Mapper Module
*/
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
Expand Down
18 changes: 15 additions & 3 deletions src/app/account-mapper/account-mapper.module.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
/** Angular Imports */
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

/** Custom Components */
import { AccountMapperComponent } from './account-mapper/account-mapper.component';
import { FilterSelectorComponent } from './filter-selector/filter-selector.component';
import { CreateBeneficiariesComponent } from './create-beneficiaries/create-beneficiaries.component';
import { BeneficiariesComponent } from './beneficiaries/beneficiaries.component';

/** Custom Modules */
import { SharedModule } from 'app/shared/shared.module';
import { PipesModule } from 'app/pipes/pipes.module';
import { AccountMapperRoutingModule } from './account-mapper-routing.module';



/**
* Account Mapper Module
*/
@NgModule({
declarations: [
AccountMapperComponent
AccountMapperComponent,
FilterSelectorComponent,
CreateBeneficiariesComponent,
BeneficiariesComponent
],
imports: [
AccountMapperRoutingModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,84 +1,6 @@
<div class="container" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">

<mat-accordion class="filter-options">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<h3 class="m-r-10">{{"labels.inputs.Filters" | translate}}</h3>
<fa-icon icon="filter" size="xl"></fa-icon>
</mat-panel-title>

</mat-expansion-panel-header>
<div class="container" fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">

<mat-form-field fxFlex="20%">
<mat-label>{{"labels.inputs.Financial Institution" | translate}}</mat-label>
<input matInput [formControl]="financialInstitution">
</mat-form-field>

<mat-form-field fxFlex="20%">
<mat-label>{{"labels.inputs.Functional ID" | translate}}</mat-label>
<input matInput [formControl]="functionalId">
</mat-form-field>

<mat-form-field fxFlex="20%">
<mat-label>{{"labels.inputs.Financial Address" | translate}}</mat-label>
<input matInput [formControl]="financialAddress">
</mat-form-field>

<div fxFlex="20%" class="push-end m-t-15">
<button mat-raised-button color="primary" (click)="searchAccounts()">
<fa-icon icon="search" class="m-r-10"></fa-icon> {{"labels.buttons.Search" | translate}}
</button>
</div>

</div>

</mat-expansion-panel>
</mat-accordion>

<mat-card class="container">
<mat-progress-bar mode="indeterminate" *ngIf="isLoading"></mat-progress-bar>

<table mat-table [dataSource]="dataSource" matSort *ngIf="!isLoading">

<ng-container matColumnDef="governmentEntity">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{"labels.inputs.Government Entity" | translate}} </th>
<td mat-cell *matCellDef="let item"> {{item.registeringInstitutionId }} </td>
</ng-container>

<ng-container matColumnDef="financialInstitution">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{"labels.inputs.Financial Institution" | translate}} </th>
<td mat-cell *matCellDef="let item" >{{ item.bankingInstitutionCode }} </td>
</ng-container>

<ng-container matColumnDef="functionalId">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{"labels.inputs.Functional ID" | translate}} </th>
<td mat-cell *matCellDef="let item"> {{ item.payeeIdentity }} </td>
</ng-container>

<ng-container matColumnDef="financialAddress">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{"labels.inputs.Financial Address" | translate}} </th>
<td mat-cell *matCellDef="let item">
<mifosx-identifier identifier="{{item.financialAddress}}"></mifosx-identifier>
</td>
</ng-container>

<ng-container matColumnDef="paymentModality">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{"labels.inputs.Payment Modality" | translate}} </th>
<td mat-cell *matCellDef="let item"> {{paymentModalityDescription(item.paymentModality)}} </td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
class="select-row"></tr>

</table>

<mat-paginator #paginator [pageSize]="pageSize" [pageIndex]="currentPage" (page)="pageChanged($event)"
[pageSizeOptions]="[50, 100, 200]" [length]="totalRows" showFirstLastButtons>
</mat-paginator>

</mat-card>

<div class="container">
<div fxLayout="row" fxLayout.lt-md="column" class="account-wrap">
<mifosx-filter-selector></mifosx-filter-selector>
</div>
<router-outlet></router-outlet>
</div>
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
.container {
width: 80%;
}

.account-mapper-wrap {
flex-wrap: wrap;
width: 100%;

mifosx-batches,
mifosx-sub-batches,
mifosx-filter-selector {
width: 100%;
}

width: 90%;
}

.filter-options {
width: 100%;
margin-bottom: 20px;
}
.account-wrap {
flex-wrap: wrap;
width: 100%;

.push-end {
text-align: end;
mifosx-voucher-management,
mifosx-vouchers-bulk-import,
mifosx-filter-selector {
width: 100%;
}
}
89 changes: 2 additions & 87 deletions src/app/account-mapper/account-mapper/account-mapper.component.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,8 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { AccountMapperService } from '../services/account-mapper.service';
import { UntypedFormControl } from '@angular/forms';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { AccountData } from '../models/account-mapper.model';
import { Dates } from 'app/core/utils/dates';
import { Component } from '@angular/core';

@Component({
selector: 'mifosx-account-mapper',
templateUrl: './account-mapper.component.html',
styleUrls: ['./account-mapper.component.scss']
})
export class AccountMapperComponent implements OnInit {

@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;

/** government Entity form control. */
governmentEntity = new UntypedFormControl();
/** financial Institution form control. */
financialInstitution = new UntypedFormControl();
/** functional Id form control. */
functionalId = new UntypedFormControl();
/** financial Address form control. */
financialAddress = new UntypedFormControl();

/** Columns to be displayed in transactions table. */
displayedColumns: string[] = ['governmentEntity', 'financialInstitution', 'functionalId', 'financialAddress', 'paymentModality'];
/** Data source for transactions table. */
dataSource = new MatTableDataSource();

totalRows = 0;
currentPage = 0;
pageSize = 10;
isLoading = false;

accountsData: AccountData;

constructor(private dates: Dates,
private accountMapperService: AccountMapperService) { }

ngOnInit(): void {
this.getAccounts();
}

getAccounts(): void {
this.isLoading = true;
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) => {
this.isLoading = false;
});
}

convertTimestampToUTCDate(timestamp: any) {
if (!timestamp) {
return undefined;
}
return this.dates.formatUTCDate(new Date(timestamp));
}

pageChanged(event: PageEvent) {
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 {

}
}
export class AccountMapperComponent {}
Loading