diff --git a/src/app/clients/clients-routing.module.ts b/src/app/clients/clients-routing.module.ts index f84a683c6..26a9bd070 100644 --- a/src/app/clients/clients-routing.module.ts +++ b/src/app/clients/clients-routing.module.ts @@ -166,9 +166,21 @@ const routes: Routes = [ ] }, { - path: 'loans', - data: { title: extract('Loans'), breadcrumb: 'loans' }, - loadChildren: '../loans/loans.module#LoansModule' + path: 'clients', + data: { title: extract('Clients'), breadcrumb: 'Clients', routeParamBreadcrumb: false }, + children: [ + { + path: ':clientId', + data: { title: extract('Clients View'), routeParamBreadcrumb: 'clientId' }, + children: [ + { + path: 'loans', + data: { title: extract('Loans'), breadcrumb: 'loans', routeParamBreadcrumb: false }, + loadChildren: '../loans/loans.module#LoansModule' + } + ] + } + ] } ]) ]; diff --git a/src/app/clients/clients-view/general-tab/general-tab.component.html b/src/app/clients/clients-view/general-tab/general-tab.component.html index 8aeb01c87..8478ff410 100644 --- a/src/app/clients/clients-view/general-tab/general-tab.component.html +++ b/src/app/clients/clients-view/general-tab/general-tab.component.html @@ -133,7 +133,7 @@ - + diff --git a/src/app/clients/clients-view/general-tab/general-tab.component.ts b/src/app/clients/clients-view/general-tab/general-tab.component.ts index 8ac9c1efd..db01fff81 100644 --- a/src/app/clients/clients-view/general-tab/general-tab.component.ts +++ b/src/app/clients/clients-view/general-tab/general-tab.component.ts @@ -31,6 +31,7 @@ export class GeneralTabComponent { showClosedLoanAccounts = false; showClosedSavingAccounts = false; showClosedShareAccounts = false; + clientid: any; constructor( private route: ActivatedRoute, @@ -43,6 +44,7 @@ export class GeneralTabComponent { this.shareAccounts = data.clientAccountsData.shareAccounts; this.upcomingCharges = data.clientChargesData.pageItems; this.clientSummary = data.clientSummary[0]; + this.clientid = this.route.parent.snapshot.params['clientId']; }); } diff --git a/src/app/loans/common-resolvers/loan-datatable.resolver.ts b/src/app/loans/common-resolvers/loan-datatable.resolver.ts new file mode 100644 index 000000000..3ad249498 --- /dev/null +++ b/src/app/loans/common-resolvers/loan-datatable.resolver.ts @@ -0,0 +1,32 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve, ActivatedRouteSnapshot } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { LoansService } from '../loans.service'; + +/** + * Loans notes data resolver. + */ +@Injectable() +export class LoanDatatableResolver implements Resolve { + + /** + * @param {LoansService} LoansService Loans service. + */ + constructor(private loansService: LoansService) { } + + /** + * Returns the Loans Notes Data. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const loanId = route.parent.parent.paramMap.get('loanId'); + const datatableName = route.paramMap.get('datatableName'); + return this.loansService.getLoanDatatable(loanId, datatableName); + } + +} diff --git a/src/app/loans/common-resolvers/loan-datatables.resolver.ts b/src/app/loans/common-resolvers/loan-datatables.resolver.ts new file mode 100644 index 000000000..82733b718 --- /dev/null +++ b/src/app/loans/common-resolvers/loan-datatables.resolver.ts @@ -0,0 +1,30 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { Resolve } from '@angular/router'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** Custom Services */ +import { LoansService } from '../loans.service'; + +/** + * loan datatables resolver. + */ +@Injectable() +export class LoanDatatablesResolver implements Resolve { + + /** + * @param {loansService} loansService loans service. + */ + constructor(private loansService: LoansService) { } + + /** + * Returns the loan datatables. + * @returns {Observable} + */ + resolve(): Observable { + return this.loansService.getLoanDataTables(); + } + +} diff --git a/src/app/loans/loans-routing.module.ts b/src/app/loans/loans-routing.module.ts index c34fb5297..43d070fab 100644 --- a/src/app/loans/loans-routing.module.ts +++ b/src/app/loans/loans-routing.module.ts @@ -11,19 +11,22 @@ import { LoansViewComponent } from './loans-view/loans-view.component'; import { GeneralTabComponent } from './loans-view/general-tab/general-tab.component'; import { AccountDetailsComponent } from './loans-view/account-details/account-details.component'; import { NotesTabComponent } from './loans-view/notes-tab/notes-tab.component'; +import { RepaymentScheduleTabComponent } from './loans-view/repayment-schedule-tab/repayment-schedule-tab.component'; +import { TransactionsTabComponent } from './loans-view/transactions-tab/transactions-tab.component'; +import { OriginalScheduleTabComponent } from './loans-view/original-schedule-tab/original-schedule-tab.component'; +import { OverdueChargesTabComponent } from './loans-view/overdue-charges-tab/overdue-charges-tab.component'; +import { ChargesTabComponent } from './loans-view/charges-tab/charges-tab.component'; +import { DatatableTabComponent } from './loans-view/datatable-tab/datatable-tab.component'; /** Custom Resolvers */ import { LoanChargeTemplateResolver } from './common-resolvers/loan-charge-template.resolver'; import { LoanDetailsResolver } from './common-resolvers/loan-details.resolver'; import { LoanDetailsGeneralResolver } from './common-resolvers/loan-details-general.resolver'; import { LoanNotesResolver } from './common-resolvers/loan-notes-resolver'; -import { ChargesTabComponent } from './loans-view/charges-tab/charges-tab.component'; import { LoanDetailsChargesResolver } from './common-resolvers/loan-details-charges.resolver'; -import { OverdueChargesTabComponent } from './loans-view/overdue-charges-tab/overdue-charges-tab.component'; -import { OriginalScheduleTabComponent } from './loans-view/original-schedule-tab/original-schedule-tab.component'; -import { RepaymentScheduleTabComponent } from './loans-view/repayment-schedule-tab/repayment-schedule-tab.component'; -import { TransactiosTabComponent } from './loans-view/transactios-tab/transactios-tab.component'; import { LoanAccountActionsComponent } from './loans-view/loan-account-actions/loan-account-actions.component'; +import { LoanDatatablesResolver } from './common-resolvers/loan-datatables.resolver'; +import { LoanDatatableResolver } from './common-resolvers/loan-datatable.resolver'; const routes: Routes = [ { @@ -34,7 +37,8 @@ const routes: Routes = [ data: { title: extract('Loan View'), routeParamBreadcrumb: 'loanId' }, component: LoansViewComponent, resolve: { - loanDetailsData: LoanDetailsResolver + loanDetailsData: LoanDetailsResolver, + loanDatatables: LoanDatatablesResolver, }, // Component For Loan View Comes Here children: [ @@ -72,7 +76,7 @@ const routes: Routes = [ }, { path: 'transactions', - component: TransactiosTabComponent, + component: TransactionsTabComponent, data: { title: extract('Transactions'), breadcrumb: 'Transactions', routeParamBreadcrumb: false }, resolve: { loanDetailsAssociationData: LoanDetailsChargesResolver @@ -102,6 +106,17 @@ const routes: Routes = [ loanNotes: LoanNotesResolver }, }, + { + path: 'datatables', + children: [{ + path: ':datatableName', + component: DatatableTabComponent, + data: { title: extract('Data Table View'), routeParamBreadcrumb: 'datatableName' }, + resolve: { + loanDatatable: LoanDatatableResolver + } + }] + }, { path: 'add-loan-charge', component: AddLoanChargeComponent, @@ -128,7 +143,9 @@ const routes: Routes = [ LoanDetailsGeneralResolver, LoanDetailsResolver, LoanNotesResolver, - LoanDetailsChargesResolver + LoanDetailsChargesResolver, + LoanDatatablesResolver, + LoanDatatableResolver ] }) diff --git a/src/app/loans/loans-view/datatable-tab/datatable-tab.component.html b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.html new file mode 100644 index 000000000..44256d984 --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/src/app/loans/loans-view/datatable-tab/datatable-tab.component.scss b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.spec.ts b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.spec.ts similarity index 52% rename from src/app/loans/loans-view/transactios-tab/transactios-tab.component.spec.ts rename to src/app/loans/loans-view/datatable-tab/datatable-tab.component.spec.ts index 2b683721a..1f409cd4e 100644 --- a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.spec.ts +++ b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { TransactiosTabComponent } from './transactios-tab.component'; +import { DatatableTabComponent } from './datatable-tab.component'; -describe('TransactiosTabComponent', () => { - let component: TransactiosTabComponent; - let fixture: ComponentFixture; +describe('DatatableTabComponent', () => { + let component: DatatableTabComponent; + let fixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ TransactiosTabComponent ] + declarations: [ DatatableTabComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(TransactiosTabComponent); + fixture = TestBed.createComponent(DatatableTabComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/loans/loans-view/datatable-tab/datatable-tab.component.ts b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.ts new file mode 100644 index 000000000..abf48329b --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/datatable-tab.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'mifosx-datatable-tab', + templateUrl: './datatable-tab.component.html', + styleUrls: ['./datatable-tab.component.scss'] +}) +export class DatatableTabComponent { + + /** Loan Datatable */ + loanDatatable: any; + /** Multi Row Datatable Flag */ + multiRowDatatableFlag: boolean; + + /** + * Fetches data table data from `resolve` + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { loanDatatable: any }) => { + this.loanDatatable = data.loanDatatable; + this.multiRowDatatableFlag = this.loanDatatable.columnHeaders[0].columnName === 'id' ? true : false; + }); + } + +} diff --git a/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.html b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.html new file mode 100644 index 000000000..2ea73ff82 --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.html @@ -0,0 +1,34 @@ +
+ +
+
+

{{datatableName}}

+
+
+ + + + + + +
+
+ + + + + + + + + + + + +
{{datatableColumn}} {{data.row[i]}}
+ +
diff --git a/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.scss b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.scss new file mode 100644 index 000000000..b60aa2a1e --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.scss @@ -0,0 +1,10 @@ +.tab-container { + padding: 1%; + margin: 1%; + .action-button{ + margin-left: auto; + } + table { + width: 100%; + } +} diff --git a/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.spec.ts b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.spec.ts new file mode 100644 index 000000000..dd46589d8 --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MultiRowComponent } from './multi-row.component'; + +describe('MultiRowComponent', () => { + let component: MultiRowComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MultiRowComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MultiRowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.ts b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.ts new file mode 100644 index 000000000..31a69e824 --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/multi-row/multi-row.component.ts @@ -0,0 +1,184 @@ +/** Angular Imports */ +import { Component, OnChanges, OnInit, Input, ViewChild } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MatTable } from '@angular/material/table'; +import { MatDialog } from '@angular/material'; +import { DatePipe } from '@angular/common'; + +/** Custom Dialogs */ +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { DeleteDialogComponent } from '../../../../shared/delete-dialog/delete-dialog.component'; + +/** Custom Models */ +import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; +import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; +import { CheckboxBase } from 'app/shared/form-dialog/formfield/model/checkbox-base'; +import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; + +/** Custom Services */ +import { LoansService } from '../../../loans.service'; + +/** + * Loan Multi Row Data Tables + */ +@Component({ + selector: 'mifosx-multi-row', + templateUrl: './multi-row.component.html', + styleUrls: ['./multi-row.component.scss'] +}) +export class MultiRowComponent implements OnInit, OnChanges { + + /** Data Object */ + @Input() dataObject: any; + + /** Data Table Name */ + datatableName: string; + /** Data Table Columns */ + datatableColumns: string[] = []; + /** Data Table Data */ + datatableData: any; + /** Loan Id */ + loanId: string; + /** Toggle button visibility */ + showDeleteBotton: boolean; + + /** Data Table Reference */ + @ViewChild('dataTable') dataTableRef: MatTable; + + /** + * Fetches loan Id from parent route params. + * @param {ActivatedRoute} route Activated Route. + * @param {DatePipe} datePipe Date Pipe. + * @param {LoansService} loansService Loans Service. + * @param {MatDialog} dialog Mat Dialog. + */ + constructor(private route: ActivatedRoute, + private datePipe: DatePipe, + private loansService: LoansService, + private dialog: MatDialog) { + this.loanId = this.route.parent.parent.snapshot.paramMap.get('loanId'); + } + + /** + * Updates related variables on changes to dataObject. + */ + ngOnChanges() { + this.datatableColumns = this.dataObject.columnHeaders.map((columnHeader: any) => { + return columnHeader.columnName; + }); + this.datatableData = this.dataObject.data; + this.showDeleteBotton = this.datatableData[0] ? true : false; + } + + /** + * Fetches data table name from route params. + * subscription is required due to asynchronicity. + */ + ngOnInit() { + this.route.params.subscribe((routeParams: any) => { + this.datatableName = routeParams.datatableName; + }); + } + + /** + * Adds a new row to the given multi row data table. + */ + add() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'loan_id')); + }); + const formfields: FormfieldBase[] = columns.map((column: any) => { + switch (column.columnDisplayType) { + case 'INTEGER': + case 'STRING': + case 'DECIMAL': + case 'TEXT': return new InputBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: (column.columnDisplayType === 'INTEGER' || column.columnDisplayType === 'DECIMAL') ? 'number' : 'text', + required: (column.isColumnNullable) ? false : true + }); + case 'BOOLEAN': return new CheckboxBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'checkbox', + required: (column.isColumnNullable) ? false : true + }); + case 'CODELOOKUP': return new SelectBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + options: { label: 'value', value: 'id', data: column.columnValues }, + required: (column.isColumnNullable) ? false : true + }); + case 'DATE': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'date', + required: (column.isColumnNullable) ? false : true + }); + } + case 'DATETIME': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd HH:mm'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'datetime-local', + required: (column.isColumnNullable) ? false : true + }); + } + } + }); + const data = { + title: 'Add ' + this.datatableName, + formfields: formfields + }; + const addDialogRef = this.dialog.open(FormDialogComponent, { data }); + addDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.loansService.addLoanDatatableEntry(this.loanId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.loansService.getLoanDatatable(this.loanId, this.datatableName).subscribe((dataObject: any) => { + this.datatableData = dataObject.data; + this.dataTableRef.renderRows(); + }); + }); + } + }); + } + + /** + * Deletes all rows of the given multi row data table. + */ + delete() { + const deleteDataTableDialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: `the contents of ${this.datatableName}` } + }); + deleteDataTableDialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.loansService.deleteDatatableContent(this.loanId, this.datatableName).subscribe(() => { + this.loansService.getLoanDatatable(this.loanId, this.datatableName).subscribe((dataObject: any) => { + this.datatableData = dataObject.data; + this.showDeleteBotton = false; + this.dataTableRef.renderRows(); + }); + }); + } + }); + } + +} diff --git a/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.html b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.html new file mode 100644 index 000000000..2704540f7 --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.html @@ -0,0 +1,41 @@ +
+ +
+ +
+

{{datatableName}}

+
+ +
+
+ + + + + + + + + +
+
+ +
+ + + +
+ + + {{columnHeader.columnName}} : {{dataObject.data[0].row[i]}} + + +
+ +
diff --git a/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.scss b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.scss new file mode 100644 index 000000000..544ca291a --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.scss @@ -0,0 +1,11 @@ +.tab-container { + padding: 1%; + margin: 1%; + .delete-button { + margin-left: 1%; + } +} + +.tableName { + padding-left: 2%; +} diff --git a/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.spec.ts b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.spec.ts new file mode 100644 index 000000000..8aece650c --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SingleRowComponent } from './single-row.component'; + +describe('SingleRowComponent', () => { + let component: SingleRowComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SingleRowComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SingleRowComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.ts b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.ts new file mode 100644 index 000000000..83690a5bd --- /dev/null +++ b/src/app/loans/loans-view/datatable-tab/single-row/single-row.component.ts @@ -0,0 +1,204 @@ +/** Angular Imports */ +import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MatDialog } from '@angular/material'; +import { DatePipe } from '@angular/common'; + +/** Custom Components */ +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { DeleteDialogComponent } from '../../../../shared/delete-dialog/delete-dialog.component'; + +/** Custom Models */ +import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base'; +import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base'; +import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; +import { CheckboxBase } from 'app/shared/form-dialog/formfield/model/checkbox-base'; + +/** Custom Services */ +import { LoansService } from '../../../loans.service'; + + +@Component({ + selector: 'mifosx-single-row', + templateUrl: './single-row.component.html', + styleUrls: ['./single-row.component.scss'] +}) +export class SingleRowComponent implements OnInit { + + /** Data Object */ + @Input() dataObject: any; + + /** Data Table Name */ + datatableName: string; + /** Loan Id */ + loanId: string; + + /** + * Fetches loan Id from parent route params. + * @param {ActivatedRoute} route Activated Route. + * @param {DatePipe} datePipe Date Pipe. + * @param {LoansService} loansService Loans Service. + * @param {MatDialog} dialog Mat Dialog. + */ + constructor(private route: ActivatedRoute, + private datePipe: DatePipe, + private dialog: MatDialog, + private loansService: LoansService) { + this.loanId = this.route.parent.parent.snapshot.paramMap.get('loanId'); + } + + /** + * Fetches data table name from route params. + * subscription is required due to asynchronicity. + */ + ngOnInit() { + this.route.params.subscribe((routeParams: any) => { + this.datatableName = routeParams.datatableName; + }); + } + + /** + * Creates a new instance of the given single row data table. + */ + add() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'loan_id')); + }); + const formfields: FormfieldBase[] = this.getFormfields(columns, dateTransformColumns, dataTableEntryObject); + const data = { + title: 'Add ' + this.datatableName, + formfields: formfields + }; + const addDialogRef = this.dialog.open(FormDialogComponent, { data }); + addDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.loansService.addLoanDatatableEntry(this.loanId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.loansService.getLoanDatatable(this.loanId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Edits the current instance of single row data table. + */ + edit() { + let dataTableEntryObject: any = { locale: 'en' }; + const dateTransformColumns: string[] = []; + const columns = this.dataObject.columnHeaders.filter((column: any) => { + return ((column.columnName !== 'id') && (column.columnName !== 'loan_id')); + }); + let formfields: FormfieldBase[] = this.getFormfields(columns, dateTransformColumns, dataTableEntryObject); + formfields = formfields.map((formfield: FormfieldBase, index: number) => { + formfield.value = (this.dataObject.data[0].row[index + 1]) ? this.dataObject.data[0].row[index + 1] : ''; + return formfield; + }); + const data = { + title: 'Edit ' + this.datatableName, + layout: { addButtonText: 'Confirm' }, + formfields: formfields + }; + const editDialogRef = this.dialog.open(FormDialogComponent, { data }); + editDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + dateTransformColumns.forEach((column) => { + response.data.value[column] = this.datePipe.transform(response.data.value[column], dataTableEntryObject.dateFormat); + }); + dataTableEntryObject = { ...response.data.value, ...dataTableEntryObject }; + this.loansService.editLoanDatatableEntry(this.loanId, this.datatableName, dataTableEntryObject).subscribe(() => { + this.loansService.getLoanDatatable(this.loanId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Deletes the current instance of single row data table. + */ + delete() { + const deleteDataTableDialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: `the contents of ${this.datatableName}` } + }); + deleteDataTableDialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.loansService.deleteDatatableContent(this.loanId, this.datatableName) + .subscribe(() => { + this.loansService.getLoanDatatable(this.loanId, this.datatableName).subscribe((dataObject: any) => { + this.dataObject = dataObject; + }); + }); + } + }); + } + + /** + * Maps API response to data table form fields. + * @param {any} columns Data Table Columns. + * @param {string[]} dateTransformColumns Columns transformed with date pipe. + * @param {any} dataTableEntryObject Additional data table details. + */ + getFormfields(columns: any, dateTransformColumns: string[], dataTableEntryObject: any) { + return columns.map((column: any) => { + switch (column.columnDisplayType) { + case 'INTEGER': + case 'STRING': + case 'DECIMAL': + case 'TEXT': return new InputBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: (column.columnDisplayType === 'INTEGER' || column.columnDisplayType === 'DECIMAL') ? 'number' : 'text', + required: (column.isColumnNullable) ? false : true + }); + case 'BOOLEAN': return new CheckboxBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'checkbox', + required: (column.isColumnNullable) ? false : true + }); + case 'CODELOOKUP': return new SelectBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + options: { label: 'value', value: 'id', data: column.columnValues }, + required: (column.isColumnNullable) ? false : true + }); + case 'DATE': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'date', + required: (column.isColumnNullable) ? false : true + }); + } + case 'DATETIME': { + dateTransformColumns.push(column.columnName); + dataTableEntryObject.dateFormat = 'yyyy-MM-dd HH:mm'; + return new DatepickerBase({ + controlName: column.columnName, + label: column.columnName, + value: '', + type: 'datetime-local', + required: (column.isColumnNullable) ? false : true + }); + } + } + }); + } + +} diff --git a/src/app/loans/loans-view/loans-view.component.html b/src/app/loans/loans-view/loans-view.component.html index c9ad3da9a..fcc18dcae 100644 --- a/src/app/loans/loans-view/loans-view.component.html +++ b/src/app/loans/loans-view/loans-view.component.html @@ -80,10 +80,16 @@ Charges - + Notes + + + {{loanDatatable.registeredTableName}} + + diff --git a/src/app/loans/loans-view/loans-view.component.ts b/src/app/loans/loans-view/loans-view.component.ts index beb0d45f6..cf5e597bb 100644 --- a/src/app/loans/loans-view/loans-view.component.ts +++ b/src/app/loans/loans-view/loans-view.component.ts @@ -13,6 +13,7 @@ import { ButtonConfig } from './button-config'; export class LoansViewComponent implements OnInit { loanDetailsData: any; + loanDatatables: any; recalculateInterest: any; status: string; buttons: { @@ -29,9 +30,10 @@ export class LoansViewComponent implements OnInit { loanId: number; constructor(private route: ActivatedRoute, - private router: Router) { - this.route.data.subscribe((data: { loanDetailsData: any, }) => { + private router: Router) { + this.route.data.subscribe((data: { loanDetailsData: any, loanDatatables: any}) => { this.loanDetailsData = data.loanDetailsData; + this.loanDatatables = data.loanDatatables; }); this.loanId = this.route.snapshot.params['loanId']; } diff --git a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.html b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.html similarity index 100% rename from src/app/loans/loans-view/transactios-tab/transactios-tab.component.html rename to src/app/loans/loans-view/transactions-tab/transactions-tab.component.html diff --git a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.scss b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.scss similarity index 100% rename from src/app/loans/loans-view/transactios-tab/transactios-tab.component.scss rename to src/app/loans/loans-view/transactions-tab/transactions-tab.component.scss diff --git a/src/app/loans/loans-view/transactions-tab/transactions-tab.component.spec.ts b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.spec.ts new file mode 100644 index 000000000..a67fc2279 --- /dev/null +++ b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TransactionsTabComponent } from './transactions-tab.component'; + +describe('TransactionsTabComponent', () => { + let component: TransactionsTabComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TransactionsTabComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TransactionsTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.ts b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts similarity index 88% rename from src/app/loans/loans-view/transactios-tab/transactios-tab.component.ts rename to src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts index 8c42ca1db..1ff495a86 100644 --- a/src/app/loans/loans-view/transactios-tab/transactios-tab.component.ts +++ b/src/app/loans/loans-view/transactions-tab/transactions-tab.component.ts @@ -3,11 +3,11 @@ import { ActivatedRoute } from '@angular/router'; import {FormControl} from '@angular/forms'; @Component({ - selector: 'mifosx-transactios-tab', - templateUrl: './transactios-tab.component.html', - styleUrls: ['./transactios-tab.component.scss'] + selector: 'mifosx-transactions-tab', + templateUrl: './transactions-tab.component.html', + styleUrls: ['./transactions-tab.component.scss'] }) -export class TransactiosTabComponent implements OnInit { +export class TransactionsTabComponent implements OnInit { /** Loan Details Data */ transactions: any; diff --git a/src/app/loans/loans.module.ts b/src/app/loans/loans.module.ts index cfcc737f6..63c80cef9 100644 --- a/src/app/loans/loans.module.ts +++ b/src/app/loans/loans.module.ts @@ -18,9 +18,12 @@ import { ChargesTabComponent } from './loans-view/charges-tab/charges-tab.compon import { OverdueChargesTabComponent } from './loans-view/overdue-charges-tab/overdue-charges-tab.component'; import { OriginalScheduleTabComponent } from './loans-view/original-schedule-tab/original-schedule-tab.component'; import { RepaymentScheduleTabComponent } from './loans-view/repayment-schedule-tab/repayment-schedule-tab.component'; -import { TransactiosTabComponent } from './loans-view/transactios-tab/transactios-tab.component'; import { LoanAccountActionsComponent } from './loans-view/loan-account-actions/loan-account-actions.component'; import { LoansAccountCloseComponent } from './loans-view/loan-account-actions/loans-account-close/loans-account-close.component'; +import { TransactionsTabComponent } from './loans-view/transactions-tab/transactions-tab.component'; +import { DatatableTabComponent } from './loans-view/datatable-tab/datatable-tab.component'; +import { MultiRowComponent } from './loans-view/datatable-tab/multi-row/multi-row.component'; +import { SingleRowComponent } from './loans-view/datatable-tab/single-row/single-row.component'; /** * Loans Module @@ -39,9 +42,12 @@ import { LoansAccountCloseComponent } from './loans-view/loan-account-actions/lo OverdueChargesTabComponent, OriginalScheduleTabComponent, RepaymentScheduleTabComponent, - TransactiosTabComponent, LoanAccountActionsComponent, LoansAccountCloseComponent, + TransactionsTabComponent, + DatatableTabComponent, + MultiRowComponent, + SingleRowComponent, ], providers: [DatePipe], }) diff --git a/src/app/loans/loans.service.ts b/src/app/loans/loans.service.ts index 197671968..555319913 100644 --- a/src/app/loans/loans.service.ts +++ b/src/app/loans/loans.service.ts @@ -95,4 +95,55 @@ export class LoansService { return this.http.post(`/loans/${loanId}/transactions`, closeData, {params: httpParams}); } + /** + * Get Loan Datatables + */ + getLoanDataTables() { + const httpParams = new HttpParams().set('apptable', 'm_loan'); + return this.http.get(`/datatables`, { params: httpParams }); + } + + /** + * Get Loan Datatable + * @param loanId Loan ID + * @param datatableName Datatable Name + */ + getLoanDatatable(loanId: string, datatableName: string) { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.get(`/datatables/${datatableName}/${loanId}`, { params: httpParams }); + } + + /** + * @param loanId Loan Id of loan to get add datatable entry for. + * @param datatableName Data Table name. + * @param data Data. + * @returns {Observable} + */ + addLoanDatatableEntry(loanId: string, datatableName: string, data: any): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.post(`/datatables/${datatableName}/${loanId}`, data, { params: httpParams }); + } + + /** + * @param loanId Loan Id of loan to get add datatable entry for. + * @param datatableName Data Table name. + * @param data Data. + * @returns {Observable} + */ + editLoanDatatableEntry(loanId: string, datatableName: string, data: any): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.put(`/datatables/${datatableName}/${loanId}`, data, { params: httpParams }); + } + + /** + * @param loanId Loan Id of loan to get add datatable entry for. + * @param datatableName Data Table name. + * @returns {Observable} + */ + deleteDatatableContent(loanId: string, datatableName: string): Observable { + const httpParams = new HttpParams().set('genericResultSet', 'true'); + return this.http.delete(`/datatables/${datatableName}/${loanId}`, { params: httpParams }); + } + + } diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 9722d2536..12859d27d 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -10,7 +10,7 @@ export const environment = { production: false, version: env.npm_package_version + '-dev', fineractPlatformTenantId: 'default', // For connecting to server running elsewhere update the tenant identifier - baseApiUrl: 'https://dev.mifos.io', // For connecting to server running elsewhere update the base API URL + baseApiUrl: 'https://staging.mifos.io', // For connecting to server running elsewhere update the base API URL apiProvider: '/fineract-provider/api', apiVersion: '/v1', serverUrl: '',