diff --git a/src/app/cashier/cashier-shared.scss b/src/app/cashier/cashier-shared.scss index f544f9a0f..9874d3ade 100644 --- a/src/app/cashier/cashier-shared.scss +++ b/src/app/cashier/cashier-shared.scss @@ -428,3 +428,190 @@ border: 1px solid #bfdbfe; } } + +// GL View toggle button active state +.pg-btn--active { + background: #1e3a5f; + color: #fff; + border-color: #1e3a5f; +} + +// GL Card +.gl-card { + background: #fff; + border: 1px solid #e2e8f0; + border-radius: 12px; + overflow: hidden; + + &__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 20px; + background: #f8fafc; + border-bottom: 1px solid #e2e8f0; + gap: 16px; + flex-wrap: wrap; + } + + &__header-left { + display: flex; + align-items: center; + gap: 12px; + } + + &__icon { + width: 40px; + height: 40px; + border-radius: 10px; + background: #1e3a5f; + display: flex; + align-items: center; + justify-content: center; + + mat-icon { + color: #fff; + font-size: 20px; + width: 20px; + height: 20px; + } + } + + &__title { + font-size: 15px; + font-weight: 700; + color: #1e293b; + } + + &__sub { + font-size: 12px; + color: #64748b; + margin-top: 2px; + } + + &__totals { + display: flex; + align-items: center; + gap: 16px; + } + + &__total-sep { + color: #cbd5e1; + font-size: 18px; + } + + &__total { + display: flex; + flex-direction: column; + align-items: flex-end; + } + + &__total-label { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #94a3b8; + } + + &__total-value { + font-size: 18px; + font-weight: 800; + font-variant-numeric: tabular-nums; + } + + &__total--dr .gl-card__total-value { + color: #dc2626; + } + + &__total--cr .gl-card__total-value { + color: #15803d; + } + + &__filters { + display: flex; + align-items: flex-end; + gap: 12px; + padding: 14px 20px; + border-bottom: 1px solid #f1f5f9; + flex-wrap: wrap; + background: #fff; + } +} + +// GL Table +.gl-table { + .gl-th--voucher { + width: 110px; + } + + .gl-th--dr { + color: #dc2626 !important; + } + + .gl-th--cr { + color: #15803d !important; + } + + .gl-voucher { + font-family: 'Roboto Mono', 'Courier New', monospace; + font-size: 12px; + font-weight: 700; + color: #475569; + } + + .gl-acno { + font-family: 'Roboto Mono', 'Courier New', monospace; + font-size: 12px; + color: #1d4ed8; + } + + .gl-acname { + font-weight: 500; + color: #1e293b; + } + + .gl-amt--dr { + color: #dc2626; + font-weight: 700; + } + + .gl-amt--cr { + color: #15803d; + font-weight: 700; + } + + .gl-row--dr td { + background: #fff5f5; + } + + .gl-row--cr td { + background: #f0fdf4; + } + + .gl-row--dr:hover td { + background: #fee2e2; + } + + .gl-row--cr:hover td { + background: #dcfce7; + } + + .gl-foot { + background: #f1f5f9; + border-top: 2px solid #e2e8f0; + + &__label { + font-size: 13px; + font-weight: 800; + color: #1e293b; + padding: 12px 14px; + } + + &__val { + font-size: 14px; + font-weight: 800; + padding: 12px 14px; + } + } +} diff --git a/src/app/cashier/cashier.service.ts b/src/app/cashier/cashier.service.ts index 892d61bac..d27a9923a 100644 --- a/src/app/cashier/cashier.service.ts +++ b/src/app/cashier/cashier.service.ts @@ -129,6 +129,13 @@ export class CashierService { return this.http.get('/cashreports/cashier-day-status'); } + getGlEntries(date: string, cashierId?: number, tellerId?: number): Observable { + let params = new HttpParams().set('date', date); + if (cashierId) params = params.set('cashierId', String(cashierId)); + if (tellerId) params = params.set('tellerId', String(tellerId)); + return this.http.get('/cashreports/gl-entries', { params }); + } + checkSettlement(cashierId: number, date: string): Observable { const params = new HttpParams().set('cashierId', String(cashierId)).set('date', date); return this.http.get('/cashsettlement/check', { params }); diff --git a/src/app/cashier/closing-cash-report/closing-cash-report.component.html b/src/app/cashier/closing-cash-report/closing-cash-report.component.html index 2576bf0e7..95ae8e8b1 100644 --- a/src/app/cashier/closing-cash-report/closing-cash-report.component.html +++ b/src/app/cashier/closing-cash-report/closing-cash-report.component.html @@ -21,10 +21,13 @@ + - @if (rows.length > 0) { + @if (!showGl && rows.length > 0) {
@@ -48,98 +51,205 @@
} -
- @if (noteRows.length > 0) { - - - - - - - - - - - - - - - @for (r of noteRows; track r.denominationId) { + @if (!showGl) { +
+ @if (noteRows.length > 0) { + +
DenominationDeposit PcsDeposit AmtWithdrawal PcsWithdrawal AmtNet PcsNet Amount
+ - - - - - - - + + + + + + + - } - -
- ₹{{ r.denominationValue }} - {{ r.depositCount }}₹{{ r.depositAmount | number: '1.2-2' }}{{ r.withdrawalCount }}₹{{ r.withdrawalAmount | number: '1.2-2' }} - {{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }} - - {{ r.netCount >= 0 ? '' : '−' }}₹{{ (r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2' }} - DenominationDeposit PcsDeposit AmtWithdrawal PcsWithdrawal AmtNet PcsNet Amount
- } + + + @for (r of noteRows; track r.denominationId) { + + + ₹{{ r.denominationValue }} + + {{ r.depositCount }} + ₹{{ r.depositAmount | number: '1.2-2' }} + {{ r.withdrawalCount }} + ₹{{ r.withdrawalAmount | number: '1.2-2' }} + + {{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }} + + + {{ r.netCount >= 0 ? '' : '−' }}₹{{ + (r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2' + }} + + + } + + + } - @if (coinRows.length > 0) { - - - - - - - - - - - - - - - @for (r of coinRows; track r.denominationId) { + @if (coinRows.length > 0) { + +
DenominationDeposit PcsDeposit AmtWithdrawal PcsWithdrawal AmtNet PcsNet Amount
+ - - - - - - - + + + + + + + - } - -
- ₹{{ r.denominationValue }} - {{ r.depositCount }}₹{{ r.depositAmount | number: '1.2-2' }}{{ r.withdrawalCount }}₹{{ r.withdrawalAmount | number: '1.2-2' }} - {{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }} - - {{ r.netCount >= 0 ? '' : '−' }}₹{{ (r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2' }} - DenominationDeposit PcsDeposit AmtWithdrawal PcsWithdrawal AmtNet PcsNet Amount
- } + + + @for (r of coinRows; track r.denominationId) { + + + ₹{{ r.denominationValue }} + + {{ r.depositCount }} + ₹{{ r.depositAmount | number: '1.2-2' }} + {{ r.withdrawalCount }} + ₹{{ r.withdrawalAmount | number: '1.2-2' }} + + {{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }} + + + {{ r.netCount >= 0 ? '' : '−' }}₹{{ + (r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2' + }} + + + } + + + } - @if (loaded && rows.length === 0 && exchangeRows.length === 0) { -
No cash denomination data for this date.
- } -
+ @if (loaded && rows.length === 0 && exchangeRows.length === 0) { +
No cash denomination data for this date.
+ } +
+ } + - - @if (exchangeRows.length > 0) { + + @if (showGl) { +
+ +
+
+
+ account_balance +
+
+
GL Entries
+
Cashier transaction ledger for {{ date }}
+
+
+
+
+ Total DR + ₹{{ glTotalDr | number: '1.2-2' }} +
+
|
+
+ Total CR + ₹{{ glTotalCr | number: '1.2-2' }} +
+
+
+ + +
+ + @if (selectedTellerId) { + + } + +
+ + + @if (glLoading) { +
Loading...
+ } @else if (glRows.length === 0 && glLoaded) { +
No entries found for this date and filter.
+ } @else if (glRows.length > 0) { + + + + + + + + + + + + @for (r of glRows; track $index) { + + + + + + + + } + + + + + + + + +
Voucher NoA/C NoA/C NameDR (₹)CR (₹)
{{ r.voucherNo }}{{ r.acNo }}{{ r.acName }} + @if (r.dr > 0) { + ₹{{ r.dr | number: '1.2-2' }} + } + + @if (r.cr > 0) { + ₹{{ r.cr | number: '1.2-2' }} + } +
Total₹{{ glTotalDr | number: '1.2-2' }}₹{{ glTotalCr | number: '1.2-2' }}
+ } +
+ } + + @if (!showGl && exchangeRows.length > 0) {
swap_horiz diff --git a/src/app/cashier/closing-cash-report/closing-cash-report.component.ts b/src/app/cashier/closing-cash-report/closing-cash-report.component.ts index 01a468490..b520a9cd7 100644 --- a/src/app/cashier/closing-cash-report/closing-cash-report.component.ts +++ b/src/app/cashier/closing-cash-report/closing-cash-report.component.ts @@ -36,6 +36,20 @@ export class ClosingCashReportComponent implements OnInit { loading = false; loaded = false; + // GL View + showGl = false; + glRows: any[] = []; + glTotalDr = 0; + glTotalCr = 0; + glLoading = false; + glLoaded = false; + + // Filters for GL + tellers: any[] = []; + cashiers: any[] = []; + selectedTellerId: number | null = null; + selectedCashierId: number | null = null; + get noteRows(): any[] { return this.rows.filter((r) => r.kind !== 'coin'); } @@ -53,9 +67,11 @@ export class ClosingCashReportComponent implements OnInit { const d = new Date(); this.date = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; this.load(); + this.service.getTellers().subscribe({ next: (t: any[]) => (this.tellers = t || []), error: () => {} }); } load(): void { + this.showGl = false; this.loading = true; this.service.closingCashReport(this.date).subscribe({ next: (res: any) => { @@ -78,4 +94,51 @@ export class ClosingCashReportComponent implements OnInit { } }); } + + toggleGl(): void { + this.showGl = !this.showGl; + if (this.showGl && !this.glLoaded) { + this.loadGl(); + } + } + + onTellerChange(): void { + this.selectedCashierId = null; + this.cashiers = []; + if (this.selectedTellerId) { + this.service.getCashiersForTeller(this.selectedTellerId).subscribe({ + next: (res: any) => (this.cashiers = res?.cashiers || res || []), + error: () => {} + }); + } + this.glLoaded = false; + this.loadGl(); + } + + onCashierChange(): void { + this.glLoaded = false; + this.loadGl(); + } + + loadGl(): void { + this.glLoading = true; + this.service + .getGlEntries(this.date, this.selectedCashierId || undefined, this.selectedTellerId || undefined) + .subscribe({ + next: (res: any) => { + this.glRows = res?.rows || []; + this.glTotalDr = Number(res?.totalDr || 0); + this.glTotalCr = Number(res?.totalCr || 0); + this.glLoading = false; + this.glLoaded = true; + }, + error: () => { + this.glRows = []; + this.glTotalDr = 0; + this.glTotalCr = 0; + this.glLoading = false; + this.glLoaded = true; + } + }); + } }