| Denomination |
+ Morning |
Expected |
Physical |
Variance |
@@ -139,6 +183,7 @@
₹{{ row.denominationValue }}
|
+ {{ row.morningCount || '—' }} |
{{ row.expectedCount }} |
diff --git a/src/app/cashier/reconciliation/reconciliation.component.scss b/src/app/cashier/reconciliation/reconciliation.component.scss
index 9dfc43133..e690d7b80 100644
--- a/src/app/cashier/reconciliation/reconciliation.component.scss
+++ b/src/app/cashier/reconciliation/reconciliation.component.scss
@@ -111,3 +111,116 @@
color: #92400e;
}
}
+
+.pg-chip--coin {
+ background: #fef3c7;
+ color: #92400e;
+ border-color: #fcd34d;
+}
+
+/* ── Morning Opening Balance panel ── */
+.morning-panel {
+ background: linear-gradient(135deg, #fffbeb 0%, #fef9ec 100%);
+ border: 1px solid #fcd34d;
+ border-radius: 10px;
+ overflow: hidden;
+
+ &__head {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 12px 16px;
+ border-bottom: 1px solid #fde68a;
+
+ mat-icon {
+ color: #d97706;
+ font-size: 20px;
+ height: 20px;
+ width: 20px;
+ flex-shrink: 0;
+ }
+
+ span {
+ flex: 1;
+ font-size: 13px;
+ font-weight: 600;
+ color: #78350f;
+
+ em {
+ font-weight: 400;
+ opacity: 0.75;
+ font-style: normal;
+ font-size: 12px;
+ }
+ }
+ }
+
+ &__total {
+ font-size: 15px;
+ font-weight: 800;
+ color: #92400e;
+ white-space: nowrap;
+ }
+
+ &__body {
+ padding: 10px 16px 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ }
+
+ &__section-label {
+ font-size: 10px;
+ font-weight: 800;
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+ color: #92400e;
+ margin-bottom: 2px;
+
+ &--coin {
+ color: #78350f;
+ }
+ }
+}
+
+.morning-panel__pills {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-bottom: 4px;
+}
+
+.morning-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 2px;
+ padding: 3px 9px;
+ background: #fef3c7;
+ border: 1px solid #fcd34d;
+ border-radius: 999px;
+ font-size: 12px;
+ font-weight: 700;
+ color: #92400e;
+
+ &--coin {
+ background: #fff7ed;
+ border-color: #fdba74;
+ color: #7c2d12;
+ }
+}
+
+.morning-pill__x {
+ font-weight: 400;
+ opacity: 0.75;
+ margin-left: 1px;
+}
+
+/* ── Morning column in recon table ── */
+.recon-col-morning {
+ color: #d97706;
+}
+
+.recon-morning {
+ color: #b45309;
+ font-weight: 600;
+}
diff --git a/src/app/cashier/reconciliation/reconciliation.component.ts b/src/app/cashier/reconciliation/reconciliation.component.ts
index ca2c76ec3..27b8e3ff5 100644
--- a/src/app/cashier/reconciliation/reconciliation.component.ts
+++ b/src/app/cashier/reconciliation/reconciliation.component.ts
@@ -15,7 +15,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { MatInputModule } from '@angular/material/input';
import { MatTabsModule } from '@angular/material/tabs';
-import { of } from 'rxjs';
+import { forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { CashierService } from '../cashier.service';
@@ -23,6 +23,7 @@ interface DenomRow {
denominationId: number;
denominationValue: number;
kind: string;
+ morningCount: number;
expectedCount: number;
physicalCount: number;
varianceCount: number;
@@ -75,6 +76,7 @@ export class ReconciliationComponent implements OnInit {
note = '';
varianceReason = '';
rows: DenomRow[] = [];
+ morningTotal = 0;
loadingExpected = false;
saving = false;
@@ -120,21 +122,33 @@ export class ReconciliationComponent implements OnInit {
fetchExpected(): void {
if (!this.selectedCashierId) return;
this.loadingExpected = true;
- this.service
- .getExpectedBalance(this.selectedCashierId, this.reconDate)
- .pipe(catchError(() => of(null)))
- .subscribe((data: any) => {
- this.loadingExpected = false;
- if (!data) return;
- this.rows = (data.denominations || []).map((d: any) => ({
+ forkJoin({
+ expected: this.service
+ .getExpectedBalance(this.selectedCashierId, this.reconDate)
+ .pipe(catchError(() => of(null))),
+ morning: this.service
+ .getCashierMorningBalance(this.selectedCashierId, this.reconDate)
+ .pipe(catchError(() => of(null)))
+ }).subscribe(({ expected, morning }) => {
+ this.loadingExpected = false;
+ const morningMap = new Map();
+ ((morning?.denominations || []) as any[]).forEach((d: any) =>
+ morningMap.set(d.denominationId, d.morningCount ?? 0)
+ );
+ this.morningTotal = Number(morning?.totalMorning ?? 0);
+ if (!expected) return;
+ this.rows = ((expected.denominations || []) as any[])
+ .sort((a: any, b: any) => b.denominationValue - a.denominationValue)
+ .map((d: any) => ({
denominationId: d.denominationId || null,
denominationValue: d.denominationValue,
kind: d.kind || 'note',
+ morningCount: morningMap.get(d.denominationId) ?? 0,
expectedCount: d.expectedCount || 0,
physicalCount: d.expectedCount || 0,
varianceCount: 0
}));
- });
+ });
}
updatePhysical(row: DenomRow, raw: any): void {
@@ -148,6 +162,12 @@ export class ReconciliationComponent implements OnInit {
get coinRows(): DenomRow[] {
return this.rows.filter((r) => r.kind === 'coin');
}
+ get morningNoteTotal(): number {
+ return this.noteRows.reduce((s, r) => s + r.morningCount * r.denominationValue, 0);
+ }
+ get morningCoinTotal(): number {
+ return this.coinRows.reduce((s, r) => s + r.morningCount * r.denominationValue, 0);
+ }
get totalExpected(): number {
return this.rows.reduce((s, r) => s + r.denominationValue * r.expectedCount, 0);
|