feat(clearing): add CTS/NACH clearing UI with real NPCI batch sessions
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s

- 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>
This commit is contained in:
Jaanu423
2026-07-21 15:57:45 +05:30
co-authored by Claude Sonnet 5
parent ed2a40a8bf
commit 6d205c0ed2
55 changed files with 6801 additions and 8 deletions
@@ -0,0 +1,77 @@
<!--
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/.
-->
<h1 mat-dialog-title>{{ 'labels.inputs.Cheque' | translate }} {{ item.chequeNumber }}</h1>
<div mat-dialog-content>
<div class="info-grid">
<div>
<span class="k">{{ 'labels.inputs.Payee Name' | translate }}</span
><span>{{ item.payeeName || '–' }}</span>
</div>
<div>
<span class="k">{{ 'labels.inputs.Amount' | translate }}</span
><span>{{ item.amount }}</span>
</div>
<div>
<span class="k">{{ 'labels.inputs.Account' | translate }}</span
><span>{{ item.accountNo || item.accountId || '–' }}</span>
</div>
</div>
<div class="mode-toggle">
<button mat-stroked-button type="button" [class.active]="mode === 'PASS'" color="primary" (click)="setMode('PASS')">
{{ 'labels.buttons.Pass' | translate }}
</button>
<button
mat-stroked-button
type="button"
[class.active]="mode === 'RETURN'"
color="warn"
(click)="setMode('RETURN')"
>
{{ 'labels.buttons.Return' | translate }}
</button>
</div>
@if (mode === 'PASS') {
<form [formGroup]="passForm">
<mat-form-field appearance="fill">
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<input matInput formControlName="note" />
</mat-form-field>
</form>
} @else {
<form [formGroup]="returnForm">
<mat-form-field appearance="fill">
<mat-label>{{ 'labels.inputs.Return Reason Code' | translate }}</mat-label>
<mat-select formControlName="returnReasonCode" required>
@for (c of reasonCodes; track c.id) {
<mat-option [value]="c.code">{{ c.code }} — {{ c.description }}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>{{ 'labels.inputs.Reason' | translate }}</mat-label>
<input matInput formControlName="reason" />
</mat-form-field>
</form>
}
</div>
<div mat-dialog-actions align="end">
<button mat-raised-button type="button" mat-dialog-close>{{ 'labels.buttons.Cancel' | translate }}</button>
<button
mat-raised-button
[color]="mode === 'RETURN' ? 'warn' : 'primary'"
(click)="submit()"
[disabled]="busy || (mode === 'RETURN' && returnForm.invalid)"
>
{{ (mode === 'PASS' ? 'labels.buttons.Pass' : 'labels.buttons.Return') | translate }}
</button>
</div>