/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** Angular Imports */ import { Component, OnInit, ViewChild, AfterViewInit, inject } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { UntypedFormControl, ReactiveFormsModule } from '@angular/forms'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort, MatSortHeader } from '@angular/material/sort'; import { MatTableDataSource, MatTable, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow } from '@angular/material/table'; /** rxjs Imports */ import { startWith, map, debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; /** Custom Services */ import { AccountingService } from '../../accounting.service'; import { AsyncPipe } from '@angular/common'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MatAutocompleteTrigger, MatAutocomplete, MatOption } from '@angular/material/autocomplete'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; /** * View provisioning entry component. */ @Component({ selector: 'mifosx-view-provisioning-entry', templateUrl: './view-provisioning-entry.component.html', styleUrls: ['./view-provisioning-entry.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, FaIconComponent, MatAutocompleteTrigger, MatAutocomplete, MatTable, MatSort, MatColumnDef, MatHeaderCellDef, MatHeaderCell, MatSortHeader, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, MatPaginator, AsyncPipe ] }) export class ViewProvisioningEntryComponent implements OnInit, AfterViewInit { private accountingService = inject(AccountingService); private route = inject(ActivatedRoute); private router = inject(Router); /** Provisioning entry id. */ provisioningEntryId: string; /** Provisioning entry. */ provisioningEntry: any; /** Provisioning entry entries. */ provisioningEntryEntries: any; /** Office name filter form control. */ officeName = new UntypedFormControl(); /** Office data. */ officeData: any; /** Filtered office data for autocomplete. */ filteredOfficeData: any; /** Loan product filter form control. */ loanProduct = new UntypedFormControl(); /** Loan product data. */ loanProductData: any; /** Filtered loan product data for autocomplete. */ filteredLoanProductData: any; /** Provisioning category filter form control. */ provisioningCategory = new UntypedFormControl(); /** Provisioning category data. */ provisioningCategoryData: any; /** Filtered provisioning category data for autocomplete. */ filteredProvisioningCategoryData: any; /** Columns to be displayed in provisioning entry entries table. */ displayedColumns: string[] = [ 'officeName', 'productName', 'currencyCode', 'categoryName', 'amountreserved', 'liabilityAccountName', 'expenseAccountName' ]; /** Data source for provisioning entry entries table. */ dataSource: MatTableDataSource; /** Provisioning entry entries filter. */ filterValue: any = { officeName: '', productName: '', categoryName: '' }; /** Paginator for provisioning entry entries table. */ @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; /** Sorter for provisioning entry entries table. */ @ViewChild(MatSort, { static: true }) sort: MatSort; /** * Retrieves the provisioning entry, provisioning entry entries, offices, * loan products, provisioning categories data from `resolve`. * @param {AccountingService} accountingService Accounting Service. * @param {ActivatedRoute} route Activated Route. * @param {Router} router Router for navigation. */ constructor() { this.route.data.subscribe( (data: { provisioningEntry: any; provisioningEntryEntries: any; offices: any; loanProducts: any; provisiningCategories: any; }) => { this.provisioningEntryId = data.provisioningEntry.id; this.provisioningEntry = data.provisioningEntry; this.provisioningEntryEntries = data.provisioningEntryEntries; this.officeData = data.offices; this.loanProductData = data.loanProducts; this.provisioningCategoryData = data.provisiningCategories; } ); } /** * Sets filtered offices, loan products and provisioning categories for autocomplete * and provisioning entry entries table. */ ngOnInit() { this.setProvisioningEntryEntries(); this.setFilteredOffices(); this.setFilteredLoanProducts(); this.setFilteredProvisioningCategories(); } /** * Subscribes to all search filters: * Office Name, Loan Product, Provisioning categories. */ ngAfterViewInit() { this.officeName.valueChanges .pipe( map((value) => value.toLowerCase()), debounceTime(500), distinctUntilChanged(), tap((filterValue) => { this.applyFilter(filterValue, 'officeName'); }) ) .subscribe(); this.loanProduct.valueChanges .pipe( map((value) => value.toLowerCase()), debounceTime(500), distinctUntilChanged(), tap((filterValue) => { this.applyFilter(filterValue, 'productName'); }) ) .subscribe(); this.provisioningCategory.valueChanges .pipe( map((value) => value.toLowerCase()), debounceTime(500), distinctUntilChanged(), tap((filterValue) => { this.applyFilter(filterValue, 'categoryName'); }) ) .subscribe(); } /** * Filter predicate for provisioning entry entries table data. * @param {any} data Table data. * @param {any} filterValue Values to filter data by. */ filterPredicate(data: any, filterValue: any) { return ( data.officeName.toLowerCase().indexOf(filterValue['officeName']) !== -1 && data.productName.toLowerCase().indexOf(filterValue['productName']) !== -1 && data.categoryName.toLowerCase().indexOf(filterValue['categoryName']) !== -1 ); } /** * Initializes the data source, paginator, sorter and filter predicate for * provisioning entry entries table. */ setProvisioningEntryEntries() { this.dataSource = new MatTableDataSource(this.provisioningEntryEntries.pageItems); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; this.dataSource.filterPredicate = this.filterPredicate; } /** * Filters data in provisioning entry entries table based on passed value. * @param {string} filterValue Value to filter data. * @param {string} property Property to filter data. */ applyFilter(filterValue: string, property: string) { this.filterValue[property] = filterValue; this.dataSource.filter = this.filterValue; } /** * Sets filtered offices for autocomplete. */ setFilteredOffices() { this.filteredOfficeData = this.officeName.valueChanges.pipe( startWith(''), map((office: any) => (typeof office === 'string' ? office : office.name)), map((officeName: string) => (officeName ? this.filterOfficeAutocompleteData(officeName) : this.officeData)) ); } /** * Sets filtered loan products for autocomplete. */ setFilteredLoanProducts() { this.filteredLoanProductData = this.loanProduct.valueChanges.pipe( startWith(''), map((loanProduct: any) => (typeof loanProduct === 'string' ? loanProduct : loanProduct.name)), map((loanProductName: string) => loanProductName ? this.filterLoanProductAutocompleteData(loanProductName) : this.loanProductData ) ); } /** * Sets filtered provisioning categories for autocomplete. */ setFilteredProvisioningCategories() { this.filteredProvisioningCategoryData = this.provisioningCategory.valueChanges.pipe( startWith(''), map((provisioningCategory: any) => typeof provisioningCategory === 'string' ? provisioningCategory : provisioningCategory.categoryName ), map((provisioningCategoryName: string) => provisioningCategoryName ? this.filterProvisioningCategoryAutocompleteData(provisioningCategoryName) : this.provisioningCategoryData ) ); } /** * Filters offices. * @param {string} officeName Office name to filter office by. * @returns {any} Filtered offices. */ private filterOfficeAutocompleteData(officeName: string): any { return this.officeData.filter((office: any) => office.name.toLowerCase().includes(officeName.toLowerCase())); } /** * Filters loan products. * @param {string} loanProductName Loan product name to filter loan products by. * @returns {any} Filtered loan products. */ private filterLoanProductAutocompleteData(loanProductName: string): any { return this.loanProductData.filter((loanProduct: any) => loanProduct.name.toLowerCase().includes(loanProductName.toLocaleLowerCase()) ); } /** * Filters provisioning categories. * @param {string} provisioningCategoryName Provisioning category name to filter provisioning categories by. * @returns {any} Filtered provisioning categories. */ private filterProvisioningCategoryAutocompleteData(provisioningCategoryName: string): any { return this.provisioningCategoryData.filter((provisioningCategory: any) => provisioningCategory.categoryName.toLowerCase().includes(provisioningCategoryName.toLocaleLowerCase()) ); } /** * Creates provisioning journal entries * and redirects to created entries. */ createProvisioningJournalEntries() { this.accountingService.createProvisioningJournalEntries(this.provisioningEntryId).subscribe((response: any) => { this.router.navigate( [ '../../journal-entries/view', response.resourceId ], { relativeTo: this.route } ); }); } }