+
Name
diff --git a/src/app/loans/loans-view/view-charge/view-charge.component.scss b/src/app/loans/loans-view/view-charge/view-charge.component.scss
index 56668f14f..7fa0ec4ad 100644
--- a/src/app/loans/loans-view/view-charge/view-charge.component.scss
+++ b/src/app/loans/loans-view/view-charge/view-charge.component.scss
@@ -1,6 +1,8 @@
+@import "assets/styles/helper";
+
.container {
max-width: 37rem;
-
+
.content {
div {
margin: 1rem 0;
@@ -8,3 +10,13 @@
}
}
}
+
+.paid {
+ background-color: $status-active;
+ height: 4px;
+}
+
+.not-paid {
+ background-color: $status-active-overdue;
+ height: 4px;
+}
diff --git a/src/app/loans/loans-view/view-charge/view-charge.component.ts b/src/app/loans/loans-view/view-charge/view-charge.component.ts
index 2378d21ca..cb77c65f2 100644
--- a/src/app/loans/loans-view/view-charge/view-charge.component.ts
+++ b/src/app/loans/loans-view/view-charge/view-charge.component.ts
@@ -52,7 +52,7 @@ export class ViewChargeComponent {
private settingsService: SettingsService) {
this.route.data.subscribe((data: { loansAccountCharge: any, loanDetailsData: any }) => {
this.chargeData = data.loansAccountCharge;
- this.allowPayCharge = (this.chargeData.chargeTimeType.code === 'chargeTimeType.instalmentFee');
+ this.allowPayCharge = (this.chargeData.chargePayable && !this.chargeData.paid);
this.allowWaive = !this.chargeData.chargeTimeType.waived;
this.loansAccountData = data.loanDetailsData;
});
@@ -72,7 +72,7 @@ export class ViewChargeComponent {
})
];
const data = {
- title: 'Pay Charge',
+ title: `Pay Charge ${this.chargeData.id}`,
layout: { addButtonText: 'Confirm' },
formfields: formfields
};
@@ -173,6 +173,10 @@ export class ViewChargeComponent {
});
}
+ loanChargeColor(): string {
+ return this.chargeData.paid ? 'paid' : 'not-paid';
+ }
+
/**
* Refetches data fot the component
* TODO: Replace by a custom reload component instead of hard-coded back-routing.
diff --git a/src/app/loans/loans.module.ts b/src/app/loans/loans.module.ts
index 2952e51ed..70e9d348f 100644
--- a/src/app/loans/loans.module.ts
+++ b/src/app/loans/loans.module.ts
@@ -73,6 +73,7 @@ import { LoanDelinquencyTagsTabComponent } from './loans-view/loan-delinquency-t
import { LoansAccountScheduleStepComponent } from './loans-account-stepper/loans-account-schedule-step/loans-account-schedule-step.component';
import { EditRepaymentScheduleComponent } from './loans-view/loan-account-actions/edit-repayment-schedule/edit-repayment-schedule.component';
import { DisburseToSavingsAccountComponent } from './loans-view/loan-account-actions/disburse-to-savings-account/disburse-to-savings-account.component';
+import { LoansAccountDatatableStepComponent } from './loans-account-stepper/loans-account-datatable-step/loans-account-datatable-step.component';
/**
* Loans Module
@@ -144,7 +145,8 @@ import { DisburseToSavingsAccountComponent } from './loans-view/loan-account-act
LoanDelinquencyTagsTabComponent,
LoansAccountScheduleStepComponent,
EditRepaymentScheduleComponent,
- DisburseToSavingsAccountComponent
+ DisburseToSavingsAccountComponent,
+ LoansAccountDatatableStepComponent
],
providers: [ ],
})
diff --git a/src/app/loans/loans.service.ts b/src/app/loans/loans.service.ts
index ef813d93c..fa043dd6d 100644
--- a/src/app/loans/loans.service.ts
+++ b/src/app/loans/loans.service.ts
@@ -322,6 +322,10 @@ export class LoansService {
return this.http.get(`/loans/${loanId}/documents`);
}
+ downloadLoanDocument(parentEntityId: string, documentId: string) {
+ return this.http.get(`/loans/${parentEntityId}/documents/${documentId}/attachment`, { responseType: 'blob' });
+ }
+
deleteLoanDocument(loanId: any, documentId: any): Observable {
return this.http.delete(`/loans/${loanId}/documents/${documentId}`);
}
diff --git a/src/app/savings/common-resolvers/saving-documents.resolver.spec.ts b/src/app/savings/common-resolvers/saving-documents.resolver.spec.ts
new file mode 100644
index 000000000..5531c2b4f
--- /dev/null
+++ b/src/app/savings/common-resolvers/saving-documents.resolver.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { SavingDocumentsResolver } from './saving-documents.resolver';
+
+describe('SavingDocumentsResolver', () => {
+ let resolver: SavingDocumentsResolver;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ resolver = TestBed.inject(SavingDocumentsResolver);
+ });
+
+ it('should be created', () => {
+ expect(resolver).toBeTruthy();
+ });
+});
diff --git a/src/app/savings/common-resolvers/saving-documents.resolver.ts b/src/app/savings/common-resolvers/saving-documents.resolver.ts
new file mode 100644
index 000000000..519c7910b
--- /dev/null
+++ b/src/app/savings/common-resolvers/saving-documents.resolver.ts
@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+import {
+ Resolve,
+ ActivatedRouteSnapshot
+} from '@angular/router';
+import { Observable } from 'rxjs';
+import { SavingsService } from '../savings.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SavingDocumentsResolver implements Resolve {
+
+ /**
+ * @param {SavingsService} savingsService Savings service.
+ */
+ constructor(private savingsService: SavingsService) { }
+
+ /**
+ * Returns the Savings data.
+ * @returns {Observable}
+ */
+ resolve(route: ActivatedRouteSnapshot): Observable {
+ const savingAccountId = route.parent.paramMap.get('savingAccountId');
+ return this.savingsService.getSavingsDocuments(savingAccountId);
+ }
+}
diff --git a/src/app/savings/common-resolvers/saving-notes.resolver.spec.ts b/src/app/savings/common-resolvers/saving-notes.resolver.spec.ts
new file mode 100644
index 000000000..24bc375e0
--- /dev/null
+++ b/src/app/savings/common-resolvers/saving-notes.resolver.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { SavingNotesResolver } from './saving-notes.resolver';
+
+describe('SavingNotesResolver', () => {
+ let resolver: SavingNotesResolver;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ resolver = TestBed.inject(SavingNotesResolver);
+ });
+
+ it('should be created', () => {
+ expect(resolver).toBeTruthy();
+ });
+});
diff --git a/src/app/savings/common-resolvers/saving-notes.resolver.ts b/src/app/savings/common-resolvers/saving-notes.resolver.ts
new file mode 100644
index 000000000..a418126de
--- /dev/null
+++ b/src/app/savings/common-resolvers/saving-notes.resolver.ts
@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+import {
+ Resolve,
+ ActivatedRouteSnapshot
+} from '@angular/router';
+import { Observable } from 'rxjs';
+import { SavingsService } from '../savings.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class SavingNotesResolver implements Resolve {
+
+ /**
+ * @param {SavingsService} savingsService Savings service.
+ */
+ constructor(private savingsService: SavingsService) { }
+
+ /**
+ * Returns the Savings data.
+ * @returns {Observable}
+ */
+ resolve(route: ActivatedRouteSnapshot): Observable {
+ const savingAccountId = route.parent.paramMap.get('savingAccountId');
+ return this.savingsService.getSavingsNotes(savingAccountId);
+ }
+}
diff --git a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts
index a86cb3f8a..1bb0025d8 100644
--- a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts
+++ b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts
@@ -135,7 +135,7 @@ export class ChargesTabComponent implements OnInit {
dateFormat,
locale
};
- this.savingsService.executeSavingsAccountChargesCommand(this.savingsAccountData.id, 'paycharge', dataObject, chargeId)
+ this.savingsService.executeSavingsAccountChargesCommand(this.savingsAccountData.id, 'pay', dataObject, chargeId)
.subscribe(() => {
this.reload();
});
diff --git a/src/app/savings/savings-account-view/notes-tab/notes-tab.component.html b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.html
new file mode 100644
index 000000000..04cf7318f
--- /dev/null
+++ b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.html
@@ -0,0 +1,7 @@
+
+
diff --git a/src/app/savings/savings-account-view/notes-tab/notes-tab.component.scss b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/savings/savings-account-view/notes-tab/notes-tab.component.spec.ts b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.spec.ts
new file mode 100644
index 000000000..017254b1f
--- /dev/null
+++ b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NotesTabComponent } from './notes-tab.component';
+
+describe('NotesTabComponent', () => {
+ let component: NotesTabComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ NotesTabComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NotesTabComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/savings/savings-account-view/notes-tab/notes-tab.component.ts b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.ts
new file mode 100644
index 000000000..98f0647cc
--- /dev/null
+++ b/src/app/savings/savings-account-view/notes-tab/notes-tab.component.ts
@@ -0,0 +1,55 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { AuthenticationService } from 'app/core/authentication/authentication.service';
+import { SavingsService } from 'app/savings/savings.service';
+
+@Component({
+ selector: 'mifosx-notes-tab',
+ templateUrl: './notes-tab.component.html',
+ styleUrls: ['./notes-tab.component.scss']
+})
+export class NotesTabComponent implements OnInit {
+
+ entityId: string;
+ username: string;
+ entityNotes: any;
+
+ constructor(private route: ActivatedRoute,
+ private savingsService: SavingsService,
+ private authenticationService: AuthenticationService) {
+ const savedCredentials = this.authenticationService.getCredentials();
+ this.username = savedCredentials.username;
+ this.entityId = this.route.parent.snapshot.params['savingAccountId'];
+ this.route.data.subscribe((data: { savingAccountNotes: any }) => {
+ this.entityNotes = data.savingAccountNotes;
+ });
+ }
+
+ ngOnInit() {
+ }
+
+ addNote(noteContent: any) {
+ this.savingsService.createSavingsNote(this.entityId, noteContent).subscribe((response: any) => {
+ this.entityNotes.push({
+ id: response.resourceId,
+ createdByUsername: this.username,
+ createdOn: new Date(),
+ note: noteContent
+ });
+ });
+ }
+
+ editNote(noteId: string, noteContent: any, index: number) {
+ this.savingsService.editSavingsNote(this.entityId, noteId, noteContent).subscribe(() => {
+ this.entityNotes[index].note = noteContent.note;
+ });
+ }
+
+ deleteNote(noteId: string, index: number) {
+ this.savingsService.deleteSavingsNote(this.entityId, noteId)
+ .subscribe(() => {
+ this.entityNotes.splice(index, 1);
+ });
+ }
+
+}
diff --git a/src/app/savings/savings-account-view/savings-account-view.component.html b/src/app/savings/savings-account-view/savings-account-view.component.html
index b2e186e22..ae15da436 100644
--- a/src/app/savings/savings-account-view/savings-account-view.component.html
+++ b/src/app/savings/savings-account-view/savings-account-view.component.html
@@ -34,10 +34,10 @@
{{entityType}} Name: {{savingsAccountData.clientName || savingsAccountData.groupName}}
({{savingsAccountData.clientAccountNo}})
- Current Balances: + Current Balances : {{savingsAccountData.currency.displaySymbol}}{{savingsAccountData.summary.accountBalance | number}}
- Available Balance: + Available Balance : {{savingsAccountData.currency.displaySymbol}}{{savingsAccountData.summary.availableBalance | number}} @@ -310,6 +310,14 @@ [active]="charges.isActive"> Charges + + Savings Documents + + + Notes +
+
diff --git a/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.scss b/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.spec.ts b/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.spec.ts
new file mode 100644
index 000000000..80b91a7fe
--- /dev/null
+++ b/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SavingsDocumentsTabComponent } from './savings-documents-tab.component';
+
+describe('SavingsDocumentsTabComponent', () => {
+ let component: SavingsDocumentsTabComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ SavingsDocumentsTabComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SavingsDocumentsTabComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.ts b/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.ts
new file mode 100644
index 000000000..b0829ac7b
--- /dev/null
+++ b/src/app/savings/savings-account-view/savings-documents-tab/savings-documents-tab.component.ts
@@ -0,0 +1,71 @@
+import { Component, OnInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { ActivatedRoute } from '@angular/router';
+import { UploadDocumentDialogComponent } from 'app/clients/clients-view/custom-dialogs/upload-document-dialog/upload-document-dialog.component';
+import { SavingsService } from 'app/savings/savings.service';
+import { SettingsService } from 'app/settings/settings.service';
+import { environment } from 'environments/environment';
+
+@Component({
+ selector: 'mifosx-savings-documents-tab',
+ templateUrl: './savings-documents-tab.component.html',
+ styleUrls: ['./savings-documents-tab.component.scss']
+})
+export class SavingsDocumentsTabComponent implements OnInit {
+
+ /** Stores the resolved savings documents data */
+ entityDocuments: any;
+ /** Stores the saving Account Id */
+ entityId: string;
+ entityType: string = 'savings';
+
+ /**
+ * Retrieves the savings data from `resolve`.
+ * @param {ActivatedRoute} route Activated Route.
+ */
+ constructor(private route: ActivatedRoute,
+ private savingsService: SavingsService,
+ private settingsService: SettingsService,
+ public dialog: MatDialog) {
+ this.route.data.subscribe((data: { savingsDocuments: any }) => {
+ this.setSavingsDocumentsData(data.savingsDocuments);
+ });
+ this.entityId = this.route.parent.snapshot.params['savingAccountId'];
+ }
+
+ ngOnInit() {
+ }
+
+ setSavingsDocumentsData(data: any) {
+ data.forEach((ele: any) => {
+ ele.docUrl = this.settingsService.serverUrl + '/savings/' + ele.parentEntityId + '/documents/' + ele.id + '/attachment?tenantIdentifier=' + environment.fineractPlatformTenantId;
+ if (ele.fileName) {
+ if (ele.fileName.toLowerCase().indexOf('.jpg') !== -1 || ele.fileName.toLowerCase().indexOf('.jpeg') !== -1 || ele.fileName.toLowerCase().indexOf('.png') !== -1) {
+ ele.fileIsImage = true;
+ }
+ }
+ if (ele.type) {
+ if (ele.type.toLowerCase().indexOf('image') !== -1) {
+ ele.fileIsImage = true;
+ }
+ }
+ });
+ this.entityDocuments = data;
+ }
+
+ downloadDocument(parentEntityId: string, documentId: string) {
+ this.savingsService.downloadSavingsDocument(parentEntityId, documentId).subscribe(res => {
+ const url = window.URL.createObjectURL(res);
+ window.open(url);
+ });
+ }
+
+ uploadDocument(formData: FormData): any {
+ return this.savingsService.loadSavingsDocument(this.entityId, formData);
+ }
+
+ deleteDocument(documentId: any) {
+ this.savingsService.deleteSavingsDocument(this.entityId, documentId).subscribe((res: any) => {});
+ }
+
+}
diff --git a/src/app/savings/savings-account-view/view-charge/view-charge.component.ts b/src/app/savings/savings-account-view/view-charge/view-charge.component.ts
index e337b4d59..23bdb777e 100644
--- a/src/app/savings/savings-account-view/view-charge/view-charge.component.ts
+++ b/src/app/savings/savings-account-view/view-charge/view-charge.component.ts
@@ -93,7 +93,7 @@ export class ViewChargeComponent {
dateFormat,
locale
};
- this.savingsService.executeSavingsAccountChargesCommand(this.chargeData.accountId, 'paycharge', dataObject, this.chargeData.id)
+ this.savingsService.executeSavingsAccountChargesCommand(this.chargeData.accountId, 'pay', dataObject, this.chargeData.id)
.subscribe(() => {
this.reload();
});
diff --git a/src/app/savings/savings-routing.module.ts b/src/app/savings/savings-routing.module.ts
index 327d5778b..2605e4565 100644
--- a/src/app/savings/savings-routing.module.ts
+++ b/src/app/savings/savings-routing.module.ts
@@ -37,6 +37,11 @@ import { GSIMAccountsResolver } from 'app/groups/common-resolvers/gsim-account-r
import { GroupAccountsResolver } from 'app/groups/common-resolvers/group-account.resolver';
import { GSIMViewResolver } from './gsim-account/gsim-account.resolver';
import { GroupViewResolver } from 'app/groups/common-resolvers/group-view.resolver';
+import { SavingsDocumentsTabComponent } from './savings-account-view/savings-documents-tab/savings-documents-tab.component';
+import { NotesTabComponent } from './savings-account-view/notes-tab/notes-tab.component';
+import { SavingNotesResolver } from './common-resolvers/saving-notes.resolver';
+import { SavingDocumentsResolver } from './common-resolvers/saving-documents.resolver';
+import { DocumentsTabComponent } from 'app/clients/clients-view/documents-tab/documents-tab.component';
/** Savings Routes */
const routes: Routes = [
{
@@ -91,6 +96,22 @@ const routes: Routes = [
component: StandingInstructionsTabComponent,
data: { title: extract('Savings Account SIH'), breadcrumb: 'Standing Instructions', routeParamBreadcrumb: false }
},
+ {
+ path: 'notes',
+ component: NotesTabComponent,
+ data: { title: extract('Savings Account Notes'), breadcrumb: 'Notes', routeParamBreadcrumb: false },
+ resolve: {
+ savingAccountNotes: SavingNotesResolver
+ }
+ },
+ {
+ path: 'documents',
+ component: DocumentsTabComponent,
+ data: { title: extract('Savings Account Documents'), breadcrumb: 'Documents', routeParamBreadcrumb: false },
+ resolve: {
+ savingAccountDocuments: SavingDocumentsResolver
+ }
+ },
{
path: 'datatables',
children: [
@@ -184,6 +205,26 @@ const routes: Routes = [
savingsAccountActionData: SavingsAccountActionsResolver
}
},
+ {
+ path: 'documents',
+ data: { title: extract('Savings Account Documents'), breadcrumb: 'Documents', routeParamBreadcrumb: false },
+ children: [
+ {
+ path: '',
+ redirectTo: '../documents', pathMatch: 'prefix'
+ },
+ ]
+ },
+ {
+ path: 'notes',
+ data: { title: extract('Savings Account Notes'), breadcrumb: 'Notes', routeParamBreadcrumb: false },
+ children: [
+ {
+ path: '',
+ redirectTo: '../notes', pathMatch: 'prefix'
+ },
+ ]
+ },
{
path: 'transfer-funds',
loadChildren: () => import('../account-transfers/account-transfers.module').then(m => m.AccountTransfersModule)
diff --git a/src/app/savings/savings.module.ts b/src/app/savings/savings.module.ts
index 643e96228..cd30dfd65 100644
--- a/src/app/savings/savings.module.ts
+++ b/src/app/savings/savings.module.ts
@@ -49,6 +49,8 @@ import { GsimAccountComponent } from './gsim-account/gsim-account.component';
import { CreateGsimAccountComponent } from './gsim-account/create-gsim-account/create-gsim-account.component';
import { ManageSavingsAccountComponent } from './saving-account-actions/manage-savings-account/manage-savings-account.component';
import { ReleaseAmountDialogComponent } from './savings-account-view/custom-dialogs/release-amount-dialog/release-amount-dialog.component';
+import { SavingsDocumentsTabComponent } from './savings-account-view/savings-documents-tab/savings-documents-tab.component';
+import { NotesTabComponent } from './savings-account-view/notes-tab/notes-tab.component';
/**
@@ -104,7 +106,9 @@ import { ReleaseAmountDialogComponent } from './savings-account-view/custom-dial
GsimAccountComponent,
CreateGsimAccountComponent,
ManageSavingsAccountComponent,
- ReleaseAmountDialogComponent
+ ReleaseAmountDialogComponent,
+ SavingsDocumentsTabComponent,
+ NotesTabComponent
],
providers: [ ]
})
diff --git a/src/app/savings/savings.service.ts b/src/app/savings/savings.service.ts
index a523ea0ac..3d1cda9d8 100644
--- a/src/app/savings/savings.service.ts
+++ b/src/app/savings/savings.service.ts
@@ -286,4 +286,61 @@ export class SavingsService {
return this.http.post(`/savingsaccounts/gsim`, gsimData);
}
+ /**
+ * @param savingAccountId Savings Id
+ * @returns The notes for particular loan
+ */
+ getSavingsNotes(savingAccountId: string): Observable {
+ return this.http.get(`/savings/${savingAccountId}/notes`);
+ }
+
+ /**
+ * Adds a note to the particular Savings Id
+ * @param savingAccountId Savings ID
+ * @param noteData Note Data to be added
+ * @returns {Observable}
+ */
+ createSavingsNote(savingAccountId: string, noteData: any): Observable {
+ return this.http.post(`/savings/${savingAccountId}/notes`, noteData);
+ }
+
+ /**
+ * Edits the Savings Note
+ * @param savingAccountId Savings ID
+ * @param noteId Note ID
+ * @param noteData Note Data
+ */
+ editSavingsNote(savingAccountId: string, noteId: string, noteData: any) {
+ return this.http.put(`/savings/${savingAccountId}/notes/${noteId}`, noteData);
+ }
+
+ /**
+ * Deletes the particular Note
+ * @param savingAccountId Savings ID
+ * @param noteId Note ID
+ */
+ deleteSavingsNote(savingAccountId: string, noteId: string) {
+ return this.http.delete(`/savings/${savingAccountId}/notes/${noteId}`);
+ }
+
+ /**
+ * @param savingAccountId Savings Account Id of account to get data for.
+ * @returns {Observable} Savings data.
+ */
+ getSavingsDocuments(savingAccountId: any): Observable {
+ return this.http.get(`/savings/${savingAccountId}/documents`);
+ }
+
+ downloadSavingsDocument(parentEntityId: string, documentId: string) {
+ return this.http.get(`/savings/${parentEntityId}/documents/${documentId}/attachment`, { responseType: 'blob' });
+ }
+
+ deleteSavingsDocument(savingAccountId: any, documentId: any): Observable {
+ return this.http.delete(`/savings/${savingAccountId}/documents/${documentId}`);
+ }
+
+ loadSavingsDocument(savingAccountId: any, data: any): Observable {
+ return this.http.post(`/savings/${savingAccountId}/documents`, data);
+ }
+
}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index b17559b44..fe5368817 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -29,6 +29,9 @@ import { MaterialModule } from './material.module';
import { TranslateModule } from '@ngx-translate/core';
import { ExternalIdentifierComponent } from './external-identifier/external-identifier.component';
import { PipesModule } from 'app/pipes/pipes.module';
+import { EntityNotesTabComponent } from './tabs/entity-notes-tab/entity-notes-tab.component';
+import { EntityDocumentsTabComponent } from './tabs/entity-documents-tab/entity-documents-tab.component';
+import { DirectivesModule } from 'app/directives/directives.module';
/**
* Shared Module
@@ -42,7 +45,8 @@ import { PipesModule } from 'app/pipes/pipes.module';
MaterialModule,
ReactiveFormsModule,
TranslateModule.forRoot(),
- PipesModule
+ PipesModule,
+ DirectivesModule
],
declarations: [
FormfieldComponent,
@@ -63,7 +67,9 @@ import { PipesModule } from 'app/pipes/pipes.module';
SearchToolComponent,
ServerSelectorComponent,
TenantSelectorComponent,
- ExternalIdentifierComponent
+ ExternalIdentifierComponent,
+ EntityNotesTabComponent,
+ EntityDocumentsTabComponent
],
exports: [
FileUploadComponent,
@@ -81,7 +87,9 @@ import { PipesModule } from 'app/pipes/pipes.module';
ReactiveFormsModule,
TranslateModule,
TenantSelectorComponent,
- ExternalIdentifierComponent
+ ExternalIdentifierComponent,
+ EntityNotesTabComponent,
+ EntityDocumentsTabComponent
]
})
export class SharedModule { }
diff --git a/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.html b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.html
new file mode 100644
index 000000000..f9eee5951
--- /dev/null
+++ b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.html
@@ -0,0 +1,50 @@
+;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ EntityDocumentsTabComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(EntityDocumentsTabComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.ts b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.ts
new file mode 100644
index 000000000..45bc21233
--- /dev/null
+++ b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.ts
@@ -0,0 +1,108 @@
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatPaginator } from '@angular/material/paginator';
+import { MatSort } from '@angular/material/sort';
+import { MatTable, MatTableDataSource } from '@angular/material/table';
+import { UploadDocumentDialogComponent } from 'app/clients/clients-view/custom-dialogs/upload-document-dialog/upload-document-dialog.component';
+import { ClientsService } from 'app/clients/clients.service';
+import { LoansService } from 'app/loans/loans.service';
+import { SavingsService } from 'app/savings/savings.service';
+import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
+import { Observable } from 'rxjs';
+
+@Component({
+ selector: 'mifosx-entity-documents-tab',
+ templateUrl: './entity-documents-tab.component.html',
+ styleUrls: ['./entity-documents-tab.component.scss']
+})
+export class EntityDocumentsTabComponent implements OnInit {
+ @ViewChild('documentsTable', { static: true }) documentsTable: MatTable;
+
+ @Input() entityId: string;
+ @Input() entityType: string;
+ @Input() entityDocuments: any;
+
+ @Input() callbackUpload: (documentData: FormData) => Observable;
+ @Input() callbackDownload: (documentId: string) => void;
+ @Input() callbackDelete: (documentId: string) => void;
+
+ /** Status of the loan account */
+ status: any;
+ /** Choice */
+ choice: boolean;
+
+ /** Columns to be displayed in loan documents table. */
+ displayedColumns: string[] = ['name', 'description', 'filename', 'actions'];
+ /** Data source for loan documents table. */
+ dataSource: MatTableDataSource;
+
+ /** Paginator for codes table. */
+ @ViewChild(MatPaginator) paginator: MatPaginator;
+ /** Sorter for codes table. */
+ @ViewChild(MatSort) sort: MatSort;
+
+ /**
+ *
+ * @param {MatDialog} dialog Dialog for Inputs.
+ * @param {SavingsService} savingsService Savings Account services.
+ * @param {LoansService} loansService Loan Account services.
+ * @param {ClientsService} clientsService Client services.
+ */
+ constructor(public dialog: MatDialog,
+ private savingsService: SavingsService,
+ private loansService: LoansService,
+ private clientsService: ClientsService) { }
+
+ ngOnInit() {
+ this.dataSource = new MatTableDataSource(this.entityDocuments);
+ this.dataSource.paginator = this.paginator;
+ this.dataSource.sort = this.sort;
+ }
+
+ downloadDocument(documentId: string) {
+ this.callbackDownload(documentId);
+ }
+
+ uploadDocument() {
+ const uploadDocumentDialogRef = this.dialog.open(UploadDocumentDialogComponent, {
+ data: { documentIdentifier: false, entityType: 'Loan' }
+ });
+ uploadDocumentDialogRef.afterClosed().subscribe((dialogResponse: any) => {
+ if (dialogResponse) {
+ const formData: FormData = new FormData;
+ formData.append('name', dialogResponse.fileName);
+ formData.append('file', dialogResponse.file);
+ formData.append('description', dialogResponse.description);
+ this.callbackUpload(formData).subscribe((res: any) => {
+ this.entityDocuments.push({
+ id: res.resourceId,
+ parentEntityType: this.entityType,
+ parentEntityId: this.entityId,
+ name: dialogResponse.fileName,
+ description: dialogResponse.description,
+ fileName: dialogResponse.file.name
+ });
+ this.documentsTable.renderRows();
+ });
+ }
+ });
+ }
+
+ deleteDocument(documentId: string, name: number) {
+ const deleteDocumentDialogRef = this.dialog.open(DeleteDialogComponent, {
+ data: { deleteContext: `Document: ${name}` }
+ });
+ deleteDocumentDialogRef.afterClosed().subscribe((response: any) => {
+ if (response.delete) {
+ this.callbackDelete(documentId);
+ for (let i = 0; i < this.entityDocuments.length; i++) {
+ if (this.entityDocuments[i].id === documentId) {
+ this.entityDocuments.splice(i, 1);
+ }
+ }
+ this.documentsTable.renderRows();
+ }
+ });
+ }
+
+}
diff --git a/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.html b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.html
new file mode 100644
index 000000000..5d8039bdc
--- /dev/null
+++ b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.html
@@ -0,0 +1,35 @@
+;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ EntityNotesTabComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(EntityNotesTabComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.ts b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.ts
new file mode 100644
index 000000000..ceab73be7
--- /dev/null
+++ b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.ts
@@ -0,0 +1,83 @@
+import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { MatDialog } from '@angular/material/dialog';
+import { ClientsService } from 'app/clients/clients.service';
+import { LoansService } from 'app/loans/loans.service';
+import { SavingsService } from 'app/savings/savings.service';
+import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
+import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
+
+@Component({
+ selector: 'mifosx-entity-notes-tab',
+ templateUrl: './entity-notes-tab.component.html',
+ styleUrls: ['./entity-notes-tab.component.scss']
+})
+export class EntityNotesTabComponent implements OnInit {
+
+ @ViewChild('formRef', { static: true }) formRef: any;
+
+ @Input() entityId: string;
+ @Input() entityNotes: any;
+
+ @Input() callbackAdd: (note: any) => void;
+ @Input() callbackEdit: (noteId: string, note: string, index: number) => void;
+ @Input() callbackDelete: (noteId: string, index: number) => void;
+
+ noteForm: FormGroup;
+
+ constructor(private formBuilder: FormBuilder,
+ private savingsService: SavingsService,
+ private loansService: LoansService,
+ private clientsService: ClientsService,
+ private dialog: MatDialog) { }
+
+ ngOnInit() {
+ this.createNoteForm();
+ }
+
+ createNoteForm() {
+ this.noteForm = this.formBuilder.group({
+ 'note': ['', Validators.required]
+ });
+ }
+
+ addNote() {
+ this.callbackAdd(this.noteForm.value);
+ this.formRef.resetForm();
+ }
+
+ editNote(noteId: string, noteContent: string, index: number) {
+ const editNoteDialogRef = this.dialog.open(FormDialogComponent, {
+ data: { formfields: [{
+ controlName: 'note',
+ required: true,
+ value: noteContent,
+ controlType: 'input',
+ label: 'Note'
+ }],
+ layout: {
+ columns: 1,
+ addButtonText: 'Confirm'
+ },
+ title: 'Edit Note'
+ }
+ });
+ editNoteDialogRef.afterClosed().subscribe((response: any) => {
+ if (response.data && response.data.value.note !== noteContent) {
+ this.callbackEdit(noteId, response.data.value, index);
+ }
+ });
+ }
+
+ deleteNote(noteId: string, index: number) {
+ const deleteNoteDialogRef = this.dialog.open(DeleteDialogComponent, {
+ data: { deleteContext: `Note: ${this.entityNotes[index].note}` }
+ });
+ deleteNoteDialogRef.afterClosed().subscribe((response: any) => {
+ if (response.delete) {
+ this.callbackDelete(noteId, index);
+ }
+ });
+ }
+
+}
diff --git a/src/assets/env.js b/src/assets/env.js
index c3358b1c3..b6356d4ff 100644
--- a/src/assets/env.js
+++ b/src/assets/env.js
@@ -14,4 +14,6 @@
// Language Environment variables
window["env"]["defaultLanguage"] = '';
window["env"]["supportedLanguages"] = '';
+
+ window['env']['preloadClients'] = '';
})(this);
diff --git a/src/assets/env.template.js b/src/assets/env.template.js
index 3a0566ee3..e011ea700 100644
--- a/src/assets/env.template.js
+++ b/src/assets/env.template.js
@@ -14,4 +14,6 @@
// Language Environment variables
window["env"]["defaultLanguage"] = '$MIFOS_DEFAULT_LANGUAGE';
window["env"]["supportedLanguages"] = '$MIFOS_SUPPORTED_LANGUAGES';
+
+ window['env']['preloadClients'] = '$MIFOS_PRELOAD_CLIENTS';
})(this);
diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts
index 27251c5e9..9436d0a6c 100644
--- a/src/environments/environment.prod.ts
+++ b/src/environments/environment.prod.ts
@@ -22,7 +22,8 @@ export const environment = {
serverUrl: ''
},
defaultLanguage: window['env']['defaultLanguage'] || 'en-US',
- supportedLanguages: window['env']['supportedLanguages'] || 'en-US,es-MX,fr-FR'
+ supportedLanguages: window['env']['supportedLanguages'] || 'en-US,es-MX,fr-FR',
+ preloadClients: window['env']['preloadClients'] || true
};
// Server URL
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 38342b866..28061dfda 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -27,7 +27,8 @@ export const environment = {
serverUrl: ''
},
defaultLanguage: window['env']['defaultLanguage'] || 'en-US',
- supportedLanguages: window['env']['supportedLanguages'] || 'en-US,es-MX,fr-FR'
+ supportedLanguages: window['env']['supportedLanguages'] || 'en-US,es-MX,fr-FR',
+ preloadClients: window['env']['preloadClients'] || true
};
// Server URL
- Current Balances: + Current Balances : {{savingsAccountData.currency.displaySymbol}}{{savingsAccountData.summary.accountBalance | number}}
- Available Balance: + Available Balance : {{savingsAccountData.currency.displaySymbol}}{{savingsAccountData.summary.availableBalance | number}} @@ -310,6 +310,14 @@ [active]="charges.isActive"> Charges + + Savings Documents + + + Notes +
+
+
+
+
+ 10" [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons>
+
+
diff --git a/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.scss b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.scss
new file mode 100644
index 000000000..223688cb7
--- /dev/null
+++ b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.scss
@@ -0,0 +1,15 @@
+table {
+ width: 100%;
+ margin-top: 3%;
+ .document-action-button {
+ min-width: 26px;
+ padding: 0 6px;
+ margin: 4px;
+ line-height: 25px;
+ }
+}
+
+.tab-container {
+ padding: 1%;
+ margin: 1%;
+}
diff --git a/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.spec.ts b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.spec.ts
new file mode 100644
index 000000000..2db427eec
--- /dev/null
+++ b/src/app/shared/tabs/entity-documents-tab/entity-documents-tab.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EntityDocumentsTabComponent } from './entity-documents-tab.component';
+
+describe('EntityDocumentsTabComponent', () => {
+ let component: EntityDocumentsTabComponent;
+ let fixture: ComponentFixture
+
+
+
+ Documents
+ +
+
+
+ | Name | +{{ document.name }} | +Description | +{{ document.description }} | +File Name | +{{ document.fileName }} | +Actions | ++ + + | +
|---|
+
+
+
+
+
+
+
diff --git a/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.scss b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.scss
new file mode 100644
index 000000000..b40728956
--- /dev/null
+++ b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.scss
@@ -0,0 +1,4 @@
+.tab-container {
+ padding: 1%;
+ margin: 1%;
+}
diff --git a/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.spec.ts b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.spec.ts
new file mode 100644
index 000000000..975aadeb4
--- /dev/null
+++ b/src/app/shared/tabs/entity-notes-tab/entity-notes-tab.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EntityNotesTabComponent } from './entity-notes-tab.component';
+
+describe('EntityNotesTabComponent', () => {
+ let component: EntityNotesTabComponent;
+ let fixture: ComponentFixtureNotes
+ +
+
+
+
+ {{ entityNote.note }}
+
+ Created by: {{entityNote.createdByUsername}}
+ Date: {{entityNote.createdOn | dateFormat}}
+
+
+
+
+