fix(branchday): block day close when cashiers holding cash are not reconciled or settled
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s

This commit is contained in:
2026-09-02 12:06:08 +05:30
parent 63134f172a
commit d90719ad8d
4 changed files with 102 additions and 2 deletions
@@ -539,13 +539,53 @@ export class BranchDayComponent implements OnInit {
return !!this.closeTarget && this.closeTarget.businessDate < this.today;
}
/**
* True when any cashier who was given cash (currentTotal > 0) is still NOT reconciled
* or NOT settled — meaning outstanding cash hasn't been accounted for yet.
*/
get hasUnreconciledOrUnsettledCashiers(): boolean {
for (const t of this.eodTellers) {
for (const c of t.cashiers) {
if (c.currentTotal > 0 && (c.reconciled === false || c.alreadySettled === false)) {
return true;
}
}
}
return false;
}
/** Names of cashiers blocking the close, for the error message. */
get unreconciledOrUnsettledCashierDetails(): { name: string; notReconciled: boolean; notSettled: boolean }[] {
const result: { name: string; notReconciled: boolean; notSettled: boolean }[] = [];
for (const t of this.eodTellers) {
for (const c of t.cashiers) {
if (c.currentTotal > 0 && (c.reconciled === false || c.alreadySettled === false)) {
result.push({
name: c.cashierName,
notReconciled: c.reconciled === false,
notSettled: c.alreadySettled === false
});
}
}
}
return result;
}
get canSubmitClose(): boolean {
const hasFigure = this.closingCash != null || this.closeDenomTotal > 0;
if (!this.closeTarget || !hasFigure || this.closing) return false;
// Block while cashier/vault data is still loading — the reconciliation check can't run yet.
if (this.eodLoading || this.previewLoading) return false;
if (this.hasUnreconciledOrUnsettledCashiers) return false;
return !this.isLateClose || !!this.forceReason.trim();
}
submitClose(): void {
// Safety: re-check reconciliation even if the button was somehow enabled.
if (this.hasUnreconciledOrUnsettledCashiers || this.eodLoading || this.previewLoading) {
this.errorMsg = 'Cannot close — cashiers holding cash have not been reconciled or settled.';
return;
}
const day = this.closeTarget;
const denominations = this.denominationPayload(this.closeCounts);
const figure = denominations.length ? this.closeDenomTotal : this.closingCash;