feat(cashier): integrate expected balance, settlement verification, and reconciliation checks

This commit is contained in:
Jaanu423
2026-05-28 22:30:08 +05:30
parent 7ccaffa7f1
commit 6433ae068d
10 changed files with 1362 additions and 201 deletions
@@ -26,10 +26,26 @@ interface TxnRow {
isReversed: boolean;
performedByUsername: string;
createdAt: string;
reversedBy: number | null;
reversedAt: string | null;
reverseReason: string | null;
type: 'transfer' | 'settlement' | 'inter';
}
/** Unified history of all cash movements with reversal support. */
interface DenomDetail {
denominationId: number | null;
denominationValue: number;
count: number;
totalAmount: number;
}
interface DetailView {
row: TxnRow;
denominations: DenomDetail[];
loading: boolean;
}
/** Unified history of all cash movements with reversal and detail view support. */
@Component({
selector: 'mifosx-cash-history',
templateUrl: './cash-history.component.html',
@@ -59,6 +75,8 @@ export class CashHistoryComponent implements OnInit {
reversingType: string | null = null;
reverseReason = '';
detail: DetailView | null = null;
ngOnInit(): void {
this.load();
}
@@ -80,6 +98,9 @@ export class CashHistoryComponent implements OnInit {
isReversed: t.isReversed,
performedByUsername: t.performedByUsername,
createdAt: t.createdAt,
reversedBy: t.reversedBy ?? null,
reversedAt: t.reversedAt ?? null,
reverseReason: t.reverseReason ?? null,
type: 'transfer'
}));
this.settlements = (settlements as any[]).map((s) => ({
@@ -92,6 +113,9 @@ export class CashHistoryComponent implements OnInit {
isReversed: s.isReversed,
performedByUsername: s.performedByUsername,
createdAt: s.createdAt,
reversedBy: s.reversedBy ?? null,
reversedAt: s.reversedAt ?? null,
reverseReason: s.reverseReason ?? null,
type: 'settlement'
}));
this.interCashier = (inter as any[]).map((i) => ({
@@ -104,12 +128,40 @@ export class CashHistoryComponent implements OnInit {
isReversed: i.isReversed,
performedByUsername: i.performedByUsername,
createdAt: i.createdAt,
reversedBy: i.reversedBy ?? null,
reversedAt: i.reversedAt ?? null,
reverseReason: i.reverseReason ?? null,
type: 'inter'
}));
this.loading = false;
});
}
viewDetail(row: TxnRow): void {
this.detail = { row, denominations: [], loading: true };
let obs$;
if (row.type === 'transfer') obs$ = this.service.getCashTransferById(row.id);
else if (row.type === 'settlement') obs$ = this.service.getCashSettlementById(row.id);
else obs$ = this.service.getInterCashierById(row.id);
obs$.pipe(catchError(() => of(null))).subscribe((data: any) => {
if (this.detail) {
this.detail.denominations = (data?.details || []).map((d: any) => ({
denominationId: d.denominationId ?? null,
denominationValue: d.denominationValue,
count: d.count,
totalAmount: d.totalAmount
}));
this.detail.loading = false;
}
});
}
closeDetail(): void {
this.detail = null;
}
startReverse(row: TxnRow): void {
this.reversingId = row.id;
this.reversingType = row.type;
@@ -143,4 +195,12 @@ export class CashHistoryComponent implements OnInit {
}
});
}
typeLabel(type: string): string {
return type === 'transfer' ? 'Cash Transfer' : type === 'settlement' ? 'Cash Settlement' : 'Inter-Cashier Transfer';
}
totalCount(denoms: DenomDetail[]): number {
return denoms.reduce((s, d) => s + d.count, 0);
}
}