Transactions tab standarization

This commit is contained in:
Jose Alberto Hernandez
2024-03-30 19:04:56 -06:00
committed by Jose Alberto Hernandez
parent dab5ceec9d
commit 54dc91e0e2
54 changed files with 757 additions and 353 deletions
+13
View File
@@ -16,6 +16,19 @@ import { OptionData } from 'app/shared/models/option-data.model';
return ['NONE', 'Cash', 'Accrual (periodic)', 'Accrual (upfront)'];
}
public getAccountRuleName(value: string): string {
if (value === 'ACCRUAL PERIODIC') {
return 'Accrual (periodic)';
} else if (value === 'ACCRUAL UPFRONT') {
return 'Accrual (upfront)';
} else if (value === 'CASH BASED') {
return 'Cash';
} else if (value === 'NONE') {
return 'None';
}
return '';
}
public isNoneAccounting(accountingRule: OptionData): boolean {
return (accountingRule.id === 1);
}
@@ -6,6 +6,8 @@
<h3>{{"labels.heading.All Transactions" | translate }}</h3>
</div>
<div class="action-button m-b-20" fxLayout="row" fxLayoutGap="20px" *ngIf="checkStatus()">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals">
{{"labels.inputs.Hide Reversed" | translate}}</mat-checkbox>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="accruals">
{{"labels.inputs.Hide Accruals" | translate}}</mat-checkbox>
</div>
@@ -20,50 +22,55 @@
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.ID" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.id }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" (click)="showTransactions(transaction)"> {{ transaction.id }} </td>
</ng-container>
<ng-container matColumnDef="transactionDate">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Transaction Date" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.date | dateFormat }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" > {{ transaction.date | dateFormat }} </td>
</ng-container>
<ng-container matColumnDef="transactionType">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Transaction Type" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.transactionType.value }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" > {{ transaction.transactionType.value }} </td>
</ng-container>
<ng-container matColumnDef="debit">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Debit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ isDebit(transaction.transactionType) ? transaction.amount : 'N/A'}} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" > {{ isDebit(transaction.transactionType) ? transaction.amount : 'N/A'}} </td>
</ng-container>
<ng-container matColumnDef="credit">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Credit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ !isDebit(transaction.transactionType) ? transaction.amount : 'N/A' }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" > {{ !isDebit(transaction.transactionType) ? transaction.amount : 'N/A' }} </td>
</ng-container>
<ng-container matColumnDef="balance">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Balance" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.runningBalance }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" > {{ transaction.runningBalance }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Actions" | translate }} </th>
<td mat-cell class="center" *matCellDef="let transaction">
<button class="account-action-button" mat-raised-button color="primary" (click)="routeEdit($event)" [routerLink]="[transaction.id, 'reciept']">
<i class="fa fa-file" matTooltip="View Reciept"></i>
</button>
<button class="account-action-button" mat-raised-button color="primary" matTooltip="View Journal Entries"
matTooltipPosition="left" (click)="routeEdit($event)"
[routerLink]="['/','journal-entry', 'view', 'S'+transaction.id ]">
<i class="fa fa-arrow-circle-right"></i>
<button mat-icon-button [matMenuTriggerFor]="transactionMenu" aria-label="" class="action-button">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #transactionMenu="matMenu">
<button mat-menu-item (click)="showTransactions(transaction)">
<mat-icon><fa-icon icon="eye" size="sm"></fa-icon></mat-icon>
<span>{{ 'labels.text.View Transaction' | translate}}</span>
</button>
<button mat-menu-item (click)="routeEdit($event)" [routerLink]="['/','journal-entry', 'view', 'S'+transaction.id ]">
<mat-icon><fa-icon icon="table-cells" size="sm"></fa-icon></mat-icon>
<span>{{ 'tooltips.View Journal Entries' | translate}}</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row" (click)="showTransactions(row)"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row"></tr>
</table>
@@ -33,18 +33,3 @@
}
}
}
.active {
background-color: $status-active;
height: 4px;
}
.linked {
background-color: $status-approved;
height: 4px;
}
.undo {
background-color: $status-active-overdue;
height: 4px;
}
@@ -1,8 +1,12 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { SavingsAccountTransaction } from 'app/savings/models/savings-account-transaction.model';
/**
* Transactions Tab Component.
@@ -13,18 +17,19 @@ import { ActivatedRoute, Router } from '@angular/router';
styleUrls: ['./transactions-tab.component.scss']
})
export class TransactionsTabComponent implements OnInit {
accountId: string;
status: any;
/** Transactions Data */
transactionsData: any;
/** Temporary Transaction Data */
tempTransaction: any;
/** Form control to handle accural parameter */
hideAccrualsParam: UntypedFormControl;
hideReversedParam: UntypedFormControl;
/** Columns to be displayed in transactions table. */
displayedColumns: string[] = ['row', 'id', 'transactionDate', 'transactionType', 'debit', 'credit', 'balance', 'actions'];
/** Data source for transactions table. */
dataSource: MatTableDataSource<any>;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
/**
* Retrieves fixed deposits account data from `resolve`.
@@ -32,28 +37,19 @@ export class TransactionsTabComponent implements OnInit {
* @param {Router} router Router
*/
constructor(private route: ActivatedRoute,
private router: Router) {
private router: Router,
public dialog: MatDialog) {
this.route.parent.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.transactionsData = data.fixedDepositsAccountData.transactions;
this.tempTransaction = this.transactionsData;
this.accountId = this.route.parent.snapshot.params['fixedDepositAccountId'];
this.status = data.fixedDepositsAccountData.status.value;
});
}
ngOnInit() {
this.hideAccrualsParam = new UntypedFormControl(false);
this.hideReversedParam = new UntypedFormControl(false);
this.dataSource = new MatTableDataSource(this.transactionsData);
if (this.tempTransaction) {
this.tempTransaction.forEach((element: any) => {
if (this.isAccrual(element.transactionType)) {
this.tempTransaction = this.removeItem(this.tempTransaction, element);
}
});
}
}
private removeItem(arr: any, item: any) {
return arr.filter((f: any) => f !== item);
}
/**
@@ -88,25 +84,36 @@ export class TransactionsTabComponent implements OnInit {
}
}
transactionColor(transaction: any): string {
hideAccruals() {
this.filterTransactions(this.hideReversedParam.value, !this.hideAccrualsParam.value);
}
hideReversed() {
this.filterTransactions(!this.hideReversedParam.value, this.hideAccrualsParam.value);
}
filterTransactions(hideReversed: boolean, hideAccrual: boolean): void {
let transactions: SavingsAccountTransaction[] = this.transactionsData;
if (hideAccrual || hideReversed) {
transactions = this.transactionsData.filter((t: SavingsAccountTransaction) => {
return (!(hideReversed && t.reversed) && !(hideAccrual && t.transactionType.accrual));
});
}
this.dataSource = new MatTableDataSource(transactions);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
savingsTransactionColor(transaction: SavingsAccountTransaction): string {
if (transaction.reversed) {
return 'strike';
}
if (this.isAccrual(transaction.transactionType)) {
} else if (transaction.transfer) {
return 'transfer';
} else if (transaction.transactionType.accrual) {
return 'accrual';
}
return '';
}
private isAccrual(transactionType: any): boolean {
return (transactionType.accrual);
}
hideAccruals() {
if (!this.hideAccrualsParam.value) {
this.dataSource = new MatTableDataSource(this.tempTransaction);
} else {
this.dataSource = new MatTableDataSource(this.transactionsData);
return '';
}
}
@@ -118,4 +125,7 @@ export class TransactionsTabComponent implements OnInit {
$event.stopPropagation();
}
undoTransaction(transactionData: SavingsAccountTransaction): void {
}
}
@@ -64,57 +64,9 @@
{{ transactionData.note }}
</div>
<ng-container *ngIf="transactionData.paymentDetailData">
<div *ngIf="transactionData.paymentDetailData.paymentType" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Payment Type" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.paymentType" fxFlex="50%">
{{ transactionData.paymentDetailData.paymentType.name }}
</div>
<div *ngIf="transactionData.paymentDetailData.accountNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Account No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.accountNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.accountNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.checkNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Cheque Number" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.checkNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.checkNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.routingCode" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Routing Code" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.routingCode" fxFlex="50%">
{{ transactionData.paymentDetailData.routingCode }}
</div>
<div *ngIf="transactionData.paymentDetailData.receiptNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Receipt No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.receiptNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.receiptNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.bankNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Bank No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.bankNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.bankNumber }}
</div>
</ng-container>
<mifosx-transaction-payment-detail *ngIf="transactionData.paymentDetailData"
[paymentDetailData]="transactionData.paymentDetailData">
</mifosx-transaction-payment-detail>
</div>
@@ -6,6 +6,8 @@
<h3>{{"labels.heading.All Transactions" | translate }}</h3>
</div>
<div class="action-button m-b-20" fxLayout="row" fxLayoutGap="20px" *ngIf="checkStatus()">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals">
{{"labels.inputs.Hide Reversed" | translate}}</mat-checkbox>
<mat-checkbox [formControl]="hideAccrualsParam" (click)="hideAccruals()" class="accruals">
{{"labels.inputs.Hide Accruals" | translate}}</mat-checkbox>
</div>
@@ -20,38 +22,57 @@
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.ID" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.id }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)" (click)="showTransactions(transaction)"> {{ transaction.id }} </td>
</ng-container>
<ng-container matColumnDef="transactionDate">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Transaction Date" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.date | dateFormat }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)"> {{ transaction.date | dateFormat }} </td>
</ng-container>
<ng-container matColumnDef="transactionType">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Transaction Type" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.transactionType.value }} </td>
<td mat-cell *matCellDef="let transaction" [ngClass]="savingsTransactionColor(transaction)"> {{ transaction.transactionType.value }} </td>
</ng-container>
<ng-container matColumnDef="debit">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Debit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}">
<th mat-header-cell *matHeaderCellDef class="center"> {{"labels.inputs.Debit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" class="r-amount" [ngClass]="savingsTransactionColor(transaction)">
{{ isDebit(transaction.transactionType) ? transaction.amount : 'N/A'}} </td>
</ng-container>
<ng-container matColumnDef="credit">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Credit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}">
<th mat-header-cell *matHeaderCellDef class="center"> {{"labels.inputs.Credit" | translate }} </th>
<td mat-cell *matCellDef="let transaction" class="r-amount" [ngClass]="savingsTransactionColor(transaction)">
{{ !isDebit(transaction.transactionType) ? transaction.amount : 'N/A' }} </td>
</ng-container>
<ng-container matColumnDef="balance">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Balance" | translate }} </th>
<td mat-cell *matCellDef="let transaction" [ngClass]="{'strike': transaction.reversed}"> {{ transaction.runningBalance }} </td>
<th mat-header-cell *matHeaderCellDef class="center"> {{"labels.inputs.Balance" | translate }} </th>
<td mat-cell *matCellDef="let transaction" class="r-amount" [ngClass]="savingsTransactionColor(transaction)"> {{ transaction.runningBalance | formatNumber }} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> {{"labels.inputs.Actions" | translate }} </th>
<td mat-cell class="center" *matCellDef="let transaction">
<button mat-icon-button [matMenuTriggerFor]="transactionMenu" aria-label="" class="action-button">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #transactionMenu="matMenu">
<button mat-menu-item (click)="showTransactions(transaction)">
<mat-icon><fa-icon icon="eye" size="sm"></fa-icon></mat-icon>
<span>{{ 'labels.text.View Transaction' | translate}}</span>
</button>
<button mat-menu-item (click)="routeEdit($event)" [routerLink]="['/','journal-entry', 'view', 'S'+transaction.id ]">
<mat-icon><fa-icon icon="table-cells" size="sm"></fa-icon></mat-icon>
<span>{{ 'tooltips.View Journal Entries' | translate}}</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row" (click)="showTransactions(row)"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row" ></tr>
</table>
@@ -1,3 +1,5 @@
@import "assets/styles/helper";
.tab-container {
padding: 1%;
margin: 1%;
@@ -23,8 +25,3 @@
}
}
}
.strike {
text-decoration: line-through;
color: red;
}
@@ -1,8 +1,11 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router';
import { SavingsAccountTransaction } from 'app/savings/models/savings-account-transaction.model';
/**
* Transactions Tab Component.
@@ -18,14 +21,15 @@ export class TransactionsTabComponent implements OnInit {
status: any;
/** Transactions Data */
transactionsData: any;
/** Temporary Transaction Data */
tempTransaction: any;
/** Form control to handle accural parameter */
hideAccrualsParam: UntypedFormControl;
hideReversedParam: UntypedFormControl;
/** Columns to be displayed in transactions table. */
displayedColumns: string[] = ['row', 'id', 'transactionDate', 'transactionType', 'debit', 'credit', 'balance'];
displayedColumns: string[] = ['row', 'id', 'transactionDate', 'transactionType', 'debit', 'credit', 'balance', 'actions'];
/** Data source for transactions table. */
dataSource: MatTableDataSource<any>;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
/**
* Retrieves recurring deposits account data from `resolve`.
@@ -35,7 +39,6 @@ export class TransactionsTabComponent implements OnInit {
private router: Router) {
this.route.parent.data.subscribe((data: { recurringDepositsAccountData: any }) => {
this.transactionsData = data.recurringDepositsAccountData.transactions;
this.tempTransaction = this.transactionsData;
this.status = data.recurringDepositsAccountData.status.value;
});
}
@@ -43,17 +46,7 @@ export class TransactionsTabComponent implements OnInit {
ngOnInit() {
this.dataSource = new MatTableDataSource(this.transactionsData);
this.hideAccrualsParam = new UntypedFormControl(false);
if (this.tempTransaction) {
this.tempTransaction.forEach((element: any) => {
if (this.isAccrual(element.transactionType)) {
this.tempTransaction = this.removeItem(this.tempTransaction, element);
}
});
}
}
private removeItem(arr: any, item: any) {
return arr.filter((f: any) => f !== item);
this.hideReversedParam = new UntypedFormControl(false);
}
/**
@@ -65,15 +58,36 @@ export class TransactionsTabComponent implements OnInit {
|| transactionType.overdraftInterest === true || transactionType.withholdTax === true;
}
isAccrual(transactionType: any): boolean {
return (transactionType.accrual || transactionType.code === 'savingsAccountTransactionType.accrual');
hideAccruals() {
this.filterTransactions(this.hideReversedParam.value, !this.hideAccrualsParam.value);
}
hideAccruals() {
if (!this.hideAccrualsParam.value) {
this.dataSource = new MatTableDataSource(this.tempTransaction);
hideReversed() {
this.filterTransactions(!this.hideReversedParam.value, this.hideAccrualsParam.value);
}
filterTransactions(hideReversed: boolean, hideAccrual: boolean): void {
let transactions: SavingsAccountTransaction[] = this.transactionsData;
if (hideAccrual || hideReversed) {
transactions = this.transactionsData.filter((t: SavingsAccountTransaction) => {
return (!(hideReversed && t.reversed) && !(hideAccrual && t.transactionType.accrual));
});
}
this.dataSource = new MatTableDataSource(transactions);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
savingsTransactionColor(transaction: SavingsAccountTransaction): string {
if (transaction.reversed) {
return 'strike';
} else if (transaction.transfer) {
return 'transfer';
} else if (transaction.transactionType.accrual) {
return 'accrual';
} else {
this.dataSource = new MatTableDataSource(this.transactionsData);
return '';
}
}
@@ -92,7 +106,7 @@ export class TransactionsTabComponent implements OnInit {
* Show Transactions Details
* @param transactionsData Transactions Data
*/
showTransactions(transactionsData: any) {
showTransactions(transactionsData: SavingsAccountTransaction) {
if (transactionsData.transfer) {
this.router.navigate([`../transfer-funds/account-transfers/${transactionsData.transfer.id}`], { relativeTo: this.route });
} else {
@@ -61,7 +61,7 @@
</div>
<div fxFlex="50%">
{{ transactionData.amount }}
{{ transactionData.amount | currency:transactionData.currency.code:'symbol-narrow':'1.2-2'}}
</div>
<div fxFlex="50%" *ngIf="transactionData.note" class="mat-body-strong">
@@ -72,57 +72,9 @@
{{ transactionData.note }}
</div>
<ng-container *ngIf="transactionData.paymentDetailData">
<div *ngIf="transactionData.paymentDetailData.paymentType" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Payment Type" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.paymentType" fxFlex="50%">
{{ transactionData.paymentDetailData.paymentType.name }}
</div>
<div *ngIf="transactionData.paymentDetailData.accountNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Account No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.accountNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.accountNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.checkNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Cheque Number" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.checkNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.checkNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.routingCode" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Routing Code" | translate }}
</div>
<div *ngIf="transactionData.paymentDetailData.routingCode" fxFlex="50%">
{{ transactionData.paymentDetailData.routingCode }}
</div>
<div *ngIf="transactionData.paymentDetailData.receiptNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Receipt No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.receiptNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.receiptNumber }}
</div>
<div *ngIf="transactionData.paymentDetailData.bankNumber" fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Bank No" | translate }}.
</div>
<div *ngIf="transactionData.paymentDetailData.bankNumber" fxFlex="50%">
{{ transactionData.paymentDetailData.bankNumber }}
</div>
</ng-container>
<mifosx-transaction-payment-detail *ngIf="transactionData.paymentDetailData"
[paymentDetailData]="transactionData.paymentDetailData">
</mifosx-transaction-payment-detail>
</div>
@@ -1,3 +1,5 @@
@import "assets/styles/helper";
.container {
max-width: 37rem;
@@ -6,5 +8,25 @@
margin: 1rem 0;
word-wrap: break-word;
}
mifosx-transaction-payment-detail {
width: 100%;
margin-bottom: 20px;
}
}
}
.active {
background-color: $status-active;
height: 4px;
}
.linked {
background-color: $status-approved;
height: 4px;
}
.undo {
background-color: $status-active-overdue;
height: 4px;
}
@@ -73,7 +73,7 @@ export class ViewTransactionComponent {
}
transactionColor(): string {
if (this.transactionData.manuallyReversed) {
if (this.transactionData.reversed) {
return 'undo';
}
return 'active';
@@ -49,8 +49,8 @@
<mat-checkbox [formControl]="changeRepaymentDate"> {{"labels.inputs.Change Repayment Date" | translate}} </mat-checkbox>
<ng-container *ngIf="changeRepaymentDate.value" (click)="installmentrescheduledDatePicker.open()">
<mat-form-field>
<ng-container *ngIf="changeRepaymentDate.value">
<mat-form-field (click)="installmentrescheduledDatePicker.open()">
<mat-label>{{"labels.inputs.Installment Rescheduled to" | translate}}</mat-label>
<input matInput [min]="minDate" [matDatepicker]="installmentrescheduledDatePicker"
formControlName="adjustedDueDate">
@@ -10,8 +10,11 @@
<mat-form-field fxFlex="calc(90%-20px)">
<mat-label>{{ 'labels.inputs.Currency' | translate }}</mat-label>
<mat-select required formControlName="currency">
<mat-option *ngFor="let currency of currencyData" [value]="currency">
{{ currency.name }}
<mat-option>
<ngx-mat-select-search [formControl]="filterFormCtrl"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let currency of currencyData | async" [value]="currency">
({{currency.code}}) {{ currency.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="currencyForm.controls.currency.hasError('required')">
@@ -1,8 +1,8 @@
/** Angular Imports */
import { Component, OnInit, TemplateRef, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { Component, OnInit, TemplateRef, ElementRef, ViewChild, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { MatDialog } from '@angular/material/dialog';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormControl, Validators } from '@angular/forms';
/** Custom Dialogs */
import { DeleteDialogComponent } from '../../../shared/delete-dialog/delete-dialog.component';
@@ -14,6 +14,9 @@ import { ConfigurationWizardService } from '../../../configuration-wizard/config
/** Custom Dialog Component */
import { ContinueSetupDialogComponent } from '../../../configuration-wizard/continue-setup-dialog/continue-setup-dialog.component';
import { takeUntil } from 'rxjs/operators';
import { ReplaySubject, Subject } from 'rxjs';
import { Currency } from 'app/shared/models/general.model';
/**
* Manage Currencies component.
@@ -23,12 +26,12 @@ import { ContinueSetupDialogComponent } from '../../../configuration-wizard/cont
templateUrl: './manage-currencies.component.html',
styleUrls: ['./manage-currencies.component.scss']
})
export class ManageCurrenciesComponent implements OnInit, AfterViewInit {
export class ManageCurrenciesComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
/** Selected Currencies data. */
selectedCurrencies: any[];
/** Currency options data */
currencyData: any;
currencyList: Currency[] = [];
/** Currency form */
currencyForm: any;
@@ -37,6 +40,15 @@ export class ManageCurrenciesComponent implements OnInit, AfterViewInit {
@ViewChild('currencyFormRef') currencyFormRef: ElementRef<any>;
@ViewChild('templateCurrencyFormRef') templateCurrencyFormRef: TemplateRef<any>;
/** Currency data. */
protected currencyData: ReplaySubject<Currency[]> = new ReplaySubject<Currency[]>(1);
/** control for the filter select */
protected filterFormCtrl: UntypedFormControl = new UntypedFormControl('');
/** Subject that emits when the component has been destroyed. */
protected _onDestroy = new Subject<void>();
/**
* Retrieves the currency data from `resolve`.
* @param {ActivatedRoute} route Activated Route
@@ -53,14 +65,30 @@ export class ManageCurrenciesComponent implements OnInit, AfterViewInit {
private popoverService: PopoverService) {
this.route.parent.data.subscribe(( data: { currencies: any }) => {
this.selectedCurrencies = data.currencies.selectedCurrencyOptions;
this.currencyData = data.currencies.currencyOptions;
this.currencyList = data.currencies.currencyOptions;
});
}
ngOnInit() {
this.filterFormCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.searchItem();
});
this.createCurrencyForm();
}
ngOnDestroy(): void {
this._onDestroy.next();
this._onDestroy.complete();
}
ngOnChanges(changes: SimpleChanges): void {
if (this.currencyList) {
this.currencyData.next(this.currencyList.slice());
}
}
/**
* Creates the currency form.
*/
@@ -70,6 +98,20 @@ export class ManageCurrenciesComponent implements OnInit, AfterViewInit {
});
}
searchItem(): void {
if (this.currencyList) {
const search: string = this.filterFormCtrl.value.toLowerCase();
if (!search) {
this.currencyData.next(this.currencyList.slice());
} else {
this.currencyData.next(this.currencyList.filter((option: Currency) => {
return option.name.toLowerCase().indexOf(search) >= 0 || option.code.toLowerCase().indexOf(search) >= 0;
}));
}
}
}
/**
* Adds a new currency to the list.
*/
@@ -1,11 +1,11 @@
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
<button mat-raised-button color="primary" [routerLink]="['edit']" *mifosxHasPermission="'UPDATE_CASHIER'">
<fa-icon icon="edit" class="m-r-10"></fa-icon>
Edit
{{'labels.buttons.Edit' | translate}}
</button>
<button mat-raised-button color="warn" (click)="deleteCashier()" *mifosxHasPermission="'DELETECASHIER_TELLER'">
<fa-icon icon="trash" class="m-r-10"></fa-icon>
Delete
{{'labels.buttons.Delete' | translate}}
</button>
</div>
@@ -19,7 +19,7 @@
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="header">
Name
{{'labels.inputs.Name' | translate}}
</div>
<div fxFlex="50%">
@@ -27,7 +27,7 @@
</div>
<div fxFlex="50%" class="header">
Teller
{{'labels.inputs.Teller' | translate}}
</div>
<div fxFlex="50%">
@@ -35,7 +35,7 @@
</div>
<div fxFlex="50%" class="header" *ngIf="cashierData.description !== ''">
Description
{{'labels.inputs.Description' | translate}}
</div>
<div fxFlex="50%" *ngIf="cashierData.description !== ''">
@@ -43,7 +43,7 @@
</div>
<div fxFlex="50%" class="header">
Start Date
{{'labels.inputs.Start Date' | translate}}
</div>
<div fxFlex="50%">
@@ -51,7 +51,7 @@
</div>
<div fxFlex="50%" class="header">
End Date
{{'labels.inputs.End Date' | translate}}
</div>
<div fxFlex="50%">
@@ -59,7 +59,7 @@
</div>
<div fxFlex="50%" class="header">
Full Day?
{{'labels.inputs.Full Day?' | translate}}
</div>
<div fxFlex="50%">
@@ -69,7 +69,9 @@
</div>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['..']">{{"labels.buttons.Back" | translate}}</button>
</mat-card-actions>
</mat-card>
</div>
@@ -1,6 +1,14 @@
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
<!--
<button mat-raised-button color="primary" *mifosxHasPermission="'UPDATE_LOANPRODUCT'" (click)="copyProduct()">
<fa-icon icon="copy" class="m-r-10"></fa-icon>{{'labels.buttons.Create' | translate}} {{'labels.text.Copy' | translate}}
</button>
-->
<button mat-raised-button color="primary" *mifosxHasPermission="'UPDATE_LOANPRODUCT'" (click)="exportDefinition()">
<fa-icon icon="download" class="m-r-10"></fa-icon>{{'labels.buttons.Export' | translate}}
</button>
<button mat-raised-button color="primary" [routerLink]="['../edit']" *mifosxHasPermission="'UPDATE_LOANPRODUCT'">
<fa-icon icon="edit" class="m-r-10"></fa-icon>Edit
<fa-icon icon="edit" class="m-r-10"></fa-icon>{{'labels.buttons.Edit' | translate}}
</button>
</div>
@@ -1,6 +1,13 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { LoanProduct } from '../../models/loan-product.model';
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { TranslateService } from '@ngx-translate/core';
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
@Component({
selector: 'mifosx-general-tab',
@@ -12,7 +19,12 @@ export class GeneralTabComponent implements OnInit {
loanProduct: LoanProduct;
useDueForRepaymentsConfigurations = false;
constructor(private route: ActivatedRoute) {
constructor(private route: ActivatedRoute,
private router: Router,
private dialog: MatDialog,
private productsService: ProductsService,
private settingsService: SettingsService,
private translateService: TranslateService) {
this.route.data.subscribe((data: { loanProduct: any }) => {
this.loanProduct = data.loanProduct;
this.useDueForRepaymentsConfigurations = (!this.loanProduct.dueDaysForRepaymentEvent && !this.loanProduct.overDueDaysForRepaymentEvent);
@@ -23,4 +35,88 @@ export class GeneralTabComponent implements OnInit {
this.loanProduct.allowAttributeConfiguration = Object.values(this.loanProduct.allowAttributeOverrides).some((attribute: boolean) => attribute);
}
exportDefinition(): void {
const product = this.loanProduct;
delete product['id'];
const fileName: string = product.name.replace(' ', '_') + '.json';
const link = document.createElement('a');
link.setAttribute('href', 'data:text/plain;charset=utf-u,' + encodeURIComponent(JSON.stringify(product, null, 2)));
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
copyProduct(): void {
const productNameTmp = `${this.loanProduct.name.replace(' ', '_')}_${this.translateService.instant('labels.text.Copy')}`;
const productCopy = JSON.parse(JSON.stringify(this.loanProduct));
const formfields: FormfieldBase[] = [
new InputBase({
controlName: 'name',
label: this.translateService.instant('labels.inputs.Name'),
value: productNameTmp,
type: 'text',
required: true,
order: 2
}),
new InputBase({
controlName: 'shortName',
label: this.translateService.instant('labels.inputs.Short Name'),
value: '',
type: 'text',
required: true,
order: 2
}),
];
const data = {
title: `${this.translateService.instant('labels.buttons.Create')} ${this.translateService.instant('labels.inputs.Loan Product')}`,
layout: { addButtonText: this.translateService.instant('labels.buttons.Create') },
formfields: formfields
};
const createProductDialogRef = this.dialog.open(FormDialogComponent, { data });
createProductDialogRef.afterClosed().subscribe((productResponse: any) => {
if (productResponse.data) {
productCopy['name'] = productResponse.data.value['name'];
productCopy['shortName'] = productResponse.data.value['shortName'];
productCopy['delinquencyBucketId'] = productCopy['delinquencyBucket'] ? productCopy['delinquencyBucket']['id'] : null;
productCopy['currencyCode'] = productCopy['currency'] ? productCopy['currency']['code'] : null;
productCopy['interestRatePerPeriod'] = productCopy['annualInterestRate'];
productCopy['transactionProcessingStrategyCode'] = productCopy['transactionProcessingStrategyName'];
productCopy['allowPartialPeriodInterestCalcualtion'] = productCopy['allowPartialPeriodInterestCalculation'];
productCopy['locale'] = this.settingsService.language.code;
let valueTmp: any = productCopy['daysInMonthType']['value'];
productCopy['daysInMonthType'] = valueTmp;
valueTmp = productCopy['daysInYearType']['value'];
productCopy['daysInYearType'] = valueTmp;
valueTmp = productCopy['amortizationType']['id'];
productCopy['amortizationType'] = valueTmp;
delete productCopy['id'];
delete productCopy['advancedPaymentAllocationTransactionTypes'];
delete productCopy['advancedPaymentAllocationTypes'];
delete productCopy['creditAllocationTransactionTypes'];
delete productCopy['creditAllocationAllocationTypes'];
delete productCopy['delinquencyBucketOptions'];
delete productCopy['allowAttributeConfiguration'];
delete productCopy['status'];
delete productCopy['delinquencyBucket'];
delete productCopy['currency'];
delete productCopy['isRatesEnabled'];
delete productCopy['annualInterestRate'];
delete productCopy['transactionProcessingStrategyName'];
delete productCopy['allowPartialPeriodInterestCalculation'];
delete productCopy['advancedPaymentAllocationFutureInstallmentAllocationRules'];
this.productsService.createLoanProduct(productCopy)
.subscribe((response: any) => {
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
});
}
});
}
}
@@ -3,7 +3,7 @@
<div class="mat-elevation-z1 m-b-25" [hidden]="!accountWithTransactions">
<div fxLayout="row" fxLayoutAlign="start">
<div class="m-b-10">
<h3>{{"labels.headings.All Transactions" | translate }}</h3>
<h3>{{"labels.heading.All Transactions" | translate }}</h3>
</div>
<div class="action-button m-b-20" fxLayout="row" fxLayoutGap="20px" *ngIf="checkStatus()">
<mat-checkbox [formControl]="hideReversedParam" (click)="hideReversed()" class="accruals">
@@ -25,12 +25,3 @@
}
}
}
.strike {
text-decoration: line-through;
color: red;
}
.transfer {
color: $status-transfer;
}
@@ -26,8 +26,6 @@ export class TransactionsTabComponent implements OnInit {
status: any;
/** Transactions Data */
transactionsData: SavingsAccountTransaction[] = [];
/** Temporary Transaction Data */
tempTransaction: any;
/** Form control to handle accural parameter */
hideAccrualsParam: UntypedFormControl;
hideReversedParam: UntypedFormControl;
@@ -54,7 +52,6 @@ export class TransactionsTabComponent implements OnInit {
private dateUtils: Dates) {
this.route.parent.parent.data.subscribe((data: { savingsAccountData: any }) => {
this.transactionsData = data.savingsAccountData.transactions;
this.tempTransaction = this.transactionsData;
this.status = data.savingsAccountData.status.value;
});
this.accountId = this.route.parent.parent.snapshot.params['savingAccountId'];
@@ -71,17 +68,6 @@ export class TransactionsTabComponent implements OnInit {
this.accountWithTransactions = (this.transactionsData && this.transactionsData.length > 0);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
if (this.tempTransaction) {
this.tempTransaction.forEach((element: any) => {
if (this.isAccrual(element.transactionType)) {
this.tempTransaction = this.removeItem(this.tempTransaction, element);
}
});
}
}
private removeItem(arr: any, item: any) {
return arr.filter((f: any) => f !== item);
}
/**
@@ -129,21 +115,19 @@ export class TransactionsTabComponent implements OnInit {
}
hideAccruals() {
if (!this.hideAccrualsParam.value) {
this.dataSource = new MatTableDataSource(this.tempTransaction);
} else {
this.dataSource = new MatTableDataSource(this.transactionsData);
}
this.filterTransactions(this.hideReversedParam.value, !this.hideAccrualsParam.value);
}
hideReversed() {
this.filterTransactions(!this.hideReversedParam.value, this.hideAccrualsParam.value);
}
filterTransactions(hideReversed: boolean, hideAccrual: boolean): void {
let transactions: SavingsAccountTransaction[] = this.transactionsData;
if (!this.hideReversedParam.value) {
transactions = [];
this.transactionsData.forEach((t: SavingsAccountTransaction) => {
if (!t.reversed) {
transactions.push(t);
}
if (hideAccrual || hideReversed) {
transactions = this.transactionsData.filter((t: SavingsAccountTransaction) => {
return (!(hideReversed && t.reversed) && !(hideAccrual && t.transactionType.accrual));
});
}
this.dataSource = new MatTableDataSource(transactions);
@@ -154,11 +138,13 @@ export class TransactionsTabComponent implements OnInit {
savingsTransactionColor(transaction: SavingsAccountTransaction): string {
if (transaction.reversed) {
return 'strike';
}
if (transaction.transfer) {
} else if (transaction.transfer) {
return 'transfer';
} else if (transaction.transactionType.accrual) {
return 'accrual';
} else {
return '';
}
return '';
}
undoTransaction(transactionData: SavingsAccountTransaction): void {
@@ -29,6 +29,8 @@
<mat-card-content>
<div fxLayout="row wrap" class="content">
<div fxFlex="100%" [ngClass]="transactionColor()">
</div>
<div fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Id" | translate}}
@@ -59,15 +61,15 @@
</div>
<div fxFlex="50%">
{{ transactionData.currency.name }}
{{ transactionData.currency.displayLabel }}
</div>
<div fxFlex="50%" class="mat-body-strong">
{{"labels.inputs.Amount" | translate}}
{{"labels.inputs.Amount" | translate }}
</div>
<div fxFlex="50%">
{{ transactionData.amount | currency:transactionData.currency.code }}
{{ transactionData.amount | currency:transactionData.currency.code:'symbol-narrow':'1.2-2' }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="transactionData.note">
@@ -1,3 +1,5 @@
@import "assets/styles/helper";
.container {
max-width: 37rem;
.content {
@@ -12,3 +14,18 @@
}
}
}
.active {
background-color: $status-active;
height: 4px;
}
.linked {
background-color: $status-approved;
height: 4px;
}
.undo {
background-color: $status-active-overdue;
height: 4px;
}
@@ -71,4 +71,10 @@ export class SavingsTransactionGeneralTabComponent implements OnInit {
});
}
transactionColor(): string {
if (this.transactionData.reversed) {
return 'undo';
}
return 'active';
}
}
@@ -2,7 +2,7 @@
<nav mat-tab-nav-bar class="navigation-tabs">
<a mat-tab-link [routerLink]="['./general']" routerLinkActive #general="routerLinkActive"
[active]="general.isActive">
General
{{'labels.heading.General' | translate}}
</a>
<ng-container *ngFor="let entityDatatable of entityDatatables">
<a mat-tab-link [routerLink]="['./datatables',entityDatatable.registeredTableName]" routerLinkActive
@@ -2,7 +2,7 @@
<div fxFlexFill *ngIf="accountingRule" fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">{{'labels.inputs.Type' | translate}}:</span>
<span fxFlex="60%">{{'labels.accounting.' + accountingRule.value | translate}}</span>
<span fxFlex="60%">{{'labels.accounting.' + getAccountingRuleName(accountingRule.value) | translate}}</span>
</div>
<div fxFlexFill *ngIf="isCashOrAccrualAccounting()" fxLayout="row wrap" fxLayout.lt-md="column">
@@ -31,4 +31,8 @@ export class ViewSavingsAccountingDetailsComponent implements OnInit {
return false;
}
getAccountingRuleName(value: string): string {
return this.accounting.getAccountRuleName(value);
}
}
@@ -9,6 +9,6 @@
</div>
<mat-dialog-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
<button mat-raised-button mat-dialog-close>{{ layout.cancelButtonText }}</button>
<button mat-raised-button color="primary" [mat-dialog-close]="{ data: form }" [disabled]="!form.valid || form.pristine">{{ layout.addButtonText }}</button>
<button mat-raised-button mat-dialog-close>{{ 'labels.buttons.' + layout.cancelButtonText | translate }}</button>
<button mat-raised-button color="primary" [mat-dialog-close]="{ data: form }" [disabled]="!form.valid || form.pristine">{{ 'labels.buttons.' + layout.addButtonText | translate }}</button>
</mat-dialog-actions>
@@ -1,13 +1,13 @@
<mat-card class="container-card">
<mat-card-content>
<mat-tab-group #tabGroup mat-align-tabs="center" (selectedTabChange)="onJobTabChange($event)">
<mat-tab label="Scheduler Jobs">
<mat-tab label="{{title('Scheduler Jobs')}}">
<mifosx-manage-scheduler-jobs></mifosx-manage-scheduler-jobs>
</mat-tab>
<mat-tab label="Workflow Jobs">
<mat-tab label="{{title('Workflow Jobs')}}">
<mifosx-workflow-jobs></mifosx-workflow-jobs>
</mat-tab>
<mat-tab label="COB">
<mat-tab label="{{title('COB')}}">
<mifosx-cob-workflow [isCatchUpRunning]="isCatchUpRunning"></mifosx-cob-workflow>
</mat-tab>
</mat-tab-group>
@@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { MatTabChangeEvent } from '@angular/material/tabs';
import { SystemService } from '../system.service';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'mifosx-manage-jobs',
@@ -11,7 +12,8 @@ export class ManageJobsComponent implements OnInit {
/** Process running flag */
isCatchUpRunning = true;
constructor(private systemService: SystemService) { }
constructor(private systemService: SystemService,
private translateService: TranslateService) { }
ngOnInit(): void {
}
@@ -24,4 +26,8 @@ export class ManageJobsComponent implements OnInit {
}
}
title(label: string) {
return this.translateService.instant('labels.inputs.' + label);
}
}
@@ -1,8 +1,8 @@
<div>
<h2>Job: {{ displayName }}</h2>
<h2>{{'labels.inputs.Job' | translate}}: {{ displayName }}</h2>
<table mat-table [dataSource]="updatedJobParameters">
<ng-container matColumnDef="parameterName">
<th mat-header-cell *matHeaderCellDef>Parameter Name</th>
<th mat-header-cell *matHeaderCellDef>{{'labels.inputs.Parameter Name' | translate}}</th>
<td mat-cell *matCellDef="let element; index as i">
<mat-form-field>
<input matInput type="text" placeholder="Parameter Name" [(ngModel)]="element.parameterName" />
@@ -11,7 +11,7 @@
</ng-container>
<ng-container matColumnDef="parameterValue">
<th mat-header-cell *matHeaderCellDef>Parameter Value</th>
<th mat-header-cell *matHeaderCellDef>{{'labels.inputs.Parameter Value' | translate}}</th>
<td mat-cell *matCellDef="let element; index as i">
<mat-form-field>
<input matInput type="text" placeholder="Parameter Value" [(ngModel)]="element.parameterValue" />
@@ -36,6 +36,6 @@
<button mat-button (click)="addParameter()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>
Add Parameter
{{'labels.buttons.Add Parameter' | translate}}
</button>
</div>
@@ -0,0 +1,27 @@
<h2 mat-dialog-title><span class="m-r-10">{{'labels.inputs.Job Name' | translate}}:</span>{{job.displayName}}</h2>
<mat-dialog-content>
<table class="m-b-5">
<tbody>
<tr class="m-b-20">
<td class="header">{{'labels.inputs.Start Time' | translate}}</td>
<td>{{job.lastRunHistory.jobRunStartTime | datetimeFormat}}</td>
<td class="header">{{'labels.inputs.End Time' | translate}}</td>
<td>{{job.lastRunHistory.jobRunEndTime | datetimeFormat}}</td>
</tr>
<tr>
<td colspan="4" class="message">
<div #content class="note-field" [class.show]="show" [class.note-text]="content.scrollHeight > 18">
<span>{{job.lastRunHistory.jobRunErrorLog}}</span>
</div>
<button mat-flat-button *ngIf="content.scrollHeight > 18" class="show-button" (click)="show = !show">
{{ buttonLabel() }}
</button>
</td>
</tr>
</tbody>
</table>
</mat-dialog-content>
<mat-dialog-actions align="center">
<button mat-raised-button mat-dialog-close>{{"labels.buttons.Close" | translate}}</button>
</mat-dialog-actions>
@@ -0,0 +1,47 @@
.message {
height: auto;
font-weight: 500;
}
tr {
padding-bottom: 10px;
}
span:not(.note){
font-size: .9rem;
line-height: 14px
}
.note-text {
height: 7.95rem;
overflow: hidden;
display: inline-block;
position: relative;
text-align: left;
}
.note-field:not(.show)::after {
content: '...';
padding-left: .5rem;
position: absolute;
right: 0;
bottom: 0;
}
.show {
overflow: visible;
text-overflow: none;
height: auto;
}
button {
background: transparent;
font-size: small;
border: none;
padding: 0;
cursor: pointer;
}
button:hover {
text-decoration: none;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorLogPopoverComponent } from './error-log-popover.component';
describe('ErrorLogPopoverComponent', () => {
let component: ErrorLogPopoverComponent;
let fixture: ComponentFixture<ErrorLogPopoverComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ErrorLogPopoverComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ErrorLogPopoverComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,34 @@
import { Component, Inject, OnInit } from '@angular/core';
import { SchedulerJob } from '../models/scheduler-job.model';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
interface ErrorJobDataType {
job: SchedulerJob;
}
@Component({
selector: 'mifosx-error-log-popover',
templateUrl: './error-log-popover.component.html',
styleUrls: ['./error-log-popover.component.scss']
})
export class ErrorLogPopoverComponent implements OnInit {
show = false;
/* Initialize Selected Job */
job: SchedulerJob;
constructor(@Inject(MAT_DIALOG_DATA) public data: ErrorJobDataType,
private translateService: TranslateService) { }
ngOnInit(): void {
this.job = this.data.job;
}
buttonLabel(): string {
const label: string = this.show ? 'Show less' : 'Show more';
return this.translateService.instant('labels.buttons.' + label);
}
}
@@ -1,15 +1,15 @@
<div class="container m-b-20 space-top" fxLayout="row" fxLayoutGap="20px">
<div #schedulerStatus>
<h2 class="no-m">Scheduler Status:<span class="m-l-20 m-r-20">{{ schedulerActive ? 'Active' : 'Inactive' }}</span>
<h2 class="no-m">{{'labels.heading.Scheduler Status' | translate}}:<span class="m-l-20 m-r-20">{{ schedulerActive ? 'Active' : 'Inactive' }}</span>
</h2>
</div>
<button mat-raised-button class="suspend" (click)="suspendScheduler()" *ngIf="schedulerActive">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
Suspend
{{'labels.buttons.Suspend' | translate}}
</button>
<button mat-raised-button class="activate" (click)="activateScheduler()" *ngIf="!schedulerActive">
<fa-icon icon="times-circle" class="m-r-10"></fa-icon>
Activate
{{'labels.buttons.Activate' | translate}}
</button>
</div>
@@ -23,14 +23,18 @@
</mat-form-field>
</div>
<div class="container space-top" fxLayout="row" fxLayoutGap="20px">
<div class="space-top" fxLayout="row" fxLayoutGap="20px">
<button mat-raised-button color="primary" (click)="runSelectedJobs()" [disabled]="!isAnyJobSelected()">
<fa-icon icon="play" class="m-r-10"></fa-icon>
Run Selected Jobs
{{'labels.buttons.Run Selected Jobs' | translate}}
</button>
<button mat-raised-button color="primary" (click)="openCustomParametersDialog()" [disabled]="!isAnyJobSelected()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>
Add Custom Parameters
{{'labels.buttons.Add Custom Parameters' | translate}}
</button>
<button mat-raised-button color="primary" (click)="refresh()">
<fa-icon icon="sync" class="m-r-10"></fa-icon>
{{'labels.buttons.Refresh' | translate}}
</button>
</div>
@@ -53,12 +57,12 @@
</ng-container>
<ng-container matColumnDef="displayName">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let job"> {{ job.displayName }} </td>
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Name' | translate}} </th>
<td mat-cell *matCellDef="let job" [routerLink]="[job.jobId]"> {{ job.displayName }} </td>
</ng-container>
<ng-container matColumnDef="active">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Active ? </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Active' | translate}}</th>
<td mat-cell *matCellDef="let job" class="center">
<div [className]="job.active === true ? 'currently-running' : 'not-currently-running'">
<fa-icon matTooltip="{{ job.active === true | yesNo }}" matTooltipPosition="right" icon="circle"
@@ -67,31 +71,27 @@
</td>
</ng-container>
<ng-container matColumnDef="nextRunTime">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Next Run </th>
<td mat-cell *matCellDef="let job"> {{ job.nextRunTime }} </td>
</ng-container>
<ng-container matColumnDef="previousRunTime">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Previous Run </th>
<td mat-cell *matCellDef="let job"><span *ngIf="job.lastRunHistory">{{ job.lastRunHistory.jobRunStartTime
}}</span></td>
</ng-container>
<ng-container matColumnDef="previousRunStatus">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Previous Run Status </th>
<td mat-cell *matCellDef="let job" class="center">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Previous Run' | translate}} </th>
<td mat-cell *matCellDef="let job">
<div *ngIf="job.lastRunHistory">
<fa-icon *ngIf="job.lastRunHistory.status === 'success'" class="success" matTooltip="Successful"
matTooltipPosition="right" icon="check-circle" size="lg"></fa-icon>
<fa-icon *ngIf="!(job.lastRunHistory.status == 'success')" class="fail" matTooltip="Failed"
matTooltipPosition="right" icon="times-circle" size="lg"></fa-icon>
<span *ngIf="job.lastRunHistory" class="m-l-5">
{{ job.lastRunHistory.jobRunStartTime | datetimeFormat}}</span>
</div>
</td>
</ng-container>
<ng-container matColumnDef="nextRunTime">
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Next Run' | translate}} </th>
<td mat-cell *matCellDef="let job"> {{ job.nextRunTime | datetimeFormat }} </td>
</ng-container>
<ng-container matColumnDef="currentlyRunning">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Currently Running </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Currently Running' | translate}} </th>
<td mat-cell *matCellDef="let job" class="center">
<div [className]="job.currentlyRunning === true ? 'currently-running' : 'not-currently-running'">
<fa-icon matTooltip="{{ job.currentlyRunning === true | yesNo }}" matTooltipPosition="right"
@@ -101,10 +101,10 @@
</ng-container>
<ng-container matColumnDef="errorLog">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Error Log </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{'labels.inputs.Error Log' | translate}} </th>
<td mat-cell *matCellDef="let job" class="center">
<button mat-icon-button class="errorlog"
*ngIf="!(job.lastRunHistory && job.lastRunHistory.status == 'success')" matTooltip="Error Log"
<button mat-icon-button class="errorlog" (click)="showErrorLog(job)"
*ngIf="!(job.lastRunHistory && job.lastRunHistory.status == 'success')" matTooltip="{{'labels.inputs.Error Log' | translate}}"
matTooltipPosition="right">
<fa-icon icon="exclamation-circle" size="lg"></fa-icon>
</button>
@@ -112,7 +112,7 @@
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [routerLink]="[row.jobId]" class="select-row"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row"></tr>
</table>
@@ -125,7 +125,7 @@
<div class="container space-top" fxLayout="row" fxLayoutGap="20px">
<button mat-raised-button color="primary" (click)="runSelectedJobs()" [disabled]="!isAnyJobSelected()">
<fa-icon icon="play" class="m-r-10"></fa-icon>
Run Selected Jobs<ng-template #templateSchedulerJobs let-data let-popover="popover">
{{'labels.buttons.Run Selected Jobs' | translate}}<ng-template #templateSchedulerJobs let-data let-popover="popover">
<h2>Template</h2>
<p>This is the template I am trying to use. Is that fine.</p>
<button (click)="popover.close();nextStepSchedulerJobs()">Next</button>
@@ -133,7 +133,7 @@
</button>
<button mat-raised-button color="primary" (click)="refresh()">
<fa-icon icon="sync" class="m-r-10"></fa-icon>
Refresh
{{'labels.buttons.Refresh' | translate}}
</button>
</div>
@@ -141,10 +141,10 @@
<h4>Scheduler Status. Button will be used to change the status.</h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">Close</button>
<button mat-raised-button color="primary" (click)="popover.close();previousStep()">Back</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();previousStep()">{{'labels.buttons.Back' | translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">Next</button>
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Next' | translate}}</button>
</div>
</ng-template>
@@ -152,11 +152,11 @@
<h4>Search bar to filter jobs.</h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">Close</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateSchedulerStatus,schedulerStatus, 'bottom', true)">Back</button>
(click)="popover.close();showPopover(templateSchedulerStatus,schedulerStatus, 'bottom', true)">{{'labels.buttons.Back' | translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateJobsTable,jobsTable, 'top', true)">Next</button>
(click)="popover.close();showPopover(templateJobsTable,jobsTable, 'top', true)">{{'labels.buttons.Next' | translate}}</button>
</div>
</ng-template>
@@ -166,9 +166,9 @@
Jobs</a></h4>
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column">
<button mat-raised-button color="warn"
(click)="popover.close();configurationWizardService.closeConfigWizard()">Close</button>
(click)="popover.close();configurationWizardService.closeConfigWizard()">{{'labels.buttons.Close' | translate}}</button>
<button mat-raised-button color="primary"
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">Back</button>
<button mat-raised-button color="primary" (click)="popover.close();nextStep()">Next</button>
(click)="popover.close();showPopover(templateFilter, filter, 'bottom', true)">{{'labels.buttons.Back' | translate}}</button>
<button mat-raised-button color="primary" (click)="popover.close();nextStep()">{{'labels.buttons.Next' | translate}}</button>
</div>
</ng-template>
@@ -39,3 +39,8 @@ table {
.space-top {
margin-top: 30px;
}
.cdk-column-displayName,
.mat-column-displayName {
flex: 0 0 5px !important;
}
@@ -17,6 +17,8 @@ import { ConfigurationWizardService } from '../../../configuration-wizard/config
/** Custom Dialog Component */
import { NextStepDialogComponent } from '../../../configuration-wizard/next-step-dialog/next-step-dialog.component';
import { CustomParametersPopoverComponent } from './custom-parameters-popover/custom-parameters-popover.component';
import { SchedulerJob } from './models/scheduler-job.model';
import { ErrorLogPopoverComponent } from './error-log-popover/error-log-popover.component';
/**
* Manage scheduler jobs component.
@@ -33,7 +35,7 @@ export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
/** Scheduler data */
schedulerData: any;
/** Columns to be displayed in manage scheduler jobs table. */
displayedColumns: string[] = ['select', 'displayName', 'active', 'nextRunTime', 'previousRunTime', 'previousRunStatus', 'currentlyRunning', 'errorLog'];
displayedColumns: string[] = ['select', 'displayName', 'active', 'previousRunTime', 'currentlyRunning', 'nextRunTime', 'errorLog'];
/** Data source for manage scheduler jobs table. */
dataSource: MatTableDataSource<any>;
/** Initialize Selection */
@@ -252,4 +254,14 @@ export class ManageSchedulerJobsComponent implements OnInit, AfterViewInit {
});
}
showErrorLog(job: SchedulerJob): void {
if (job.lastRunHistory) {
this.dialog.open(ErrorLogPopoverComponent, {
data: {
job: job
}
});
}
}
}
@@ -0,0 +1,19 @@
export interface SchedulerJob {
jobId: number;
displayName: string;
nextRunTime: Date;
cronExpression: string;
active: boolean;
currentlyRunning: boolean;
lastRunHistory: LastRunHistory;
}
export interface LastRunHistory {
version: number;
jobRunStartTime: Date;
jobRunEndTime: Date;
status: string;
jobRunErrorMessage: string;
triggerType: string;
jobRunErrorLog: string;
}
+3 -1
View File
@@ -74,6 +74,7 @@ import { CobWorkflowComponent } from './manage-jobs/cob-workflow/cob-workflow.co
import { LoanLockedComponent } from './manage-jobs/cob-workflow/loan-locked/loan-locked.component';
import { CustomParametersPopoverComponent } from './manage-jobs/scheduler-jobs/custom-parameters-popover/custom-parameters-popover.component';
import { CustomParametersTableComponent } from './manage-jobs/scheduler-jobs/custom-parameters-popover/custom-parameters-table/custom-parameters-table.component';
import { ErrorLogPopoverComponent } from './manage-jobs/scheduler-jobs/error-log-popover/error-log-popover.component';
@NgModule({
imports: [
@@ -147,7 +148,8 @@ import { CustomParametersTableComponent } from './manage-jobs/scheduler-jobs/cus
CobWorkflowComponent,
LoanLockedComponent,
CustomParametersPopoverComponent,
CustomParametersTableComponent
CustomParametersTableComponent,
ErrorLogPopoverComponent
],
})
export class SystemModule { }