diff --git a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.html b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.html index 1d3962a84..8b7abb060 100644 --- a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.html +++ b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.html @@ -80,6 +80,118 @@
- TREE VIEW +
+ + +
+ +
+ +
+ + + + + +
+ +
+ Account Name +
+ +
+ {{ glAccount.name }} +
+ +
+ GL Code +
+ +
+ {{ glAccount.glCode }} +
+ +
+ Account Type +
+ +
+ {{ glAccount.type }} +
+ +
+ Account Usage +
+ +
+ {{ glAccount.usage }} +
+ +
+ Manual Entries Allowed +
+ +
+ {{ glAccount.manualEntriesAllowed }} +
+ +
+ Description +
+ +
+ {{ glAccount.description }} +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ +
diff --git a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.scss b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.scss index b209ba200..1bd30aea2 100644 --- a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.scss +++ b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.scss @@ -2,6 +2,36 @@ table { width: 100%; } +.gl-account-tree-invisible { + display: none; +} + +.gl-account-tree ul, +.gl-account-tree li { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +.gl-account-tree { + li { + span { + cursor: pointer; + } + } +} + +.content { + div { + margin: 1rem 0; + word-wrap: break-word; + } + + .header { + font-weight: 500; + } +} + .disabled { color: red; } diff --git a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts index 68c781ce0..ef393883e 100644 --- a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts +++ b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts @@ -1,8 +1,14 @@ import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core'; -import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material'; +import { MatPaginator, MatSort, MatTableDataSource, MatTreeNestedDataSource } from '@angular/material'; +import { NestedTreeControl } from '@angular/cdk/tree'; import { FormControl } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; +import { of } from 'rxjs'; + +import { GLAccountNode } from './gl-account-node.model'; +import { GlAccountTreeService } from './gl-account-tree.service'; + @Component({ selector: 'mifosx-chart-of-accounts', templateUrl: './chart-of-accounts.component.html', @@ -19,14 +25,32 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; - constructor(private route: ActivatedRoute) { + // + nestedTreeControl: NestedTreeControl; + nestedTreeDataSource: MatTreeNestedDataSource; + glAccount: GLAccountNode; + // + + constructor(private glAccountTreeService: GlAccountTreeService, + private route: ActivatedRoute) { this.route.data.subscribe((data: { glAccountData: any }) => { this.glAccountData = data.glAccountData; + glAccountTreeService.initialize(this.glAccountData); }); + // + this.nestedTreeControl = new NestedTreeControl(this._getChildren); + this.nestedTreeDataSource = new MatTreeNestedDataSource(); + // } ngOnInit() { this.tableDataSource = new MatTableDataSource(this.glAccountData); + // + this.glAccountTreeService.treeDataChange.subscribe((glAccountTreeData: any) => { + this.nestedTreeDataSource.data = glAccountTreeData; + this.nestedTreeControl.expand(this.nestedTreeDataSource.data[0]); + }); + // } ngAfterViewInit() { @@ -49,4 +73,18 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit { console.log(glAccount); } + // + hasNestedChild = (_: number, node: GLAccountNode) => node.children.length; + + viewGLAccountNode(glAccount: GLAccountNode) { + if (glAccount.glCode) { + this.glAccount = glAccount; + } else { + delete this.glAccount; + } + } + + private _getChildren = (node: GLAccountNode) => of(node.children); + // + } diff --git a/src/app/accounting/chart-of-accounts/gl-account-node.model.ts b/src/app/accounting/chart-of-accounts/gl-account-node.model.ts new file mode 100644 index 000000000..ff0b4cbda --- /dev/null +++ b/src/app/accounting/chart-of-accounts/gl-account-node.model.ts @@ -0,0 +1,23 @@ +export class GLAccountNode { + children: GLAccountNode[]; + name: string; + glCode: string; + type: string; + usage: string; + manualEntriesAllowed: boolean; + description: string; + constructor(name: string, + glCode: string = '', + type: string = '', + usage: string = '', + manualEntriesAllowed: boolean = false, + description: string = '') { + this.name = name; + this.glCode = glCode; + this.type = type; + this.usage = usage; + this.manualEntriesAllowed = manualEntriesAllowed; + this.description = description; + this.children = []; + } +} diff --git a/src/app/accounting/chart-of-accounts/gl-account-tree.service.spec.ts b/src/app/accounting/chart-of-accounts/gl-account-tree.service.spec.ts new file mode 100644 index 000000000..90fc8a66f --- /dev/null +++ b/src/app/accounting/chart-of-accounts/gl-account-tree.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { GlAccountTreeService } from './gl-account-tree.service'; + +describe('GlAccountTreeService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [GlAccountTreeService] + }); + }); + + it('should be created', inject([GlAccountTreeService], (service: GlAccountTreeService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/accounting/chart-of-accounts/gl-account-tree.service.ts b/src/app/accounting/chart-of-accounts/gl-account-tree.service.ts new file mode 100644 index 000000000..7a9ef5639 --- /dev/null +++ b/src/app/accounting/chart-of-accounts/gl-account-tree.service.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@angular/core'; + +import { BehaviorSubject } from 'rxjs'; + +import { GLAccountNode } from './gl-account-node.model'; + +@Injectable({ + providedIn: 'root' +}) +export class GlAccountTreeService { + + glAccountData: any; + + treeDataChange = new BehaviorSubject([]); + + get treeData(): GLAccountNode[] { return this.treeDataChange.value; } + + constructor() { } + + initialize(glAccountData: any) { + const data = this.buildGLAccountTree(glAccountData); + this.treeDataChange.next(data); + } + + buildGLAccountTree(glAccountData: any): GLAccountNode[] { + const glAccountTree: GLAccountNode[] = []; + + glAccountTree.push(new GLAccountNode('GL ACCOUNTS')); + glAccountTree[0].children.push(new GLAccountNode('ASSET')); + glAccountTree[0].children.push(new GLAccountNode('EQUITY')); + glAccountTree[0].children.push(new GLAccountNode('EXPENSE')); + glAccountTree[0].children.push(new GLAccountNode('INCOME')); + glAccountTree[0].children.push(new GLAccountNode('LIABILITY')); + + glAccountData.sort((glAccountOne: any, glAccountTwo: any) => { + if (!glAccountOne.parentId) { + glAccountOne.parentId = 0; + } + return glAccountOne.parentId - glAccountTwo.parentId; + }); + + const glAccounts: GLAccountNode[] = []; + + for (const glAccount of glAccountData) { + glAccounts[glAccount.id] = + new GLAccountNode(glAccount.name, glAccount.glCode, glAccount.type.value, glAccount.usage.value, glAccount.manualEntriesAllowed, glAccount.description); + } + + for (const glAccount of glAccountData) { + if (glAccount.parentId === 0) { + if (glAccount.type.value === 'ASSET') { + glAccountTree[0].children[0].children.push(glAccounts[glAccount.id]); + } else if (glAccount.type.value === 'EQUITY') { + glAccountTree[0].children[1].children.push(glAccounts[glAccount.id]); + } else if (glAccount.type.value === 'EXPENSE') { + glAccountTree[0].children[2].children.push(glAccounts[glAccount.id]); + } else if (glAccount.type.value === 'INCOME') { + glAccountTree[0].children[3].children.push(glAccounts[glAccount.id]); + } else if (glAccount.type.value === 'LIABILITY') { + glAccountTree[0].children[4].children.push(glAccounts[glAccount.id]); + } + } else { + glAccounts[glAccount.parentId].children.push(glAccounts[glAccount.id]); + } + } + + return glAccountTree; + } + +} diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index bd0799772..86ec76c1a 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -33,6 +33,7 @@ import { MatCheckboxModule, MatTooltipModule, MatSnackBarModule, MatTableModule, + MatTreeModule, MatSortModule, MatPaginatorModule, MatDividerModule, @@ -98,6 +99,7 @@ import { AuthenticationInterceptor } from './authentication/authentication.inter MatTooltipModule, MatSnackBarModule, MatTableModule, + MatTreeModule, MatSortModule, MatPaginatorModule, MatDividerModule @@ -143,6 +145,7 @@ import { AuthenticationInterceptor } from './authentication/authentication.inter MatTooltipModule, MatSnackBarModule, MatTableModule, + MatTreeModule, MatSortModule, MatPaginatorModule, MatDividerModule,