/** * 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 { ActivatedRoute, RouterLink } from '@angular/router'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatDialog } from '@angular/material/dialog'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { Observable } from 'rxjs'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; /** Custom Services */ import { ChequeBookService } from '../chequebook.service'; import { LeafDetailDialogComponent } from './leaf-detail-dialog/leaf-detail-dialog.component'; import { buildChequeIssuanceSlipPdf } from './cheque-issuance-slip-pdf'; type LeafAction = 'stoppayment' | 'revokestoppayment' | 'reportlost' | 'cancelleaf' | 'markused' | 'return'; /** * One issued cheque book: its leaf register, and the six leaf-range actions (stop-payment, revoke, * report-lost, cancel-leaf, mark-used, return) — each defaults to the whole book when no range is given. * "Mark as used" is a manual record (this CBS has no clearing/presentment integration to detect it itself) * — a branch sets it once it sees a leaf clear on the bank/clearing statement. "Return" flags a leaf as * presented-and-dishonoured (insufficient funds, signature mismatch, etc.) — terminal, like report-lost. */ @Component({ selector: 'mifosx-cheque-book-detail', templateUrl: './cheque-book-detail.component.html', styleUrls: ['./cheque-book-detail.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, RouterLink, MatButtonModule, MatSnackBarModule, FaIconComponent ] }) export class ChequeBookDetailComponent implements OnInit { private route = inject(ActivatedRoute); private formBuilder = inject(UntypedFormBuilder); private chequeBookService = inject(ChequeBookService); private snackBar = inject(MatSnackBar); private dialog = inject(MatDialog); private notify(message: string, isError = false): void { this.snackBar.open(message, 'Dismiss', { duration: isError ? 6000 : 3000 }); } bookId!: string; book: any = {}; leaves: any[] = []; busy = false; activeAction: LeafAction | null = null; actionForm: UntypedFormGroup; constructor() { this.actionForm = this.formBuilder.group({ fromLeafSeq: [''], toLeafSeq: [''], reason: [''] }); } ngOnInit(): void { this.bookId = this.route.snapshot.paramMap.get('id') as string; this.loadAll(); } loadAll(): void { this.chequeBookService.getBook(this.bookId).subscribe((data: any) => (this.book = data || {})); this.chequeBookService.getLeaves(this.bookId).subscribe((data: any[]) => { this.leaves = data || []; }); } selectLeaf(leaf: any): void { this.dialog.open(LeafDetailDialogComponent, { data: leaf, width: '420px' }); } printIssuanceSlip(): void { const doc = buildChequeIssuanceSlipPdf(this.book); doc.save(`cheque-book-issuance-${this.book.id}.pdf`); } startAction(action: LeafAction): void { this.activeAction = this.activeAction === action ? null : action; this.actionForm.reset(); const reasonControl = this.actionForm.get('reason'); if (action === 'revokestoppayment' || action === 'markused') { reasonControl?.clearValidators(); } else { reasonControl?.setValidators(Validators.required); } reasonControl?.updateValueAndValidity(); } submitAction(): void { if (this.actionForm.invalid || this.busy || !this.activeAction) { return; } this.busy = true; const raw = this.actionForm.value; const payload: any = { locale: 'en' }; if (raw.fromLeafSeq !== '' && raw.fromLeafSeq != null) payload.fromLeafSeq = raw.fromLeafSeq; if (raw.toLeafSeq !== '' && raw.toLeafSeq != null) payload.toLeafSeq = raw.toLeafSeq; if (raw.reason) payload.reason = raw.reason; const actionCalls: Record Observable> = { stoppayment: (id, p) => this.chequeBookService.stopPayment(id, p), revokestoppayment: (id, p) => this.chequeBookService.revokeStopPayment(id, p), reportlost: (id, p) => this.chequeBookService.reportBookLost(id, p), cancelleaf: (id, p) => this.chequeBookService.cancelLeaf(id, p), markused: (id, p) => this.chequeBookService.markUsed(id, p), return: (id, p) => this.chequeBookService.returnBook(id, p) }; const call = actionCalls[this.activeAction](this.bookId, payload); call.subscribe({ next: () => { this.busy = false; this.activeAction = null; this.notify('Action applied'); this.loadAll(); }, error: () => { this.busy = false; this.notify( 'Action failed — check the leaf range and that the leaves are in a state that allows this action', true ); } }); } }