Feature: Filtering and tagging now available in Ledger

This commit is contained in:
tanshu committed 2024-07-28 17:32:16 +05:30
1 parent 336a8f59c5
commit c0eca311c7
40 files changed
+973 -72

No files matched your search

+84 -27
View File
@@ -1,5 +1,6 @@
import { SelectionModel } from '@angular/cdk/collections';
import { AsyncPipe, CurrencyPipe } from '@angular/common';
import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { AfterViewInit, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
import { MatIconButton, MatButton } from '@angular/material/button';
@@ -11,6 +12,7 @@ import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort, MatSortHeader } from '@angular/material/sort';
import { MatCheckbox } from '@angular/material/checkbox';
import {
MatTable,
MatColumnDef,
@@ -29,7 +31,7 @@ import {
} from '@angular/material/table';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import moment from 'moment';
import { Observable, of as observableOf } from 'rxjs';
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
import { Account } from '../core/account';
@@ -40,7 +42,13 @@ import { ToCsvService } from '../shared/to-csv.service';
import { Ledger } from './ledger';
import { LedgerDataSource } from './ledger-datasource';
import { LedgerService } from './ledger.service';
import { MatSelect } from '@angular/material/select';
import { MatChip, MatChipSet } from '@angular/material/chips';
import { LedgerItem } from './ledger-item';
import { MatDialog } from '@angular/material/dialog';
import { TagService } from '../tag/tag.service';
import { Tag } from '../tag/tag';
import { TagDialogComponent } from '../tag-dialog/tag-dialog.component';
@Component({
selector: 'app-ledger',
@@ -52,6 +60,9 @@ import { LedgerService } from './ledger.service';
MatCardHeader,
MatCardTitleGroup,
MatCardTitle,
MatCheckbox,
MatChip,
MatChipSet,
MatIconButton,
MatIcon,
MatCardContent,
@@ -68,6 +79,7 @@ import { LedgerService } from './ledger.service';
MatOption,
MatButton,
MatTable,
MatSelect,
MatSort,
MatColumnDef,
MatHeaderCellDef,
@@ -97,17 +109,21 @@ export class LedgerComponent implements OnInit, AfterViewInit {
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
@ViewChild(MatSort, { static: true }) sort!: MatSort;
info: Ledger = new Ledger();
dataSource: LedgerDataSource = new LedgerDataSource(this.info.body);
body = new BehaviorSubject<LedgerItem[]>([]);
filter = new BehaviorSubject<string[]>([]);
dataSource: LedgerDataSource = new LedgerDataSource(this.body, this.filter);
selection = new SelectionModel<LedgerItem>(true, []);
allTags: Tag[] = [];
tags: string[] = [];
form: FormGroup<{
startDate: FormControl<Date>;
finishDate: FormControl<Date>;
account: FormControl<string | null>;
tags: FormControl<string[]>;
}>;
selectedRowId = '';
debit = 0;
credit = 0;
running = 0;
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['date', 'particulars', 'type', 'narration', 'debit', 'credit', 'running'];
@@ -123,14 +139,16 @@ export class LedgerComponent implements OnInit, AfterViewInit {
constructor(
private route: ActivatedRoute,
private router: Router,
private dialog: MatDialog,
private toCsv: ToCsvService,
private ser: LedgerService,
private accountSer: AccountService,
private tagSer: TagService,
) {
this.form = new FormGroup({
startDate: new FormControl(new Date(), { nonNullable: true }),
finishDate: new FormControl(new Date(), { nonNullable: true }),
account: new FormControl<string | null>(null),
tags: new FormControl<string[]>([], { nonNullable: true }),
});
this.accounts = this.form.controls.account.valueChanges.pipe(
@@ -142,16 +160,29 @@ export class LedgerComponent implements OnInit, AfterViewInit {
ngOnInit() {
this.route.data.subscribe((value) => {
const data = value as { info: Ledger };
const data = value as { tags: Tag[]; info: Ledger };
this.allTags = data.tags;
this.info = data.info;
this.calculateTotals();
this.tags = [
'(None)',
...Array.from(new Set(this.info.body.map((x) => x.tags).reduce((list, tags) => list.concat(tags), []))),
];
this.form.setValue({
account: this.info.account?.name ?? '',
startDate: moment(this.info.startDate, 'DD-MMM-YYYY').toDate(),
finishDate: moment(this.info.finishDate, 'DD-MMM-YYYY').toDate(),
tags: this.tags,
});
this.dataSource = new LedgerDataSource(this.info.body, this.paginator, this.sort);
this.body.next(this.info.body);
this.filter.next(this.tags);
if (!this.dataSource.paginator) {
this.dataSource.paginator = this.paginator;
}
if (!this.dataSource.sort) {
this.dataSource.sort = this.sort;
}
this.selection.clear();
});
}
@@ -167,22 +198,8 @@ export class LedgerComponent implements OnInit, AfterViewInit {
return !account ? '' : typeof account === 'string' ? account : account.name;
}
calculateTotals() {
this.debit = 0;
this.credit = 0;
this.running = 0;
this.info.body.forEach((item) => {
if (item.type !== 'Opening Balance') {
this.debit += item.debit;
this.credit += item.credit;
if (item.posted) {
this.running += item.debit - item.credit;
}
} else {
this.running += item.debit - item.credit;
}
item.running = this.running;
});
tagChanges(value: string[]) {
this.filter.next(value);
}
selected(event: MatAutocompleteSelectedEvent): void {
@@ -193,6 +210,46 @@ export class LedgerComponent implements OnInit, AfterViewInit {
this.selectedRowId = id;
}
/** Whether the number of selected elements matches the total number of rows. */
isAllSelected() {
const numSelected = this.selection.selected.length;
const numRows = this.dataSource.data.length;
return numSelected === numRows;
}
/** Selects all rows if they are not all selected; otherwise clear selection. */
toggleAllRows() {
if (this.isAllSelected()) {
this.selection.clear();
return;
}
this.selection.select(...this.dataSource.data);
}
labels() {
if (!this.selection.selected.length) {
return;
}
this.dialog
.open(TagDialogComponent, {
width: '750px',
data: {
tags: this.allTags,
vouchers: this.selection.selected,
},
})
.afterClosed()
.subscribe({
next: (result) => {
if (result) {
this.router.navigateByUrl(this.router.url);
}
},
});
}
show() {
const info = this.getInfo();
if (info.account) {