feat: add edit provisioning criteria (#1168)

Fixes: #644
This commit is contained in:
Karan Takalkar
2020-08-03 14:20:44 +05:30
committed by GitHub
parent 30abfb4e38
commit ac280d2447
11 changed files with 380 additions and 11 deletions
@@ -0,0 +1,31 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { OrganizationService } from '../../organization.service';
/**
* Provisioning criteria and template resolver.
*/
@Injectable()
export class LoanProvisioningCriteriaAndTemplateResolver implements Resolve<Object> {
/**
* @param {OrganizationService} organizationService Products service.
*/
constructor(private organizationService: OrganizationService) {}
/**
* Returns the Pprovisioning criteria and template data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const provisioningId = route.paramMap.get('id');
return this.organizationService.getProvisioningCriteria(provisioningId, true);
}
}
@@ -44,17 +44,17 @@
<ng-container matColumnDef="minAge">
<th mat-header-cell *matHeaderCellDef> Min Age </th>
<td mat-cell *matCellDef="let definition"> {{ definition.minAge || '-' }} </td>
<td mat-cell *matCellDef="let definition"> {{ definition.minAge || '0' }} </td>
</ng-container>
<ng-container matColumnDef="maxAge">
<th mat-header-cell *matHeaderCellDef> Max Age </th>
<td mat-cell *matCellDef="let definition"> {{ definition.maxAge || '-' }} </td>
<td mat-cell *matCellDef="let definition"> {{ definition.maxAge || '0' }} </td>
</ng-container>
<ng-container matColumnDef="percentage">
<th mat-header-cell *matHeaderCellDef> Percentage (%)</th>
<td mat-cell *matCellDef="let definition"> {{ definition.provisioningPercentage || '-' }} </td>
<td mat-cell *matCellDef="let definition"> {{ definition.provisioningPercentage || '0' }} </td>
</ng-container>
<ng-container matColumnDef="liabilityAccount">
@@ -0,0 +1,94 @@
<div class="container">
<mat-card>
<div>
<form [formGroup]="provisioningCriteriaForm">
<div fxLayout="row" fxLayoutGap="2%">
<mat-form-field fxFlex>
<mat-label>Provisioning Criteria</mat-label>
<input required matInput formControlName="criteriaName">
<mat-error *ngIf="provisioningCriteriaForm.controls.criteriaName.hasError('required')">
Provisioning Criteria is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex>
<mat-label>Selected Products</mat-label>
<mat-select formControlName="loanProducts" [compareWith]="compareOptions" multiple>
<mat-option *ngFor="let product of loanProducts" [value]="product">
{{ product.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</form>
</div>
<div class="mat-elevation-z1">
<mat-hint *ngIf="!provisioningCriteriaFormValid">Please fill all provisioning criteria definitions.</mat-hint>
<table mat-table class="m-t-10" [dataSource]="definitions">
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef> Category </th>
<td mat-cell *matCellDef="let definition"> {{ definition.categoryName }} </td>
</ng-container>
<ng-container matColumnDef="minAge">
<th mat-header-cell *matHeaderCellDef> Min Age </th>
<td mat-cell *matCellDef="let definition"> {{ definition.minAge || '0' }} </td>
</ng-container>
<ng-container matColumnDef="maxAge">
<th mat-header-cell *matHeaderCellDef> Max Age </th>
<td mat-cell *matCellDef="let definition"> {{ definition.maxAge || '0' }} </td>
</ng-container>
<ng-container matColumnDef="percentage">
<th mat-header-cell *matHeaderCellDef> Percentage (%)</th>
<td mat-cell *matCellDef="let definition"> {{ definition.provisioningPercentage || '0' }} </td>
</ng-container>
<ng-container matColumnDef="liabilityAccount">
<th mat-header-cell *matHeaderCellDef> Liability Account </th>
<td mat-cell *matCellDef="let definition"> {{ (definition.liabilityAccount | find:loanProvisioningCriteriaAndTemplate.glAccounts:'id':'name') || '-' }} </td>
</ng-container>
<ng-container matColumnDef="expenseAccount">
<th mat-header-cell *matHeaderCellDef> Expense Account </th>
<td mat-cell *matCellDef="let definition"> {{ (definition.expenseAccount | find:loanProvisioningCriteriaAndTemplate.glAccounts:'id':'name') || '-' }} </td>
</ng-container>
<ng-container matColumnDef="edit">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let definition">
<button mat-button color="primary" (click)="editDefinition(definition)">
<fa-icon icon="edit"></fa-icon>&nbsp;&nbsp;
Edit
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<div class="m-t-20" fxLayout="row" fxLayoutAlign="center" fxLayoutGap="20px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button color="primary" [disabled]="!provisioningCriteriaFormValid" (click)="submit()">Submit</button>
</div>
</mat-card>
</div>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditLoanProvisioningCriteriaComponent } from './edit-loan-provisioning-criteria.component';
describe('EditLoanProvisioningCriteriaComponent', () => {
let component: EditLoanProvisioningCriteriaComponent;
let fixture: ComponentFixture<EditLoanProvisioningCriteriaComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditLoanProvisioningCriteriaComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditLoanProvisioningCriteriaComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,197 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatTableDataSource, MatDialog } from '@angular/material';
import { Router, ActivatedRoute } from '@angular/router';
/** Custom Models */
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
/** Custom Dialogs */
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
/** Custom Services */
import { OrganizationService } from '../../organization.service';
/**
* Edit Loan Provisioning Criteria Component.
*/
@Component({
selector: 'mifosx-edit-loan-provisioning-criteria',
templateUrl: './edit-loan-provisioning-criteria.component.html',
styleUrls: ['./edit-loan-provisioning-criteria.component.scss']
})
export class EditLoanProvisioningCriteriaComponent implements OnInit {
/** Loan Provisioning Criteria form. */
provisioningCriteriaForm: FormGroup;
/** Loan Provisioning Criteria Template */
loanProvisioningCriteriaAndTemplate: any;
/** Liability Accounts */
liabilityAccounts: any;
/** Expense Accounts */
expenseAccounts: any;
/** Loan Products */
loanProducts: any;
/** Columns to be displayed in definitions table. */
displayedColumns: string[] = ['category', 'minAge', 'maxAge', 'percentage', 'liabilityAccount', 'expenseAccount', 'edit'];
/** Criteria Definitions Array */
definitions: {
categoryId: number,
categoryName: string,
maxAge?: number,
minAge?: number,
liabilityAccount?: string,
expenseAccount?: string,
provisioningPercentage?: number
}[] = [];
/**
* Retrieves the offices data from `resolve`.
* @param {FormBuilder} formBuilder Form Builder.
* @param {OrganizationService} organizationService Organization Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
*/
constructor(private formBuilder: FormBuilder,
private organizationService: OrganizationService,
private router: Router,
public dialog: MatDialog,
private route: ActivatedRoute) {
this.route.data.subscribe((data: { loanProvisioningCriteriaAndTemplate: any }) => {
this.loanProvisioningCriteriaAndTemplate = data.loanProvisioningCriteriaAndTemplate;
this.definitions = this.loanProvisioningCriteriaAndTemplate.definitions;
this.loanProducts = this.loanProvisioningCriteriaAndTemplate.loanProducts.concat(this.loanProvisioningCriteriaAndTemplate.selectedLoanProducts);
this.liabilityAccounts = this.loanProvisioningCriteriaAndTemplate.glAccounts.filter((account: any) => account.type.value === 'LIABILITY');
this.expenseAccounts = this.loanProvisioningCriteriaAndTemplate.glAccounts.filter((account: any) => account.type.value === 'EXPENSE');
});
}
ngOnInit() {
this.createProvisioningCriteriaForm();
}
/**
* Creates the provisioning criteria form
*/
createProvisioningCriteriaForm() {
this.provisioningCriteriaForm = this.formBuilder.group({
'criteriaName': [this.loanProvisioningCriteriaAndTemplate.criteriaName, Validators.required],
'loanProducts': [this.loanProvisioningCriteriaAndTemplate.selectedLoanProducts]
});
}
/**
* Compare function for mat-select.
* Useful in patching values if value is an object.
* @param {any} option1 option 1
* @param {any} option2 option 2.
*/
compareOptions(option1: any, option2: any) {
return option1 && option2 && option1.id === option2.id;
}
/**
* Edit Definition
* @param {any} definition Definition
* @param {number} index Definition index
*/
editDefinition(definition: any) {
const data = {
title: 'Edit Criteria Definition',
formfields: this.getDefinitionFormFields(definition),
layout: { addButtonText: 'Confirm' }
};
const editDefinitionDialogRef = this.dialog.open(FormDialogComponent, { data });
editDefinitionDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
const definitionData = {
...definition,
...response.data.value
};
this.definitions.splice(this.definitions.indexOf(definition), 1, definitionData);
this.definitions = this.definitions.concat([]);
}
});
}
/**
* Gets formfields for form dialog.
* @param {any} definition Definition
*/
getDefinitionFormFields(definition: any) {
const formfields: FormfieldBase[] = [];
formfields.push(new InputBase({
controlName: 'minAge',
label: 'Min Age',
value: definition ? definition.minAge : '',
type: 'number',
required: true,
order: 1
}));
formfields.push(new InputBase({
controlName: 'maxAge',
label: 'Max Age',
value: definition ? definition.maxAge : '',
type: 'number',
required: true,
order: 2
}));
formfields.push(new InputBase({
controlName: 'provisioningPercentage',
label: 'Percentage (%)',
value: definition ? definition.provisioningPercentage : '',
type: 'number',
required: true,
order: 3
}));
formfields.push(new SelectBase({
controlName: 'liabilityAccount',
label: 'Liability Account',
value: definition ? definition.liabilityAccount : '',
options: { label: 'name', value: 'id', data: this.liabilityAccounts },
required: true,
order: 4
}));
formfields.push(new SelectBase({
controlName: 'expenseAccount',
label: 'Expense Account',
value: definition ? definition.expenseAccount : '',
options: { label: 'name', value: 'id', data: this.expenseAccounts },
required: true,
order: 5
}));
return formfields;
}
/**
* Returns validity of form.
*/
get provisioningCriteriaFormValid() {
return this.provisioningCriteriaForm.valid;
}
/**
* Edits the loan provisioning criteria.
*/
submit() {
const locale = 'en';
const loanProvisioningCriteria = {
...this.provisioningCriteriaForm.value,
loanProducts: this.provisioningCriteriaForm.get('loanProducts').value.map((product: any) => ({
id: product.id,
name: product.name,
includeInBorrowerCycle: product.includeInBorrowerCycle
})),
definitions: this.definitions,
locale
};
this.organizationService.updateProvisioningCriteria(this.loanProvisioningCriteriaAndTemplate.criteriaId, loanProvisioningCriteria).subscribe((response: any) => {
this.router.navigate(['../'], { relativeTo: this.route });
});
}
}
@@ -3,7 +3,7 @@
<fa-icon icon="edit"></fa-icon>&nbsp;&nbsp;
Edit
</button>
<button mat-raised-button color="warn" (click)="deleteCharge()">
<button mat-raised-button color="warn" (click)="deleteCriteria()">
<fa-icon icon="trash"></fa-icon>&nbsp;&nbsp;
Delete
</button>
@@ -29,7 +29,7 @@
<div>
<table mat-table [dataSource]="dataSource">
<table mat-table class="mat-elevation-z1" [dataSource]="dataSource">
<ng-container matColumnDef="category">
<th mat-header-cell *matHeaderCellDef> Category </th>
@@ -64,11 +64,11 @@ export class ViewLoanProvisioningCriteriaComponent implements OnInit {
/**
* Delete Selected Provisioning Criteria.
*/
deleteCharge() {
const deleteChargeDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `loanProvisioningCriteria ${this.provisioningData.criteriaId}` }
deleteCriteria() {
const deleteCriteriaDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `Loan Provisioning Criteria id: ${this.provisioningData.criteriaId}` }
});
deleteChargeDialogRef.afterClosed().subscribe((response: any) => {
deleteCriteriaDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.organizationService.deleteProvisioningCriteria(this.provisioningData.criteriaId)
.subscribe(() => {
@@ -58,6 +58,7 @@ import { EditCampaignComponent } from './sms-campaigns/edit-campaign/edit-campai
import { CreateEnityDataTableChecksComponent } from './entity-data-table-checks/create-enity-data-table-checks/create-enity-data-table-checks.component';
import { CreateLoanProvisioningCriteriaComponent } from './loan-provisioning-criteria/create-loan-provisioning-criteria/create-loan-provisioning-criteria.component';
import { BulkLoanReassignmnetComponent } from './bulk-loan-reassignmnet/bulk-loan-reassignmnet.component';
import {EditLoanProvisioningCriteriaComponent } from './loan-provisioning-criteria/edit-loan-provisioning-criteria/edit-loan-provisioning-criteria.component';
/** Custom Resolvers */
import { LoanProvisioningCriteriaResolver } from './loan-provisioning-criteria/common-resolvers/loan-provisioning-criteria.resolver';
@@ -95,6 +96,7 @@ import { BulkImportResolver } from './bulk-import/bulk-import.resolver';
import { SmsCampaignTemplateResolver } from './sms-campaigns/common-resolvers/sms-campaign-template.resolver';
import { EntityDataTableChecksTemplateResolver } from './entity-data-table-checks/enitity-data-table-checks-template.resolver';
import { LoanProvisioningCriteriaTemplateResolver } from './loan-provisioning-criteria/common-resolvers/loan-provisioning-criteria-template.resolver';
import { LoanProvisioningCriteriaAndTemplateResolver } from './loan-provisioning-criteria/common-resolvers/loan-provisioning-criteria-and-template.resolver';
/** Organization Routes */
const routes: Routes = [
@@ -137,6 +139,14 @@ const routes: Routes = [
loanProvisioningCriteria: LoanProvisioningCriteriaResolver
}
},
{
path: 'edit',
component: EditLoanProvisioningCriteriaComponent,
data: { title: extract('Edit Provisioning Criteria'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
resolve: {
loanProvisioningCriteriaAndTemplate: LoanProvisioningCriteriaAndTemplateResolver
}
}
]
}
],
@@ -652,7 +662,8 @@ const routes: Routes = [
HolidayResolver,
EntityDataTableChecksTemplateResolver,
LoanProvisioningCriteriasResolver,
LoanProvisioningCriteriaTemplateResolver
LoanProvisioningCriteriaTemplateResolver,
LoanProvisioningCriteriaAndTemplateResolver
]
})
export class OrganizationRoutingModule { }
@@ -65,6 +65,7 @@ import { EditBusinessRuleParametersComponent } from './sms-campaigns/sms-campaig
import { CreateEnityDataTableChecksComponent } from './entity-data-table-checks/create-enity-data-table-checks/create-enity-data-table-checks.component';
import { BulkLoanReassignmnetComponent } from './bulk-loan-reassignmnet/bulk-loan-reassignmnet.component';
import { CreateLoanProvisioningCriteriaComponent } from './loan-provisioning-criteria/create-loan-provisioning-criteria/create-loan-provisioning-criteria.component';
import { EditLoanProvisioningCriteriaComponent } from './loan-provisioning-criteria/edit-loan-provisioning-criteria/edit-loan-provisioning-criteria.component';
/**
* Organization Module
@@ -136,6 +137,7 @@ import { CreateLoanProvisioningCriteriaComponent } from './loan-provisioning-cri
CreateEnityDataTableChecksComponent,
BulkLoanReassignmnetComponent,
CreateLoanProvisioningCriteriaComponent,
EditLoanProvisioningCriteriaComponent,
]
})
export class OrganizationModule { }
+10 -1
View File
@@ -42,13 +42,22 @@ export class OrganizationService {
}
/**
* @param {any} Criteria Provisioning Criteria to be created.
* @param {any} criteriaData Provisioning Criteria to be created.
* @returns {Observable<any>}
*/
createProvisioningCriteria(criteriaData: any): Observable<any> {
return this.http.post('/provisioningcriteria', criteriaData);
}
/**
* @param {any} criteriaId Criteria Id
* @param {any} criteriaData Provisioning Criteria to be created.
* @returns {Observable<any>}
*/
updateProvisioningCriteria(criteriaId: any, criteriaData: any): Observable<any> {
return this.http.put(`/provisioningcriteria/${criteriaId}`, criteriaData);
}
/**
* @param {string} provisioningId Provisioning ID of provisioning criteria to be deleted.
* @returns {Observable<any>}