/** * 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, inject } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatTableModule } from '@angular/material/table'; import { MatPaginatorModule, PageEvent } from '@angular/material/paginator'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; /** Custom Services */ import { ClearingService } from '../../clearing-network/clearing.service'; import { pillClass, clearingError } from '../../clearing-network/clearing-status'; /** * CTS view of the shared net-settlement batches — prepared from validated inward batches, posted to the GL * or rejected. clearingType is fixed to 'CTS'. */ @Component({ selector: 'mifosx-cts-settlement', templateUrl: './settlement.component.html', styleUrls: ['./settlement.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, MatIconModule, MatButtonModule, MatTableModule, MatPaginatorModule, MatSnackBarModule, FaIconComponent ] }) export class SettlementComponent implements OnInit { private formBuilder = inject(UntypedFormBuilder); private clearingService = inject(ClearingService); private snackBar = inject(MatSnackBar); readonly clearingType = 'CTS'; pillClass = pillClass; private notify(message: string, isError = false): void { this.snackBar.open(message, 'Dismiss', { duration: isError ? 6000 : 3000 }); } batches: any[] = []; totalRecords = 0; pageSize = 10; pageIndex = 0; pageSizeOptions = [ 10, 25, 50, 100 ]; statusFilter = ''; busy = false; rejectForId: number | null = null; rejectForm: UntypedFormGroup; columns = [ 'id', 'settlementDate', 'sourceReference', 'passed', 'returned', 'netAmount', 'status', 'actions' ]; constructor() { this.rejectForm = this.formBuilder.group({ reason: [ '', Validators.required ] }); } ngOnInit(): void { this.loadBatches(); } loadBatches(): void { this.clearingService .getSettlementBatches( this.clearingType, this.statusFilter || undefined, this.pageIndex * this.pageSize, this.pageSize ) .subscribe((res: any) => { this.batches = res?.pageItems ?? (Array.isArray(res) ? res : []); this.totalRecords = Number(res?.totalFilteredRecords ?? this.batches.length); }); } filterByStatus(status: string): void { this.statusFilter = this.statusFilter === status ? '' : status; this.pageIndex = 0; this.loadBatches(); } onPageChange(event: PageEvent): void { this.pageSize = event.pageSize; this.pageIndex = event.pageIndex; this.loadBatches(); } post(batch: any): void { if (this.busy) { return; } this.busy = true; this.clearingService.postSettlement(batch.id).subscribe({ next: () => { this.busy = false; this.notify('Settlement posted'); this.loadBatches(); }, error: (err: any) => { this.busy = false; this.notify(clearingError(err, 'Post failed'), true); } }); } toggleReject(batch: any): void { this.rejectForId = this.rejectForId === batch.id ? null : batch.id; this.rejectForm.reset(); } submitReject(id: number): void { if (this.rejectForm.invalid || this.busy) { return; } this.busy = true; this.clearingService.rejectSettlement(id, { reason: this.rejectForm.value.reason, locale: 'en' }).subscribe({ next: () => { this.busy = false; this.rejectForId = null; this.notify('Settlement rejected'); this.loadBatches(); }, error: (err: any) => { this.busy = false; this.notify(clearingError(err, 'Reject failed'), true); } }); } }