feat: add edit loan product component (#451)

- Update loan product stepper components to support editing
- Add edit loan product component
- Add pristine property to form dialog

Fixes: #439
This commit is contained in:
Abhay Chawla
2019-12-01 23:20:51 +03:00
parent 8bb4fd5b59
commit f37dcd3a5a
22 changed files with 531 additions and 101 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ export class ChargesFilterPipe implements PipeTransform {
transform(charges: any, chargesDataSource: any, currencyCode: string, multiDisburseLoan?: boolean): any {
if (charges) {
charges = charges.filter((charge: any) => {
if ((charge.currency.code !== currencyCode) || (!!multiDisburseLoan && charge.chargeTimeType.id === 12) || chargesDataSource.includes(charge)) {
if ((charge.currency.code !== currencyCode) || (!!multiDisburseLoan && charge.chargeTimeType.id === 12) || chargesDataSource.filter((chargeData: any) => chargeData.id === charge.id).length) {
return false;
}
return true;
@@ -64,8 +64,8 @@
<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductsTemplate"
[currencyCode]="loanProductCurrencyForm.value.currencyCode"
[multiDisburseLoan]="loanProductSettingsForm.value.multiDisburseLoan"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="loanProductSettingsForm.get('multiDisburseLoan')"
>
</mifosx-loan-product-charges-step>
@@ -78,6 +78,7 @@
<mifosx-loan-product-accounting-step
[loanProductsTemplate]="loanProductsTemplate"
[accountingRuleData]="accountingRuleData"
[loanProductFormValid]="loanProductFormValid"
>
</mifosx-loan-product-accounting-step>
@@ -74,7 +74,7 @@ export class CreateLoanProductComponent implements OnInit {
...this.loanProductCurrencyStep.loanProductCurrency,
...this.loanProductTermsStep.loanProductTerms,
...this.loanProductSettingsStep.loanProductSettings,
...this.loanProductChargesStep.charges,
...this.loanProductChargesStep.loanProductCharges,
...this.loanProductAccountingStep.loanProductAccounting
};
}
@@ -0,0 +1,103 @@
<div class="container">
<mat-horizontal-stepper class="mat-elevation-z8" labelPosition="bottom" #loanProductStepper>
<ng-template matStepperIcon="number">
<fa-icon icon="pencil-alt" size="sm"></fa-icon>
</ng-template>
<ng-template matStepperIcon="edit">
<fa-icon icon="pencil-alt" size="sm"></fa-icon>
</ng-template>
<ng-template matStepperIcon="done">
<fa-icon icon="check" size="sm"></fa-icon>
</ng-template>
<ng-template matStepperIcon="error">
<fa-icon icon="exclamation-triangle" size="lg"></fa-icon>
</ng-template>
<ng-template matStepperIcon="preview">
<fa-icon icon="eye" size="sm"></fa-icon>
</ng-template>
<mat-step [stepControl]="loanProductDetailsForm" completed>
<ng-template matStepLabel>DETAILS</ng-template>
<mifosx-loan-product-details-step [loanProductsTemplate]="loanProductAndTemplate"></mifosx-loan-product-details-step>
</mat-step>
<mat-step [stepControl]="loanProductCurrencyForm" completed>
<ng-template matStepLabel>CURRENCY</ng-template>
<mifosx-loan-product-currency-step [loanProductsTemplate]="loanProductAndTemplate"></mifosx-loan-product-currency-step>
</mat-step>
<mat-step [stepControl]="loanProductTermsForm" completed>
<ng-template matStepLabel>TERMS</ng-template>
<mifosx-loan-product-terms-step [loanProductsTemplate]="loanProductAndTemplate"></mifosx-loan-product-terms-step>
</mat-step>
<mat-step [stepControl]="loanProductSettingsForm" completed>
<ng-template matStepLabel>SETTINGS</ng-template>
<mifosx-loan-product-settings-step
[loanProductsTemplate]="loanProductAndTemplate"
[isLinkedToFloatingInterestRates]="loanProductTermsForm.get('isLinkedToFloatingInterestRates')"
>
</mifosx-loan-product-settings-step>
</mat-step>
<mat-step completed>
<ng-template matStepLabel>CHARGES</ng-template>
<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductAndTemplate"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="loanProductSettingsForm.get('multiDisburseLoan')"
>
</mifosx-loan-product-charges-step>
</mat-step>
<mat-step [stepControl]="loanProductAccountingForm" completed>
<ng-template matStepLabel>ACCOUNTING</ng-template>
<mifosx-loan-product-accounting-step
[loanProductsTemplate]="loanProductAndTemplate"
[accountingRuleData]="accountingRuleData"
[loanProductFormValid]="loanProductFormValidAndNotPristine"
>
</mifosx-loan-product-accounting-step>
</mat-step>
<mat-step state="preview" *ngIf="loanProductFormValidAndNotPristine" completed>
<ng-template matStepLabel>PREVIEW</ng-template>
<mifosx-loan-product-preview-step
[loanProductsTemplate]="loanProductAndTemplate"
[accountingRuleData]="accountingRuleData"
[loanProduct]="loanProduct"
(submit)="submit()"
>
</mifosx-loan-product-preview-step>
</mat-step>
</mat-horizontal-stepper>
</div>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditLoanProductComponent } from './edit-loan-product.component';
describe('EditLoanProductComponent', () => {
let component: EditLoanProductComponent;
let fixture: ComponentFixture<EditLoanProductComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditLoanProductComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditLoanProductComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,108 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { LoanProductDetailsStepComponent } from '../loan-product-stepper/loan-product-details-step/loan-product-details-step.component';
import { LoanProductCurrencyStepComponent } from '../loan-product-stepper/loan-product-currency-step/loan-product-currency-step.component';
import { LoanProductTermsStepComponent } from '../loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component';
import { LoanProductSettingsStepComponent } from '../loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component';
import { LoanProductChargesStepComponent } from '../loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component';
import { LoanProductAccountingStepComponent } from '../loan-product-stepper/loan-product-accounting-step/loan-product-accounting-step.component';
import { ProductsService } from 'app/products/products.service';
@Component({
selector: 'mifosx-edit-loan-product',
templateUrl: './edit-loan-product.component.html',
styleUrls: ['./edit-loan-product.component.scss']
})
export class EditLoanProductComponent implements OnInit {
@ViewChild(LoanProductDetailsStepComponent) loanProductDetailsStep: LoanProductDetailsStepComponent;
@ViewChild(LoanProductCurrencyStepComponent) loanProductCurrencyStep: LoanProductCurrencyStepComponent;
@ViewChild(LoanProductTermsStepComponent) loanProductTermsStep: LoanProductTermsStepComponent;
@ViewChild(LoanProductSettingsStepComponent) loanProductSettingsStep: LoanProductSettingsStepComponent;
@ViewChild(LoanProductChargesStepComponent) loanProductChargesStep: LoanProductChargesStepComponent;
@ViewChild(LoanProductAccountingStepComponent) loanProductAccountingStep: LoanProductAccountingStepComponent;
loanProductAndTemplate: any;
accountingRuleData = ['None', 'Cash', 'Accrual (periodic)', 'Accrual (upfront)'];
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router) {
this.route.data.subscribe((data: { loanProductAndTemplate: any }) => {
this.loanProductAndTemplate = data.loanProductAndTemplate;
});
}
ngOnInit() {
}
get loanProductDetailsForm() {
return this.loanProductDetailsStep.loanProductDetailsForm;
}
get loanProductCurrencyForm() {
return this.loanProductCurrencyStep.loanProductCurrencyForm;
}
get loanProductTermsForm() {
return this.loanProductTermsStep.loanProductTermsForm;
}
get loanProductSettingsForm() {
return this.loanProductSettingsStep.loanProductSettingsForm;
}
get loanProductAccountingForm() {
return this.loanProductAccountingStep.loanProductAccountingForm;
}
get loanProductFormValidAndNotPristine() {
return (
this.loanProductDetailsForm.valid &&
this.loanProductCurrencyForm.valid &&
this.loanProductTermsForm.valid &&
this.loanProductSettingsForm.valid &&
this.loanProductAccountingForm.valid &&
(
!this.loanProductDetailsForm.pristine ||
!this.loanProductCurrencyForm.pristine ||
!this.loanProductTermsForm.pristine ||
!this.loanProductSettingsForm.pristine ||
!this.loanProductChargesStep.pristine ||
!this.loanProductAccountingForm.pristine
)
);
}
get loanProduct() {
return {
...this.loanProductDetailsStep.loanProductDetails,
...this.loanProductCurrencyStep.loanProductCurrency,
...this.loanProductTermsStep.loanProductTerms,
...this.loanProductSettingsStep.loanProductSettings,
...this.loanProductChargesStep.loanProductCharges,
...this.loanProductAccountingStep.loanProductAccounting
};
}
submit() {
// TODO: Update once language and date settings are setup
const dateFormat = 'yyyy-MM-dd';
const loanProduct = {
...this.loanProduct,
charges: this.loanProduct.charges.map((charge: any) => ({ id: charge.id })),
dateFormat,
locale: 'en'
};
delete loanProduct.allowAttributeConfiguration;
delete loanProduct.advancedAccountingRules;
this.productsService.updateLoanProduct(this.loanProductAndTemplate.id, loanProduct)
.subscribe((response: any) => {
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
});
}
}
@@ -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 { ProductsService } from '../../products.service';
/**
* Loan product and template data resolver.
*/
@Injectable()
export class LoanProductAndTemplateResolver implements Resolve<Object> {
/**
* @param {ProductsService} productsService Products service.
*/
constructor(private productsService: ProductsService) {}
/**
* Returns the loan product and template data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const loanProductId = route.paramMap.get('id');
return this.productsService.getLoanProduct(loanProductId, true);
}
}
@@ -320,7 +320,7 @@
<fa-icon icon="arrow-left"></fa-icon>&nbsp;&nbsp;
Previous
</button>
<button mat-raised-button matStepperNext>
<button mat-raised-button matStepperNext [disabled]="!loanProductFormValid">
Next&nbsp;&nbsp;
<fa-icon icon="arrow-right"></fa-icon>
</button>
@@ -17,6 +17,7 @@ export class LoanProductAccountingStepComponent implements OnInit {
@Input() loanProductsTemplate: any;
@Input() accountingRuleData: any;
@Input() loanProductFormValid: boolean;
loanProductAccountingForm: FormGroup;
@@ -47,6 +48,44 @@ export class LoanProductAccountingStepComponent implements OnInit {
this.expenseAccountData = this.loanProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
this.liabilityAccountData = this.loanProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
this.incomeAndLiabilityAccountData = this.incomeAccountData.concat(this.liabilityAccountData);
this.loanProductAccountingForm.patchValue({
'accountingRule': this.loanProductsTemplate.accountingRule.id
});
switch (this.loanProductsTemplate.accountingRule.id) {
case 3:
case 4:
this.loanProductAccountingForm.patchValue({
'receivableInterestAccountId': this.loanProductsTemplate.accountingMappings.receivableInterestAccount.id,
'receivableFeeAccountId': this.loanProductsTemplate.accountingMappings.receivableFeeAccount.id,
'receivablePenaltyAccountId': this.loanProductsTemplate.accountingMappings.receivablePenaltyAccount.id,
});
/* falls through */
case 2:
this.loanProductAccountingForm.patchValue({
'fundSourceAccountId': this.loanProductsTemplate.accountingMappings.fundSourceAccount.id,
'loanPortfolioAccountId': this.loanProductsTemplate.accountingMappings.loanPortfolioAccount.id,
'transfersInSuspenseAccountId': this.loanProductsTemplate.accountingMappings.transfersInSuspenseAccount.id,
'interestOnLoanAccountId': this.loanProductsTemplate.accountingMappings.interestOnLoanAccount.id,
'incomeFromFeeAccountId': this.loanProductsTemplate.accountingMappings.incomeFromFeeAccount.id,
'incomeFromPenaltyAccountId': this.loanProductsTemplate.accountingMappings.incomeFromPenaltyAccount.id,
'incomeFromRecoveryAccountId': this.loanProductsTemplate.accountingMappings.incomeFromRecoveryAccount.id,
'writeOffAccountId': this.loanProductsTemplate.accountingMappings.writeOffAccount.id,
'overpaymentLiabilityAccountId': this.loanProductsTemplate.accountingMappings.overpaymentLiabilityAccount.id,
'advancedAccountingRules': (this.loanProductsTemplate.paymentChannelToFundSourceMappings || this.loanProductsTemplate.feeToIncomeAccountMappings || this.loanProductsTemplate.penaltyToIncomeAccountMappings) ? true : false
});
this.loanProductAccountingForm.setControl('paymentChannelToFundSourceMappings',
this.formBuilder.array((this.loanProductsTemplate.paymentChannelToFundSourceMappings || []).map((paymentFundSource: any) =>
({ paymentTypeId: paymentFundSource.paymentType.id, fundSourceAccountId: paymentFundSource.fundSourceAccount.id }))));
this.loanProductAccountingForm.setControl('feeToIncomeAccountMappings',
this.formBuilder.array((this.loanProductsTemplate.feeToIncomeAccountMappings || []).map((feesIncome: any) =>
({ chargeId: feesIncome.charge.id, incomeAccountId: feesIncome.incomeAccount.id }))));
this.loanProductAccountingForm.setControl('penaltyToIncomeAccountMappings',
this.formBuilder.array((this.loanProductsTemplate.penaltyToIncomeAccountMappings || []).map((penaltyIncome: any) =>
({ chargeId: penaltyIncome.charge.id, incomeAccountId: penaltyIncome.incomeAccount.id }))));
}
}
createLoanProductAccountingForm() {
@@ -74,7 +113,7 @@ export class LoanProductAccountingStepComponent implements OnInit {
.subscribe((advancedAccountingRules: boolean) => {
if (advancedAccountingRules) {
this.loanProductAccountingForm.addControl('paymentChannelToFundSourceMappings', this.formBuilder.array([]));
this.loanProductAccountingForm.addControl('feeToIncomeAccountMappings', this.formBuilder.array([] ));
this.loanProductAccountingForm.addControl('feeToIncomeAccountMappings', this.formBuilder.array([]));
this.loanProductAccountingForm.addControl('penaltyToIncomeAccountMappings', this.formBuilder.array([]));
} else {
this.loanProductAccountingForm.removeControl('paymentChannelToFundSourceMappings');
@@ -119,12 +158,19 @@ export class LoanProductAccountingStepComponent implements OnInit {
return this.loanProductAccountingForm.get('penaltyToIncomeAccountMappings') as FormArray;
}
setLoanProductAccountingFormDirty() {
if (this.loanProductAccountingForm.pristine) {
this.loanProductAccountingForm.markAsDirty();
}
}
add(formType: string, formArray: FormArray) {
const data = this.getData(formType);
const data = { ...this.getData(formType), pristine: false };
const dialogRef = this.dialog.open(FormDialogComponent, { data });
dialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
formArray.push(response.data);
this.setLoanProductAccountingFormDirty();
}
});
}
@@ -135,6 +181,7 @@ export class LoanProductAccountingStepComponent implements OnInit {
dialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
formArray.at(index).patchValue(response.data.value);
this.setLoanProductAccountingFormDirty();
}
});
}
@@ -146,6 +193,7 @@ export class LoanProductAccountingStepComponent implements OnInit {
dialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
formArray.removeAt(index);
this.setLoanProductAccountingFormDirty();
}
});
}
@@ -3,7 +3,7 @@
<mat-form-field fxFlex="48%">
<mat-label>Charge</mat-label>
<mat-select #charge>
<mat-option *ngFor="let charge of chargeData | chargesFilter:chargesDataSource:currencyCode:multiDisburseLoan" [value]="charge">
<mat-option *ngFor="let charge of chargeData | chargesFilter:chargesDataSource:currencyCode.value:multiDisburseLoan.value" [value]="charge">
{{ charge.name }}
</mat-option>
</mat-select>
@@ -69,7 +69,7 @@
<mat-form-field fxFlex="48%">
<mat-label>Overdue Charge</mat-label>
<mat-select #overdueCharge>
<mat-option *ngFor="let overdueCharge of overdueChargeData | chargesFilter:chargesDataSource:currencyCode" [value]="overdueCharge">
<mat-option *ngFor="let overdueCharge of overdueChargeData | chargesFilter:chargesDataSource:currencyCode.value" [value]="overdueCharge">
{{ overdueCharge.name }}
</mat-option>
</mat-select>
@@ -1,5 +1,6 @@
import { Component, OnInit, Input } from '@angular/core';
import { MatDialog } from '@angular/material';
import { FormControl } from '@angular/forms';
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
@@ -11,26 +12,35 @@ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.co
export class LoanProductChargesStepComponent implements OnInit {
@Input() loanProductsTemplate: any;
@Input() currencyCode: any;
@Input() multiDisburseLoan: any;
@Input() currencyCode: FormControl;
@Input() multiDisburseLoan: FormControl;
chargeData: any;
overdueChargeData: any;
chargesDataSource: {}[] = [];
chargesDataSource: {}[];
displayedColumns: string[] = ['name', 'chargeCalculationType', 'amount', 'chargeTimeType', 'action'];
pristine = true;
constructor(public dialog: MatDialog) {
}
ngOnInit() {
this.chargeData = this.loanProductsTemplate.chargeOptions;
this.overdueChargeData = this.loanProductsTemplate.penaltyOptions.filter((penalty: any) => penalty.chargeTimeType.code === 'chargeTimeType.overdueInstallment');
this.chargesDataSource = this.loanProductsTemplate.charges || [];
this.pristine = true;
this.currencyCode.valueChanges.subscribe(() => this.chargesDataSource = []);
this.multiDisburseLoan.valueChanges.subscribe(() => this.chargesDataSource = []);
}
addCharge(charge: any) {
this.chargesDataSource = this.chargesDataSource.concat([charge.value]);
charge.value = '';
this.pristine = false;
}
deleteCharge(charge: any) {
@@ -41,11 +51,12 @@ export class LoanProductChargesStepComponent implements OnInit {
if (response.delete) {
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1);
this.chargesDataSource = this.chargesDataSource.concat([]);
this.pristine = false;
}
});
}
get charges() {
get loanProductCharges() {
return {
charges: this.chargesDataSource
};
@@ -20,13 +20,19 @@ export class LoanProductCurrencyStepComponent implements OnInit {
ngOnInit() {
this.currencyData = this.loanProductsTemplate.currencyOptions;
this.loanProductCurrencyForm.patchValue({ 'currencyCode': this.currencyData[0].code });
this.loanProductCurrencyForm.patchValue({
'currencyCode': this.loanProductsTemplate.currency.code || this.currencyData[0].code,
'digitsAfterDecimal': this.loanProductsTemplate.installmentAmountInMultiplesOf ? this.loanProductsTemplate.currency.decimalPlaces : 2,
'inMultiplesOf': this.loanProductsTemplate.currency.inMultiplesOf,
'installmentAmountInMultiplesOf': this.loanProductsTemplate.installmentAmountInMultiplesOf
});
}
createLoanProductCurrencyForm() {
this.loanProductCurrencyForm = this.formBuilder.group({
'currencyCode': ['', Validators.required],
'digitsAfterDecimal': [2, Validators.required],
'digitsAfterDecimal': ['', Validators.required],
'inMultiplesOf': ['', Validators.required],
'installmentAmountInMultiplesOf': ['', Validators.required]
});
@@ -25,6 +25,16 @@ export class LoanProductDetailsStepComponent implements OnInit {
ngOnInit() {
this.fundData = this.loanProductsTemplate.fundOptions;
this.loanProductDetailsForm.patchValue({
'name': this.loanProductsTemplate.name,
'shortName': this.loanProductsTemplate.shortName,
'description': this.loanProductsTemplate.description,
'fundId': this.loanProductsTemplate.fundId,
'startDate': this.loanProductsTemplate.startDate && new Date(this.loanProductsTemplate.startDate),
'closeDate': this.loanProductsTemplate.closeDate && new Date(this.loanProductsTemplate.closeDate),
'includeInBorrowerCycle': this.loanProductsTemplate.includeInBorrowerCycle
});
}
createLoanProductDetailsForm() {
@@ -115,7 +115,7 @@
<h4 fxFlex="48%" class="mat-h4">Number of days a loan may be overdue before moving into arrears</h4>
<mat-form-field fxFlex="48%">
<mat-label>On arrears aging</mat-label>
<mat-label>On arrears ageing</mat-label>
<input type="number" matInput formControlName="graceOnArrearsAgeing">
</mat-form-field>
@@ -210,9 +210,9 @@
<span fxFlex="48%" fxHide.lt-md></span>
<div *ngIf="loanProductSettingsForm.value.interestRecalculationCompoundingMethod !== 0 && loanProductSettingsForm.value.recalculationCompoundingFrequencyType !== 1" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<mat-form-field fxFlex="48%">
<mat-form-field fxFlex="48%" *ngIf="loanProductSettingsForm.value.interestRecalculationCompoundingMethod !== 0 && loanProductSettingsForm.value.recalculationCompoundingFrequencyType !== 1">
<mat-label>Frequency Interval for compounding</mat-label>
<input type="number" matInput formControlName="recalculationCompoundingFrequencyInterval" required>
<mat-error>
@@ -220,18 +220,7 @@
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Compounding Frequency Date</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="recalculationCompoundingFrequencyDatePicker" formControlName="recalculationCompoundingFrequencyDate">
<mat-datepicker-toggle matSuffix [for]="recalculationCompoundingFrequencyDatePicker"></mat-datepicker-toggle>
<mat-datepicker #recalculationCompoundingFrequencyDatePicker></mat-datepicker>
</mat-form-field>
</div>
<div *ngIf="loanProductSettingsForm.value.recalculationRestFrequencyType !== 1" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<mat-form-field fxFlex="48%">
<mat-form-field fxFlex="48%" *ngIf="loanProductSettingsForm.value.recalculationRestFrequencyType !== 1">
<mat-label>Frequency Interval for recalculation</mat-label>
<input type="number" matInput formControlName="recalculationRestFrequencyInterval" required>
<mat-error>
@@ -239,13 +228,6 @@
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Rest Frequency Date</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="recalculationRestFrequencyDatePicker" formControlName="recalculationRestFrequencyDate">
<mat-datepicker-toggle matSuffix [for]="recalculationRestFrequencyDatePicker"></mat-datepicker-toggle>
<mat-datepicker #recalculationRestFrequencyDatePicker></mat-datepicker>
</mat-form-field>
</div>
<div *ngIf="loanProductSettingsForm.value.interestRecalculationCompoundingMethod !== 0" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
@@ -1,6 +1,5 @@
import { Component, OnInit, Input } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { DatePipe } from '@angular/common';
@Component({
selector: 'mifosx-loan-product-settings-step',
@@ -28,11 +27,7 @@ export class LoanProductSettingsStepComponent implements OnInit {
interestRecalculationDayOfWeekTypeData: any;
interestRecalculationOnDayTypeData: any;
minDate = new Date(2000, 0, 1);
maxDate = new Date(new Date().setFullYear(new Date().getFullYear() + 10));
constructor(private formBuilder: FormBuilder,
private datePipe: DatePipe) {
constructor(private formBuilder: FormBuilder) {
this.createLoanProductSettingsForm();
this.setConditionalControls();
}
@@ -41,8 +36,8 @@ export class LoanProductSettingsStepComponent implements OnInit {
this.isLinkedToFloatingInterestRates.valueChanges
.subscribe((isLinkedToFloatingInterestRates: any) => {
if (isLinkedToFloatingInterestRates) {
this.loanProductSettingsForm.get('isInterestRecalculationEnabled').setValue(true);
}
this.loanProductSettingsForm.get('isInterestRecalculationEnabled').setValue(true);
}
});
this.amortizationTypeData = this.loanProductsTemplate.amortizationTypeOptions;
@@ -61,13 +56,83 @@ export class LoanProductSettingsStepComponent implements OnInit {
this.interestRecalculationOnDayTypeData = Array.from({ length: 28 }, (_, index) => index + 1);
this.loanProductSettingsForm.patchValue({
'amortizationType': this.amortizationTypeData[0].id,
'interestType': this.interestTypeData[0].id,
'interestCalculationPeriodType': this.interestCalculationPeriodTypeData[0].id,
'transactionProcessingStrategyId': this.transactionProcessingStrategyData[0].id,
'daysInYearType': this.daysInYearTypeData[0].id,
'daysInMonthType': this.daysInMonthTypeData[0].id,
'amortizationType': this.loanProductsTemplate.amortizationType.id,
'interestType': this.loanProductsTemplate.interestType.id,
'isEqualAmortization': this.loanProductsTemplate.isEqualAmortization,
'interestCalculationPeriodType': this.loanProductsTemplate.interestCalculationPeriodType.id,
'allowPartialPeriodInterestCalcualtion': this.loanProductsTemplate.allowPartialPeriodInterestCalcualtion,
'transactionProcessingStrategyId': this.loanProductsTemplate.transactionProcessingStrategyId || this.transactionProcessingStrategyData[0].id,
'graceOnPrincipalPayment': this.loanProductsTemplate.graceOnPrincipalPayment,
'graceOnInterestPayment': this.loanProductsTemplate.graceOnInterestPayment,
'graceOnInterestCharged': this.loanProductsTemplate.graceOnInterestCharged,
'inArrearsTolerance': this.loanProductsTemplate.inArrearsTolerance,
'daysInYearType': this.loanProductsTemplate.daysInYearType.id,
'daysInMonthType': this.loanProductsTemplate.daysInMonthType.id,
'canDefineInstallmentAmount': this.loanProductsTemplate.canDefineInstallmentAmount,
'graceOnArrearsAgeing': this.loanProductsTemplate.graceOnArrearsAgeing,
'overdueDaysForNPA': this.loanProductsTemplate.overdueDaysForNPA,
'accountMovesOutOfNPAOnlyOnArrearsCompletion': this.loanProductsTemplate.accountMovesOutOfNPAOnlyOnArrearsCompletion,
'principalThresholdForLastInstallment': this.loanProductsTemplate.principalThresholdForLastInstallment,
'allowVariableInstallments': this.loanProductsTemplate.allowVariableInstallments,
'minimumGap': this.loanProductsTemplate.minimumGap,
'maximumGap': this.loanProductsTemplate.maximumGap,
'canUseForTopup': this.loanProductsTemplate.canUseForTopup,
'isInterestRecalculationEnabled': this.loanProductsTemplate.isInterestRecalculationEnabled,
'holdGuaranteeFunds': this.loanProductsTemplate.holdGuaranteeFunds,
'multiDisburseLoan': this.loanProductsTemplate.multiDisburseLoan,
'maxTrancheCount': this.loanProductsTemplate.maxTrancheCount,
'outstandingLoanBalance': this.loanProductsTemplate.outstandingLoanBalance
});
if (this.loanProductsTemplate.isInterestRecalculationEnabled) {
this.loanProductSettingsForm.patchValue({
'preClosureInterestCalculationStrategy': this.loanProductsTemplate.interestRecalculationData.preClosureInterestCalculationStrategy.id,
'rescheduleStrategyMethod': this.loanProductsTemplate.interestRecalculationData.rescheduleStrategyType.id,
'interestRecalculationCompoundingMethod': this.loanProductsTemplate.interestRecalculationData.interestRecalculationCompoundingType.id,
'recalculationRestFrequencyType': this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyType.id,
'isArrearsBasedOnOriginalSchedule': this.loanProductsTemplate.interestRecalculationData.isArrearsBasedOnOriginalSchedule,
'recalculationCompoundingFrequencyType': this.loanProductsTemplate.interestRecalculationData.interestRecalculationCompoundingType.id && this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyType.id,
'recalculationCompoundingFrequencyInterval': this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyInterval,
'recalculationRestFrequencyInterval': this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyInterval,
'recalculationRestFrequencyNthDayType': this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyType.id === 4 && this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyOnDay ?
-2 : this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyNthDay && this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyNthDay.id,
'recalculationCompoundingFrequencyNthDayType': this.loanProductsTemplate.interestRecalculationData.interestRecalculationCompoundingType.id && this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4
&& this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyOnDay ? -2 : this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyNthDay
&& this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyNthDay.id,
'recalculationCompoundingFrequencyDayOfWeekType': this.loanProductsTemplate.interestRecalculationData.interestRecalculationCompoundingType.id && ((this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyType.id
=== 4 && !this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyOnDay) || this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3)
&& this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyWeekday && this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyWeekday.id,
'recalculationRestFrequencyDayOfWeekType': ((this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyType.id === 4 && !this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyOnDay)
|| this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyType.id === 3) && this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyWeekday
&& this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyWeekday.id,
'recalculationCompoundingFrequencyOnDayType': this.loanProductsTemplate.interestRecalculationData.recalculationCompoundingFrequencyOnDay,
'recalculationRestFrequencyOnDayType': this.loanProductsTemplate.interestRecalculationData.recalculationRestFrequencyOnDay
});
}
if (this.loanProductsTemplate.holdGuaranteeFunds) {
this.loanProductSettingsForm.patchValue({
'mandatoryGuarantee': this.loanProductsTemplate.productGuaranteeData.mandatoryGuarantee,
'minimumGuaranteeFromOwnFunds': this.loanProductsTemplate.productGuaranteeData.minimumGuaranteeFromOwnFunds,
'minimumGuaranteeFromGuarantor': this.loanProductsTemplate.productGuaranteeData.minimumGuaranteeFromGuarantor
});
}
if (this.loanProductsTemplate.allowAttributeOverrides) {
this.loanProductSettingsForm.patchValue({
'allowAttributeConfiguration': Object.values(this.loanProductsTemplate.allowAttributeOverrides).some((attribute: boolean) => attribute),
'allowAttributeOverrides': {
'amortizationType': this.loanProductsTemplate.allowAttributeOverrides.amortizationType,
'interestType': this.loanProductsTemplate.allowAttributeOverrides.interestType,
'transactionProcessingStrategyId': this.loanProductsTemplate.allowAttributeOverrides.transactionProcessingStrategyId,
'interestCalculationPeriodType': this.loanProductsTemplate.allowAttributeOverrides.interestCalculationPeriodType,
'inArrearsTolerance': this.loanProductsTemplate.allowAttributeOverrides.inArrearsTolerance,
'repaymentEvery': this.loanProductsTemplate.allowAttributeOverrides.repaymentEvery,
'graceOnPrincipalAndInterestPayment': this.loanProductsTemplate.allowAttributeOverrides.graceOnPrincipalAndInterestPayment,
'graceOnArrearsAgeing': this.loanProductsTemplate.allowAttributeOverrides.graceOnArrearsAgeing
}
});
}
}
createLoanProductSettingsForm() {
@@ -139,34 +204,27 @@ export class LoanProductSettingsStepComponent implements OnInit {
this.loanProductSettingsForm.addControl('recalculationRestFrequencyType', new FormControl(this.interestRecalculationFrequencyTypeData[0].id, Validators.required));
this.loanProductSettingsForm.addControl('isArrearsBasedOnOriginalSchedule', new FormControl(''));
// interestRecalculationCompoundingMethod (initially 0)
this.loanProductSettingsForm.get('interestRecalculationCompoundingMethod').valueChanges
.subscribe((interestRecalculationCompoundingMethod: any) => {
if (interestRecalculationCompoundingMethod !== 0) {
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyType', new FormControl(this.interestRecalculationFrequencyTypeData[0].id, Validators.required));
// recalculationCompoundingFrequencyType (initially 1)
this.loanProductSettingsForm.get('recalculationCompoundingFrequencyType').valueChanges
.subscribe((recalculationCompoundingFrequencyType: any) => {
if (recalculationCompoundingFrequencyType !== 1) {
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyInterval', new FormControl('', Validators.required));
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyDate', new FormControl(''));
} else {
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyInterval');
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyDate');
}
if (recalculationCompoundingFrequencyType === 3) {
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyDayOfWeekType', new FormControl(''));
} else {
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyDayOfWeekType');
}
if (recalculationCompoundingFrequencyType === 4) {
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyNthDayType');
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyOnDayType');
} else if (recalculationCompoundingFrequencyType === 4) {
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyNthDayType', new FormControl(''));
this.loanProductSettingsForm.addControl('recalculationCompoundingFrequencyDayOfWeekType', new FormControl(''));
// recalculationCompoundingFrequencyNthDayType
this.loanProductSettingsForm.get('recalculationCompoundingFrequencyNthDayType').valueChanges
.subscribe((recalculationCompoundingFrequencyNthDayType: any) => {
if (recalculationCompoundingFrequencyNthDayType === -2) {
@@ -177,9 +235,10 @@ export class LoanProductSettingsStepComponent implements OnInit {
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyOnDayType');
}
});
} else {
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyNthDayType');
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyDayOfWeekType');
this.loanProductSettingsForm.removeControl('recalculationCompoundingFrequencyOnDayType');
}
});
@@ -188,28 +247,22 @@ export class LoanProductSettingsStepComponent implements OnInit {
}
});
// recalculationRestFrequencyType
this.loanProductSettingsForm.get('recalculationRestFrequencyType').valueChanges
.subscribe((recalculationRestFrequencyType: any) => {
if (recalculationRestFrequencyType !== 1) {
this.loanProductSettingsForm.addControl('recalculationRestFrequencyInterval', new FormControl('', Validators.required));
this.loanProductSettingsForm.addControl('recalculationRestFrequencyDate', new FormControl(''));
} else {
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyInterval');
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyDate');
}
if (recalculationRestFrequencyType === 3) {
this.loanProductSettingsForm.addControl('recalculationRestFrequencyDayOfWeekType', new FormControl(''));
} else {
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyDayOfWeekType');
}
if (recalculationRestFrequencyType === 4) {
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyNthDayType');
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyOnDayType');
} else if (recalculationRestFrequencyType === 4) {
this.loanProductSettingsForm.addControl('recalculationRestFrequencyNthDayType', new FormControl(''));
this.loanProductSettingsForm.addControl('recalculationRestFrequencyDayOfWeekType', new FormControl(''));
// recalculationRestFrequencyNthDayType
this.loanProductSettingsForm.get('recalculationRestFrequencyNthDayType').valueChanges
.subscribe((recalculationRestFrequencyNthDayType: any) => {
if (recalculationRestFrequencyNthDayType === -2) {
@@ -223,6 +276,8 @@ export class LoanProductSettingsStepComponent implements OnInit {
} else {
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyNthDayType');
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyDayOfWeekType');
this.loanProductSettingsForm.removeControl('recalculationRestFrequencyOnDayType');
}
});
@@ -288,20 +343,6 @@ export class LoanProductSettingsStepComponent implements OnInit {
}
get loanProductSettings() {
const prevCompoundingFrequencyDate: Date = this.loanProductSettingsForm.value.recalculationCompoundingFrequencyDate;
const prevRestFrequencyDate: Date = this.loanProductSettingsForm.value.recalculationRestFrequencyDate;
// TODO: Update once language and date settings are setup
const dateFormat = 'yyyy-MM-dd';
if (prevCompoundingFrequencyDate) {
this.loanProductSettingsForm.patchValue({
recalculationCompoundingFrequencyDate: this.datePipe.transform(prevCompoundingFrequencyDate, dateFormat)
});
}
if (prevRestFrequencyDate) {
this.loanProductSettingsForm.patchValue({
recalculationRestFrequencyDate: this.datePipe.transform(prevRestFrequencyDate, dateFormat)
});
}
return this.loanProductSettingsForm.value;
}
@@ -38,10 +38,37 @@ export class LoanProductTermsStepComponent implements OnInit {
this.floatingRateData = this.loanProductsTemplate.floatingRateOptions;
this.interestRateFrequencyTypeData = this.loanProductsTemplate.interestRateFrequencyTypeOptions;
this.repaymentFrequencyTypeData = this.loanProductsTemplate.repaymentFrequencyTypeOptions;
this.loanProductTermsForm.patchValue({
'interestRateFrequencyType': this.interestRateFrequencyTypeData[0].id,
'repaymentFrequencyType': this.repaymentFrequencyTypeData[0].id
'minPrincipal': this.loanProductsTemplate.minPrincipal,
'principal': this.loanProductsTemplate.principal,
'maxPrincipal': this.loanProductsTemplate.maxPrincipal,
'minNumberOfRepayments': this.loanProductsTemplate.minNumberOfRepayments,
'numberOfRepayments': this.loanProductsTemplate.numberOfRepayments,
'maxNumberOfRepayments': this.loanProductsTemplate.maxNumberOfRepayments,
'isLinkedToFloatingInterestRates': this.loanProductsTemplate.isLinkedToFloatingInterestRates,
'minInterestRatePerPeriod': this.loanProductsTemplate.minInterestRatePerPeriod,
'interestRatePerPeriod': this.loanProductsTemplate.interestRatePerPeriod,
'maxInterestRatePerPeriod': this.loanProductsTemplate.maxInterestRatePerPeriod,
'interestRateFrequencyType': this.loanProductsTemplate.interestRateFrequencyType.id,
'floatingRatesId': this.loanProductsTemplate.floatingRateId,
'interestRateDifferential': this.loanProductsTemplate.interestRateDifferential,
'isFloatingInterestRateCalculationAllowed': this.loanProductsTemplate.isFloatingInterestRateCalculationAllowed,
'minDifferentialLendingRate': this.loanProductsTemplate.minDifferentialLendingRate,
'defaultDifferentialLendingRate': this.loanProductsTemplate.defaultDifferentialLendingRate,
'maxDifferentialLendingRate': this.loanProductsTemplate.maxDifferentialLendingRate,
'useBorrowerCycle': this.loanProductsTemplate.useBorrowerCycle,
'repaymentEvery': this.loanProductsTemplate.repaymentEvery,
'repaymentFrequencyType': this.loanProductsTemplate.repaymentFrequencyType.id,
'minimumDaysBetweenDisbursalAndFirstRepayment': this.loanProductsTemplate.minimumDaysBetweenDisbursalAndFirstRepayment
});
this.loanProductTermsForm.setControl('principalVariationsForBorrowerCycle',
this.formBuilder.array(this.loanProductsTemplate.principalVariationsForBorrowerCycle.map((variation: any) => ({ ...variation, valueConditionType: variation.valueConditionType.id }))));
this.loanProductTermsForm.setControl('numberOfRepaymentVariationsForBorrowerCycle',
this.formBuilder.array(this.loanProductsTemplate.numberOfRepaymentVariationsForBorrowerCycle.map((variation: any) => ({ ...variation, valueConditionType: variation.valueConditionType.id }))));
this.loanProductTermsForm.setControl('interestRateVariationsForBorrowerCycle',
this.formBuilder.array(this.loanProductsTemplate.interestRateVariationsForBorrowerCycle.map((variation: any) => ({ ...variation, valueConditionType: variation.valueConditionType.id }))));
}
createLoanProductTermsForm() {
@@ -82,7 +109,7 @@ export class LoanProductTermsStepComponent implements OnInit {
this.loanProductTermsForm.addControl('minInterestRatePerPeriod', new FormControl(''));
this.loanProductTermsForm.addControl('interestRatePerPeriod', new FormControl('', Validators.required));
this.loanProductTermsForm.addControl('maxInterestRatePerPeriod', new FormControl(''));
this.loanProductTermsForm.addControl('interestRateFrequencyType', new FormControl(this.interestRateFrequencyTypeData[0].id, Validators.required));
this.loanProductTermsForm.addControl('interestRateFrequencyType', new FormControl(this.interestRateFrequencyTypeData.id, Validators.required));
this.loanProductTermsForm.removeControl('floatingRatesId');
this.loanProductTermsForm.removeControl('interestRateDifferential');
this.loanProductTermsForm.removeControl('isFloatingInterestRateCalculationAllowed');
@@ -118,12 +145,19 @@ export class LoanProductTermsStepComponent implements OnInit {
return this.loanProductTermsForm.get('interestRateVariationsForBorrowerCycle') as FormArray;
}
setLoanProductTermsFormDirty() {
if (this.loanProductTermsForm.pristine) {
this.loanProductTermsForm.markAsDirty();
}
}
addVariationsForBorrowerCycle(formType: string, variationsForBorrowerCycleFormArray: FormArray) {
const data = this.getData(formType);
const addVariationsForBorrowerCycleDialogRef = this.dialog.open(FormDialogComponent, { data });
addVariationsForBorrowerCycleDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
variationsForBorrowerCycleFormArray.push(response.data);
this.setLoanProductTermsFormDirty();
}
});
}
@@ -134,6 +168,7 @@ export class LoanProductTermsStepComponent implements OnInit {
addVariationsForBorrowerCycleDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
variationsForBorrowerCycleFormArray.at(index).patchValue(response.data.value);
this.setLoanProductTermsFormDirty();
}
});
}
@@ -145,6 +180,7 @@ export class LoanProductTermsStepComponent implements OnInit {
deleteVariationsForBorrowerCycleDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
variationsForBorrowerCycleFormArray.removeAt(index);
this.setLoanProductTermsFormDirty();
}
});
}
@@ -1,5 +1,5 @@
<div fxLayout="row" fxLayoutAlign="end" fxLayoutGap="2%" fxLayout.lt-md="column" class="container m-b-20">
<button mat-raised-button color="primary">
<button mat-raised-button color="primary" [routerLink]="['edit']">
<fa-icon icon="edit"></fa-icon>&nbsp;&nbsp;
Edit
</button>
@@ -393,8 +393,8 @@
<span fxFlex="40%">Frequency for compounding:</span>
<span fxFlex="60%">
{{ loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.value }}
<span *ngIf="loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationCompoundingFrequencyNthDay">&nbsp;&nbsp;{{ 'on ' + loanProduct.interestRecalculationData.recalculationCompoundingFrequencyNthDay.value }}</span>
<span *ngIf="(loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && !loanProduct.interestRecalculationData.recalculationCompoundingFrequencyOnDay) || loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3">&nbsp;&nbsp;{{ loanProduct.interestRecalculationData.recalculationCompoundingFrequencyWeekday.value }}</span>
<span *ngIf="loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationCompoundingFrequencyNthDay">&nbsp;&nbsp;{{ 'on ' + loanProduct.interestRecalculationData.recalculationCompoundingFrequencyNthDay?.value }}</span>
<span *ngIf="(loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && !loanProduct.interestRecalculationData.recalculationCompoundingFrequencyOnDay) || loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 3">&nbsp;&nbsp;{{ loanProduct.interestRecalculationData.recalculationCompoundingFrequencyWeekday?.value }}</span>
<span *ngIf="loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationCompoundingFrequencyOnDay">&nbsp;&nbsp;{{ 'on day ' + loanProduct.interestRecalculationData.recalculationCompoundingFrequencyOnDay }}</span>
</span>
<div fxFlexFill *ngIf="loanProduct.interestRecalculationData.recalculationCompoundingFrequencyType.id !== 1" fxLayout="row wrap" fxLayout.lt-md="column">
@@ -410,8 +410,8 @@
<span fxFlex="40%">Frequency for recalculate Outstanding Principal:</span>
<span fxFlex="60%">
{{ loanProduct.interestRecalculationData.recalculationRestFrequencyType.value }}
<span *ngIf="loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationRestFrequencyNthDay">&nbsp;&nbsp;{{ 'on ' + loanProduct.interestRecalculationData.recalculationRestFrequencyNthDay.value }}</span>
<span *ngIf="(loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 4 && !loanProduct.interestRecalculationData.recalculationRestFrequencyOnDay) || loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 3">&nbsp;&nbsp;{{ loanProduct.interestRecalculationData.recalculationRestFrequencyWeekday.value }}</span>
<span *ngIf="loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationRestFrequencyNthDay">&nbsp;&nbsp;{{ 'on ' + loanProduct.interestRecalculationData.recalculationRestFrequencyNthDay?.value }}</span>
<span *ngIf="(loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 4 && !loanProduct.interestRecalculationData.recalculationRestFrequencyOnDay) || loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 3">&nbsp;&nbsp;{{ loanProduct.interestRecalculationData.recalculationRestFrequencyWeekday?.value }}</span>
<span *ngIf="loanProduct.interestRecalculationData.recalculationRestFrequencyType.id === 4 && loanProduct.interestRecalculationData.recalculationRestFrequencyOnDay">&nbsp;&nbsp;{{ 'on day ' + loanProduct.interestRecalculationData.recalculationRestFrequencyOnDay }}</span>
</span>
</div>
+20 -4
View File
@@ -13,6 +13,7 @@ import { ProductsComponent } from './products.component';
import { LoanProductsComponent } from './loan-products/loan-products.component';
import { CreateLoanProductComponent } from './loan-products/create-loan-product/create-loan-product.component';
import { ViewLoanProductComponent } from './loan-products/view-loan-product/view-loan-product.component';
import { EditLoanProductComponent } from './loan-products/edit-loan-product/edit-loan-product.component';
import { ManageTaxConfigurationsComponent } from './manage-tax-configurations/manage-tax-configurations.component';
import { RecurringDepositProductsComponent } from './recurring-deposit-products/recurring-deposit-products.component';
import { ChargesComponent } from './charges/charges.component';
@@ -24,6 +25,7 @@ import { ManageTaxComponentsComponent } from './manage-tax-components/manage-tax
import { LoanProductsResolver } from './loan-products/loan-products.resolver';
import { LoanProductsTemplateResolver } from './loan-products/loan-products-template.resolver';
import { LoanProductResolver } from './loan-products/loan-product.resolver';
import { LoanProductAndTemplateResolver } from './loan-products/edit-loan-product/loan-product-and-template.resolver';
import { RecurringDepositProductsResolver } from './recurring-deposit-products/recurring-deposit-products.resolver';
import { ChargesResolver } from './charges/charges.resolver';
import { FixedDepositProductsResolver } from './fixed-deposit-products/fixed-deposit-products.resolver';
@@ -62,11 +64,24 @@ const routes: Routes = [
},
{
path: ':id',
component: ViewLoanProductComponent,
data: { title: extract('View Loan Product'), routeParamBreadcrumb: 'id' },
resolve: {
loanProduct: LoanProductResolver
}
children: [
{
path: '',
component: ViewLoanProductComponent,
resolve: {
loanProduct: LoanProductResolver
},
},
{
path: 'edit',
component: EditLoanProductComponent,
data: { title: extract('Edit Loan Product'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
resolve: {
loanProductAndTemplate: LoanProductAndTemplateResolver
}
}
]
}
]
},
@@ -137,6 +152,7 @@ const routes: Routes = [
LoanProductsResolver,
LoanProductsTemplateResolver,
LoanProductResolver,
LoanProductAndTemplateResolver,
RecurringDepositProductsResolver,
ChargesResolver,
FixedDepositProductsResolver,
+3 -1
View File
@@ -25,6 +25,7 @@ import { FixedDepositProductsComponent } from './fixed-deposit-products/fixed-de
import { ProductsMixComponent } from './products-mix/products-mix.component';
import { ManageTaxComponentsComponent } from './manage-tax-components/manage-tax-components.component';
import { ViewLoanProductComponent } from './loan-products/view-loan-product/view-loan-product.component';
import { EditLoanProductComponent } from './loan-products/edit-loan-product/edit-loan-product.component';
/**
* Products Module
@@ -54,7 +55,8 @@ import { ViewLoanProductComponent } from './loan-products/view-loan-product/view
FixedDepositProductsComponent,
ProductsMixComponent,
ManageTaxComponentsComponent,
ViewLoanProductComponent
ViewLoanProductComponent,
EditLoanProductComponent
],
entryComponents: [
],
+7 -2
View File
@@ -33,8 +33,13 @@ export class ProductsService {
return this.http.get('/loanproducts/template');
}
getLoanProduct(loanProductId: string): Observable<any> {
return this.http.get(`/loanproducts/${loanProductId}`);
getLoanProduct(loanProductId: string, template: boolean = false): Observable<any> {
const httpParams = new HttpParams().set('template', template.toString());
return this.http.get(`/loanproducts/${loanProductId}`, { params: httpParams });
}
updateLoanProduct(loanProductId: string, loanProduct: any): Observable<any> {
return this.http.put(`/loanproducts/${loanProductId}`, loanProduct);
}
/**
@@ -32,12 +32,14 @@ export class FormDialogComponent implements OnInit {
form: FormGroup;
formfields: FormfieldBase[];
pristine: boolean;
constructor(public dialogRef: MatDialogRef<FormDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private formGroupService: FormGroupService) {
this.dialogRef.disableClose = !data.disableClose;
this.dialogRef.disableClose = data.disableClose !== undefined ? data.disableClose : true;
this.formfields = data.formfields.sort((formfieldA: FormfieldBase, formfieldB: FormfieldBase) => formfieldA.order - formfieldB.order);
this.pristine = data.pristine !== undefined ? data.pristine : true;
this.layout = { ...this.layout, ...data.layout };
this.layout.gap = this.layout.columns > 1 ? layoutGap : 0;
this.layout.flex = (this.layout.flex / this.layout.columns) - this.layout.gap;
@@ -46,6 +48,9 @@ export class FormDialogComponent implements OnInit {
ngOnInit() {
this.dialogRef.updateSize(`${this.layout.columnWidth * this.layout.columns}px`);
this.form = this.formGroupService.createFormGroup(this.formfields);
if (!this.pristine) {
this.form.markAsDirty();
}
}
}