feat: client actions (add-charge) (#1105)

Fixes: #1104
This commit is contained in:
Karan Takalkar
2020-07-15 14:07:35 +05:30
committed by GitHub
parent 7616938e20
commit fdbde1336e
11 changed files with 285 additions and 2 deletions
@@ -0,0 +1,93 @@
<div class="container">
<mat-card>
<form [formGroup]="clientChargeForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="column">
<mat-form-field>
<mat-label>Charge</mat-label>
<mat-select required formControlName="chargeId">
<mat-option *ngFor="let clientCharge of clientChargeOptions" [value]="clientCharge.id">
{{ clientCharge.name + ' (' + clientCharge.currency.name + ')' }}
</mat-option>
</mat-select>
<mat-error *ngIf="clientChargeForm.controls.chargeId.hasError('required')">
Charge is <strong>required</strong>
</mat-error>
</mat-form-field>
<div *ngIf="chargeDetails" fxLayout="column">
<mat-form-field>
<mat-label>Amount</mat-label>
<input type=number required matInput formControlName="amount" />
<mat-error *ngIf="clientChargeForm.controls.amount.hasError('required')">
Amount is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Charge Calculation</mat-label>
<mat-select formControlName="chargeCalculationType">
<mat-option *ngFor="let chargeCalculation of chargeDetails.chargeCalculationTypeOptions"
[value]="chargeCalculation.id">
{{ chargeCalculation.value }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Charge time type</mat-label>
<mat-select formControlName="chargeTimeType">
<mat-option *ngFor="let chargeTime of chargeDetails.chargeTimeTypeOptions" [value]="chargeTime.id">
{{ chargeTime.value }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="clientChargeForm.contains('dueDate')">
<mat-label>Due for collection on</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="dueDatePicker" required
formControlName="dueDate">
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
<mat-datepicker #dueDatePicker></mat-datepicker>
<mat-error *ngIf="clientChargeForm.controls.dueDate.hasError('required')">
Due for collection on is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field *ngIf="clientChargeForm.contains('feeOnMonthDay')">
<mat-label>Due On</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="feeOnMonthDayPicker" required
formControlName="feeOnMonthDay">
<mat-datepicker-toggle matSuffix [for]="feeOnMonthDayPicker"></mat-datepicker-toggle>
<mat-datepicker #feeOnMonthDayPicker></mat-datepicker>
<mat-error *ngIf="clientChargeForm.controls.feeOnMonthDay.hasError('required')">
Due Date is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field *ngIf="clientChargeForm.contains('feeInterval')">
<mat-label>Repeats Every</mat-label>
<input matInput formControlName="feeInterval" />
</mat-form-field>
</div>
</div>
<mat-card-actions fxLayoutGap="5px" fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center">
<button type="button" mat-raised-button [routerLink]="['../../']">Cancel</button>
<button mat-raised-button color="primary" [disabled]="!clientChargeForm.valid">Submit</button>
</mat-card-actions>
</mat-card-content>
</form>
</mat-card>
</div>
@@ -0,0 +1,3 @@
.container {
width: 37rem;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AddClientChargeComponent } from './add-client-charge.component';
describe('AddClientChargeComponent', () => {
let component: AddClientChargeComponent;
let fixture: ComponentFixture<AddClientChargeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AddClientChargeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AddClientChargeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,140 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { DatePipe } from '@angular/common';
/** Custom Services */
import { ClientsService } from 'app/clients/clients.service';
/**
* Add Clients Charge component.
*/
@Component({
selector: 'mifosx-add-client-charge',
templateUrl: './add-client-charge.component.html',
styleUrls: ['./add-client-charge.component.scss']
})
export class AddClientChargeComponent implements OnInit {
/** Minimum Due Date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum Due Date allowed. */
maxDate = new Date();
/** Add Clients Charge form. */
clientChargeForm: FormGroup;
/** clients charge options. */
clientChargeOptions: any;
/** clients Id */
clientId: string;
/** charge details */
chargeDetails: any;
/**
* Retrieves charge template data from `resolve`
* @param {FormBuilder} formBuilder Form Builder
* @param {ActivatedRoute} route Activated Route
* @param {Router} router Router
* @param {DatePipe} datePipe Date Pipe
* @param {ClientsService} clientsService Clients Service
*/
constructor(
private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private datePipe: DatePipe,
private clientsService: ClientsService
) {
this.route.data.subscribe((data: { clientActionData: any }) => {
this.clientChargeOptions = data.clientActionData.chargeOptions;
});
this.clientId = this.route.parent.snapshot.params['clientId'];
}
ngOnInit() {
this.createClientsChargeForm();
this.buildDependencies();
}
/**
* Subscribe to form controls value changes
*/
buildDependencies() {
this.clientChargeForm.controls.chargeId.valueChanges.subscribe(chargeId => {
this.clientsService.getChargeAndTemplate(chargeId).subscribe((data: any) => {
this.chargeDetails = data;
const chargeTimeType = data.chargeTimeType.id;
if (data.chargeTimeType.value === 'Withdrawal Fee' || data.chargeTimeType.value === 'Saving No Activity Fee') {
this.chargeDetails.dueDateNotRequired = true;
}
if (data.chargeTimeType.value === 'Annual Fee' || data.chargeTimeType.value === 'Monthly Fee') {
this.chargeDetails.chargeTimeTypeAnnualOrMonth = true;
}
if (!this.chargeDetails.dueDateNotRequired && !this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
this.clientChargeForm.addControl('dueDate', new FormControl('', Validators.required));
} else {
this.clientChargeForm.removeControl('dueDate');
}
if (!this.chargeDetails.dueDateNotRequired && this.chargeDetails.chargeTimeTypeAnnualOrMonth) {
this.clientChargeForm.addControl('feeOnMonthDay', new FormControl('', Validators.required));
} else {
this.clientChargeForm.removeControl('feeOnMonthDay');
}
if (chargeTimeType.value === 'Monthly Fee') {
this.clientChargeForm.addControl('feeInterval', new FormControl(data.feeInterval, Validators.required));
} else {
this.clientChargeForm.removeControl('feeInterval');
}
this.clientChargeForm.patchValue({
'amount': data.amount,
'chargeCalculationType': data.chargeCalculationType.id,
'chargeTimeType': data.chargeTimeType.id
});
});
});
}
/**
* Creates the Clients Charge form.
*/
createClientsChargeForm() {
this.clientChargeForm = this.formBuilder.group({
'chargeId': ['', Validators.required],
'amount': ['', Validators.required],
'chargeCalculationType': [{ value: '', disabled: true }],
'chargeTimeType': [{ value: '', disabled: true }]
});
}
/**
* Submits Client charge.
*/
submit() {
const clientCharge = this.clientChargeForm.value;
clientCharge.locale = 'en';
if (!clientCharge.feeInterval) {
clientCharge.feeInterval = this.chargeDetails.feeInterval;
}
if (this.chargeDetails.dueDateNotRequired !== true) {
if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) {
const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup
clientCharge.monthDayFormat = monthDayFormat;
if (clientCharge.feeOnMonthDay) {
const prevDate = this.clientChargeForm.value.feeOnMonthDay;
clientCharge.feeOnMonthDay = this.datePipe.transform(prevDate, monthDayFormat);
}
} else {
const dateFormat = 'yyyy-MM-dd';
clientCharge.dateFormat = dateFormat;
if (clientCharge.dueDate) {
const prevDate = this.clientChargeForm.value.dueDate;
clientCharge.dueDate = this.datePipe.transform(prevDate, dateFormat);
}
}
}
this.clientsService.createClientCharge(this.clientId, clientCharge).subscribe( () => {
this.router.navigate(['../../'], { relativeTo: this.route });
});
}
}
@@ -11,3 +11,4 @@
<mifosx-accept-client-transfer *ngIf="actions['Accept Transfer']"></mifosx-accept-client-transfer>
<mifosx-reactivate-client *ngIf="actions['Reactivate']"></mifosx-reactivate-client>
<mifosx-undo-client-rejection *ngIf="actions['Undo Rejection']"></mifosx-undo-client-rejection>
<mifosx-add-client-charge *ngIf="actions['Add Charge']"></mifosx-add-client-charge>
@@ -26,6 +26,7 @@ export class ClientActionsComponent {
'Reject Transfer': boolean
'Reactivate': boolean
'Undo Rejection': boolean
'Add Charge': boolean
} = {
'Assign Staff': false,
'Close': false,
@@ -38,7 +39,8 @@ export class ClientActionsComponent {
'Accept Transfer': false,
'Reject Transfer': false,
'Reactivate': false,
'Undo Rejection': false
'Undo Rejection': false,
'Add Charge': false
};
/**
@@ -46,6 +46,7 @@
<button mat-menu-item (click)="doAction('Survey')"> Survey</button>
<button mat-menu-item (click)="doAction('Update Default Savings')"> Update Default Savings </button>
<button mat-menu-item (click)="doAction('Transfer Client')"> Transfer Client </button>
<button mat-menu-item (click)="doAction('Add Charge')"> Add Charge </button>
<span *ngIf="clientViewData.status.value === 'Transfer in progress'"><button mat-menu-item (click)="doAction('Undo Transfer')">Undo Transfer</button></span>
<span *ngIf="clientViewData.status.value === 'Transfer in progress'"><button mat-menu-item (click)="doAction('Accept Transfer')">Accept Transfer</button></span>
<span *ngIf="clientViewData.status.value === 'Transfer in progress'"><button mat-menu-item (click)="doAction('Reject Transfer')">Reject transfer</button></span>
@@ -68,6 +68,7 @@ export class ClientsViewComponent implements OnInit {
case 'Reject Transfer':
case 'Reactivate':
case 'Undo Rejection':
case 'Add Charge':
this.router.navigate([`actions/${name}`], { relativeTo: this.route });
break;
case 'Unassign Staff':
+3 -1
View File
@@ -41,6 +41,7 @@ import { RejectClientTransferComponent } from './clients-view/client-actions/rej
import { AcceptClientTransferComponent } from './clients-view/client-actions/accept-client-transfer/accept-client-transfer.component';
import { ReactivateClientComponent } from './clients-view/client-actions/reactivate-client/reactivate-client.component';
import { UndoClientRejectionComponent } from './clients-view/client-actions/undo-client-rejection/undo-client-rejection.component';
import { AddClientChargeComponent } from './clients-view/client-actions/add-client-charge/add-client-charge.component';
/**
@@ -87,7 +88,8 @@ import { UndoClientRejectionComponent } from './clients-view/client-actions/undo
RejectClientTransferComponent,
AcceptClientTransferComponent,
ReactivateClientComponent,
UndoClientRejectionComponent
UndoClientRejectionComponent,
AddClientChargeComponent
],
entryComponents: [
UploadDocumentDialogComponent,
+13
View File
@@ -224,6 +224,19 @@ export class ClientsService {
return this.http.get(`/clients/${clientId}/transferproposaldate`);
}
getClientChargeTemplate(clientId: any): Observable<any> {
return this.http.get(`/clients/${clientId}/charges/template`);
}
getChargeAndTemplate(chargeId: any): Observable<any> {
const httpParams = new HttpParams().set('template', 'true');
return this.http.get(`/charges/${chargeId}`, { params: httpParams });
}
createClientCharge(clientId: any, charge: any) {
return this.http.post(`/clients/${clientId}/charges`, charge);
}
/**
* @returns {Observable<any>} Offices data
*/
@@ -45,6 +45,8 @@ export class ClientActionsResolver implements Resolve<Object> {
case 'Accept Transfer':
case 'Reject Transfer':
return this.clientsService.getClientTransferProposalDate(clientId);
case 'Add Charge':
return this.clientsService.getClientChargeTemplate(clientId);
default:
return undefined;
}