- CTS clearing module: inward batches (validate/pass/return), outward presentment capture, positive pay, settlement, reconciliation - Outward Clearing merged into one screen: Pending Cheques + Batches tabs (a real clearing session per NPCI submission, either the 2-hourly job or manual send), drill into a batch to settle/dishonour its cheques - Date-range, text, and quick (Today/Yesterday/All) filters with pagination across inward batches, outward presentments, outward batches, and batch detail - NACH clearing module (mandates, batches, transaction decisioning) - Shell/sidenav wiring for both new modules Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
/**
|
|
* 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 { MatButtonModule } from '@angular/material/button';
|
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|
|
|
/** Custom Services */
|
|
import { NachClearingService } from '../../nachclearing.service';
|
|
import { ClearingService } from '../../../clearing-network/clearing.service';
|
|
import { clearingError } from '../../../clearing-network/clearing-status';
|
|
|
|
/** Pass or return a single NACH transaction. Return requires a standardized reason code. */
|
|
@Component({
|
|
selector: 'mifosx-nach-txn-decision-dialog',
|
|
templateUrl: './txn-decision-dialog.component.html',
|
|
styleUrls: ['./txn-decision-dialog.component.scss'],
|
|
imports: [
|
|
...STANDALONE_SHARED_IMPORTS,
|
|
MatButtonModule,
|
|
MatDialogModule,
|
|
MatSnackBarModule
|
|
]
|
|
})
|
|
export class TxnDecisionDialogComponent implements OnInit {
|
|
dialogRef = inject<MatDialogRef<TxnDecisionDialogComponent>>(MatDialogRef);
|
|
data = inject<{ transaction: any }>(MAT_DIALOG_DATA);
|
|
private formBuilder = inject(UntypedFormBuilder);
|
|
private nachService = inject(NachClearingService);
|
|
private clearingService = inject(ClearingService);
|
|
private snackBar = inject(MatSnackBar);
|
|
|
|
decision: 'PASS' | 'RETURN' = 'PASS';
|
|
reasonCodes: any[] = [];
|
|
busy = false;
|
|
form: UntypedFormGroup;
|
|
|
|
constructor() {
|
|
this.form = this.formBuilder.group({
|
|
returnReasonCode: [''],
|
|
reason: ['']
|
|
});
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.clearingService.getReturnReasonCodes('NACH').subscribe((res: any) => {
|
|
this.reasonCodes = Array.isArray(res) ? res : (res?.pageItems ?? []);
|
|
});
|
|
}
|
|
|
|
setDecision(decision: 'PASS' | 'RETURN'): void {
|
|
this.decision = decision;
|
|
const rc = this.form.get('returnReasonCode');
|
|
if (decision === 'RETURN') {
|
|
rc?.setValidators([Validators.required]);
|
|
} else {
|
|
rc?.clearValidators();
|
|
}
|
|
rc?.updateValueAndValidity();
|
|
}
|
|
|
|
private notify(message: string, isError = false): void {
|
|
this.snackBar.open(message, 'Dismiss', { duration: isError ? 6000 : 3000 });
|
|
}
|
|
|
|
submit(): void {
|
|
if (this.busy) {
|
|
return;
|
|
}
|
|
const id = this.data.transaction.id;
|
|
this.busy = true;
|
|
if (this.decision === 'PASS') {
|
|
this.nachService.passTransaction(id).subscribe({
|
|
next: () => this.done('Transaction passed'),
|
|
error: (err: any) => this.fail(err, 'Could not pass the transaction')
|
|
});
|
|
} else {
|
|
if (this.form.invalid) {
|
|
this.busy = false;
|
|
return;
|
|
}
|
|
this.nachService.returnTransaction(id, this.form.value).subscribe({
|
|
next: () => this.done('Transaction returned'),
|
|
error: (err: any) => this.fail(err, 'Could not return the transaction')
|
|
});
|
|
}
|
|
}
|
|
|
|
private done(message: string): void {
|
|
this.busy = false;
|
|
this.notify(message);
|
|
this.dialogRef.close({ actioned: true });
|
|
}
|
|
|
|
private fail(err: any, fallback: string): void {
|
|
this.busy = false;
|
|
this.notify(clearingError(err, fallback), true);
|
|
}
|
|
}
|