feat: add edit charge component (#625)

Fixes: #586
This commit is contained in:
Benura Abeywardena
2020-05-17 12:43:10 +05:30
committed by GitHub
parent a1f1802316
commit c40c1b0434
9 changed files with 436 additions and 31 deletions
@@ -0,0 +1,25 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { ProductsService } from '../products.service';
@Injectable()
export class ChargesTemplateResolver implements Resolve<Object> {
constructor(private productsService: ProductsService) {}
/**
* Returns the share products template data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const savingProductId = route.paramMap.get('id');
return this.productsService.getCharge(savingProductId, true);
}
}
@@ -0,0 +1,172 @@
<div class="container">
<mat-card>
<form [formGroup]="chargeForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<mat-form-field fxFlex="48%">
<mat-label>Charges applies to</mat-label>
<mat-select required formControlName="chargeAppliesTo">
<mat-option *ngFor="let chargeAppliesTo of chargeData.chargeAppliesToOptions" [value]="chargeAppliesTo.id">
{{ chargeAppliesTo.value }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" style="margin-top:10px;">
<mat-form-field fxFlex="48%">
<mat-label>Name</mat-label>
<input matInput required autofocus formControlName="name">
<mat-error *ngIf="chargeForm.controls.name.hasError('required')">
Name <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Currency</mat-label>
<mat-select required formControlName="currencyCode">
<mat-option *ngFor="let currency of chargeData.currencyOptions" [value]="currency.code">
{{ currency.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.currencyCode.hasError('required')">
Currency Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Charge time type</mat-label>
<mat-select required formControlName="chargeTimeType">
<mat-option *ngFor="let chargeTime of chargeTimeTypeOptions" [value]="chargeTime.id">
{{ chargeTime.value }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.chargeTimeType.hasError('required')">
Charge Time Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Charge calculation</mat-label>
<mat-select required formControlName="chargeCalculationType">
<mat-option *ngFor="let chargeCalculation of chargeCalculationTypeOptions" [value]="chargeCalculation.id">
{{ chargeCalculation.value }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.chargeCalculationType.hasError('required')">
Charge Calculation Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="chargePaymentMode">
<mat-label>Charge Payment By</mat-label>
<mat-select required formControlName="chargePaymentMode">
<mat-option *ngFor="let chargePaymentMode of chargeData.chargePaymetModeOptions" [value]="chargePaymentMode.id">
{{ chargePaymentMode.value }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.chargePaymentMode.hasError('required')">
Charge Payment Mode is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Amount</mat-label>
<input matInput required autofocus type="text" formControlName="amount">
<mat-error *ngIf="chargeForm.controls.amount.hasError('required')">
Amount <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="showGLAccount">
<mat-label>Income from charge</mat-label>
<mat-select required formControlName="incomeAccountId">
<mat-option *ngFor="let income of chargeData.incomeOrLiabilityAccountOptions.incomeAccountOptions" [value]="income.id">
{{ income.name }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.incomeAccountId.hasError('required')">
Income from charge is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Tax Group</mat-label>
<mat-select *ngIf="chargeData.taxGroup" required formControlName="taxGroupId">
<mat-option *ngFor="let taxGroup of chargeData.taxGroupOptions" [value]="taxGroup.id">
{{ taxGroup.name }}
</mat-option>
</mat-select>
<mat-select *ngIf="!chargeData.taxGroup" required formControlName="taxGroupId">
<mat-option value="?">
Select Option
</mat-option>
</mat-select>
</mat-form-field>
<div fxFlex="48%" class="password-never-expires-wrapper" *ngIf="addFeeFrequency" style="padding-top: 10px;">
<mat-checkbox labelPosition="before" (change)="getFeeFrequency($event.checked)">
Add Fee Frequency
</mat-checkbox>
</div>
<mat-form-field fxFlex="48%" *ngIf="addFeeFrequency && showFeeOptions">
<mat-label>Charge Frequency</mat-label>
<mat-select required formControlName="feeFrequency">
<mat-option *ngFor="let chargeFrequency of chargeData.feeFrequencyOptions" [value]="chargeFrequency.id">
{{ chargeFrequency.value }}
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.feeFrequency.hasError('required')">
Fee Frequency is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="addFeeFrequency && showFeeOptions">
<mat-label>Frequency Interval</mat-label>
<input matInput required autofocus type="text" formControlName="feeInterval" required>
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('required')">
Amount <strong>is required</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" style="margin-top:10px;">
<div fxFlex="48%" class="password-never-expires-wrapper">
<mat-checkbox labelPosition="before" formControlName="active">
Active
</mat-checkbox>
</div>
<div fxFlex="48%" class="send-password-to-email-wrapper" *ngIf="showPenalty">
<mat-checkbox labelPosition="before" formControlName="penalty">
Is Penalty
</mat-checkbox>
</div>
</div>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button color="primary" [disabled]="!chargeForm.valid">Submit</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditChargeComponent } from './edit-charge.component';
describe('EditChargeComponent', () => {
let component: EditChargeComponent;
let fixture: ComponentFixture<EditChargeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditChargeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditChargeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,148 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
/**
* Edit Charge component.
*/
@Component({
selector: 'mifosx-edit-charge',
templateUrl: './edit-charge.component.html',
styleUrls: ['./edit-charge.component.scss']
})
export class EditChargeComponent implements OnInit {
/** Selected Data. */
chargeData: any;
/** Charge form. */
chargeForm: FormGroup;
/** Select Income. */
selectedIncome: any;
/** Select Time Type. */
selectedTime: any;
/** Select Currency Type. */
selectedCurrency: any;
/** Select Calculation Type. */
selectedCalculation: any;
/** Charge Time Type options. */
chargeTimeTypeOptions: any;
/** Charge Calculation Type options. */
chargeCalculationTypeOptions: any;
/** Show Penalty. */
showPenalty = true;
/** Add Fee Frequency. */
addFeeFrequency = true;
/** Show GL Accounts. */
showGLAccount = false;
/** Charge Payment Mode. */
chargePaymentMode = false;
/** Show Fee Options. */
showFeeOptions = false;
/**
* Retrieves the charge data from `resolve`.
* @param {ProductsService} productsService Products Service.
* @param {FormBuilder} formBuilder Form Builder.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
*/
constructor(
private productsService: ProductsService,
private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
) {
this.route.data.subscribe((data: { chargesTemplate: any }) => {
this.chargeData = data.chargesTemplate;
});
}
ngOnInit() {
this.editChargeForm();
}
/**
* Edit Charge form.
*/
editChargeForm() {
this.chargeForm = this.formBuilder.group({
'name': [this.chargeData.name, Validators.required],
'chargeAppliesTo': [{value: this.chargeData.chargeAppliesTo.id, disabled: true}, Validators.required],
'currencyCode': [this.chargeData.currency.code, Validators.required],
'amount': [this.chargeData.amount, Validators.required],
'active': [this.chargeData.active],
'penalty': [this.chargeData.penalty],
'chargeTimeType': [this.chargeData.chargeTimeType.id, Validators.required],
'chargeCalculationType': [this.chargeData.chargeCalculationType.id, Validators.required],
});
switch (this.chargeData.chargeAppliesTo.value) {
case 'Loan': {
this.chargeTimeTypeOptions = this.chargeData.loanChargeTimeTypeOptions;
this.chargeCalculationTypeOptions = this.chargeData.loanChargeCalculationTypeOptions;
this.addFeeFrequency = true;
this.chargePaymentMode = true;
this.chargeForm.addControl('chargePaymentMode', this.formBuilder.control(this.chargeData.chargePaymentMode.id, Validators.required));
break;
}
case 'Savings': {
this.chargeTimeTypeOptions = this.chargeData.savingsChargeTimeTypeOptions;
this.chargeCalculationTypeOptions = this.chargeData.savingsChargeCalculationTypeOptions;
this.addFeeFrequency = false;
break;
}
case 'Shares': {
this.chargeTimeTypeOptions = this.chargeData.shareChargeTimeTypeOptions;
this.chargeCalculationTypeOptions = this.chargeData.shareChargeCalculationTypeOptions;
this.addFeeFrequency = false;
this.showGLAccount = false;
this.showPenalty = false;
break;
}
default: {
this.chargeCalculationTypeOptions = this.chargeData.clientChargeCalculationTypeOptions;
this.chargeTimeTypeOptions = this.chargeData.clientChargeTimeTypeOptions;
this.showGLAccount = true;
this.addFeeFrequency = false;
this.chargeForm.addControl('incomeAccountId', this.formBuilder.control(this.chargeData.incomeOrLiabilityAccount.id, Validators.required));
break;
}
}
if (this.chargeData.taxGroup) {
this.chargeForm.addControl('taxGroupId', this.formBuilder.control({value: this.chargeData.taxGroup.id, disabled: true}, Validators.required));
} else {
this.chargeForm.addControl('taxGroupId', this.formBuilder.control({value: '?', disabled: true}));
}
}
/**
* Get Add Fee Frequency value.
*/
getFeeFrequency(isChecked: boolean) {
this.showFeeOptions = isChecked;
if (isChecked) {
this.chargeForm.addControl('feeInterval', this.formBuilder.control('', Validators.required));
this.chargeForm.addControl('feeFrequency', this.formBuilder.control('', Validators.required));
} else {
this.chargeForm.removeControl('feeInterval');
this.chargeForm.removeControl('feeFrequency');
}
}
/**
* Submits Edit Charge form.
*/
submit() {
const charges = this.chargeForm.value;
charges.locale = 'en';
charges.chargePaymentMode = this.chargeData.chargePaymentMode.id;
this.productsService.updateCharge(this.chargeData.id.toString(), charges)
.subscribe((response: any) => {
this.router.navigate(['../'], { relativeTo: this.route });
});
}
}
@@ -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>
@@ -81,19 +81,19 @@
{{ chargeData.active === true ? 'Yes' : 'No' }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="chargeData.chargeTimeType.id == 9">
<div fxFlex="50%" class="mat-body-strong" *ngIf="chargeData.chargeTimeType.id == 9 && chargeData.feeFrequency">
Fee Frequency
</div>
<div fxFlex="50%" *ngIf="chargeData.chargeTimeType.id == 9">
<div fxFlex="50%" *ngIf="chargeData.chargeTimeType.id == 9 && chargeData.feeFrequency && chargeData.feeFrequency">
{{ chargeData.feeFrequency.value }}
</div>
<div fxFlex="50%" class="mat-body-strong" *ngIf="chargeData.chargeTimeType.id == 9">
<div fxFlex="50%" class="mat-body-strong" *ngIf="chargeData.chargeTimeType.id == 9 && chargeData.feeInterval">
Frequency Interval
</div>
<div fxFlex="50%" *ngIf="chargeData.chargeTimeType.id == 9">
<div fxFlex="50%" *ngIf="chargeData.chargeTimeType.id == 9 && chargeData.feeInterval">
{{ chargeData.feeInterval }}
</div>
+39 -21
View File
@@ -64,6 +64,8 @@ import { ManageTaxComponentsResolver } from './manage-tax-components/manage-tax-
import { ManageTaxGroupsResolver } from './manage-tax-groups/manage-tax-groups.resolver';
import { TaxComponentResolver } from './manage-tax-components/tax-component.resolver';
import { TaxComponentTemplateResolver } from './manage-tax-components/tax-component-template.resolver';
import { EditChargeComponent } from './charges/edit-charge/edit-charge.component';
import { ChargesTemplateResolver } from './charges/charges-template.resolver';
/** Products Routes */
const routes: Routes = [
@@ -270,27 +272,6 @@ const routes: Routes = [
},
data: { title: extract('Recurring Deposit Products'), breadcrumb: 'Recurring Deposit Products' },
},
{
path: 'charges',
data: { title: extract('Charges'), breadcrumb: 'Charges' },
children: [
{
path: '',
component: ChargesComponent,
resolve: {
charges: ChargesResolver
}
},
{
path: ':id',
data: { title: extract('View Charge'), routeResolveBreadcrumb: ['charge', 'name'] },
component: ViewChargeComponent,
resolve: {
charge: ChargeResolver
}
}
]
},
{
path: 'fixed-deposit-products',
data: { title: extract('Fixed Deposit Products'), breadcrumb: 'Fixed Deposit Products' },
@@ -358,6 +339,42 @@ const routes: Routes = [
]
}
]
},
{
path: 'charges',
data: { title: extract('Charges'), breadcrumb: 'Charges' },
children: [
{
path: '',
component: ChargesComponent,
resolve: {
charges: ChargesResolver
}
},
{
path: ':id',
data: { title: extract('View Charges'), routeParamBreadcrumb: 'id' },
children: [
{
path: '',
component: ViewChargeComponent,
resolve: {
charge: ChargeResolver
}
},
{
path: 'edit',
component: EditChargeComponent,
data: { title: extract('Edit Charge'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
resolve: {
chargesTemplate: ChargesTemplateResolver
}
},
]
},
]
}
]
}
@@ -388,6 +405,7 @@ const routes: Routes = [
RecurringDepositProductsResolver,
ChargesResolver,
ChargeResolver,
ChargesTemplateResolver,
FixedDepositProductsResolver,
FixedDepositProductsTemplateResolver,
ProductsMixResolver,
+6 -2
View File
@@ -1,6 +1,6 @@
/** Angular Imports */
import { NgModule } from '@angular/core';
import { DatePipe } from '@angular/common';
import { DatePipe, CommonModule } from '@angular/common';
/** Custom Modules */
import { SharedModule } from '../shared/shared.module';
@@ -69,6 +69,9 @@ import { EditFloatingRateComponent } from './floating-rates/edit-floating-rate/e
import { FloatingRatePeriodDialogComponent } from './floating-rates/floating-rate-period-dialog/floating-rate-period-dialog.component';
import { CreateTaxComponentComponent } from './manage-tax-components/create-tax-component/create-tax-component.component';
import { EditTaxComponentComponent } from './manage-tax-components/edit-tax-component/edit-tax-component.component';
import { EditChargeComponent } from './charges/edit-charge/edit-charge.component';
import { MatFormFieldModule, MatSelectModule, MatOptionModule } from '@angular/material';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
/**
* Products Module
@@ -143,7 +146,8 @@ import { EditTaxComponentComponent } from './manage-tax-components/edit-tax-comp
ManageTaxGroupsComponent,
ViewTaxComponentComponent,
CreateTaxComponentComponent,
EditTaxComponentComponent
EditTaxComponentComponent,
EditChargeComponent
],
entryComponents: [
FloatingRatePeriodDialogComponent
+16 -3
View File
@@ -98,18 +98,31 @@ export class ProductsService {
}
/**
* @returns {Observable<any>} Charges data
* @returns {Observable<any>} Charges data.
*/
getCharges(): Observable<any> {
return this.http.get('/charges');
}
getChargesTemplate(): Observable<any> {
return this.http.get('/charges/template');
}
/**
* @param {string} chargeId Charge ID of charge.
* @returns {Observable<any>} Charge.
*/
getCharge(chargeId: string): Observable<any> {
return this.http.get(`/charges/${chargeId}`);
getCharge(selectedCharge: string, template: boolean = false): Observable<any> {
const httpParams = new HttpParams().set('template', template.toString());
return this.http.get(`/charges/${selectedCharge}`, { params: httpParams });
}
/**
* @param chargeId Charge Id to be updated.
* @param charges Charge Data to be updated.
*/
updateCharge(chargeId: string, charges: any): Observable<any> {
return this.http.put(`/charges/${chargeId}`, charges);
}
/**