From 6624009d8c532f39e9d41eb49bb627c6086bb6b4 Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Mon, 31 Aug 2026 15:09:21 +0530 Subject: [PATCH] feat(accounting): redesign Migrate Opening Balances for clarity, point env at abc_bank tenant - Replaces the flat, hard-to-scan opening-balances form with a stepped layout: branch pick, a clearly-explained contra account, a pinned Debit/Credit balance status (green "Balanced" vs red "Out of balance by X"), and account rows grouped by type with a mobile-responsive grid. No behavior change - same form controls, same validation, same submit flow. - env.js: default/available tenant switched from default,socity_bank to abc_bank. Co-Authored-By: Claude Sonnet 5 --- .../migrate-opening-balances.component.html | 261 ++++++++------- .../migrate-opening-balances.component.scss | 297 +++++++++++++++++- .../migrate-opening-balances.component.ts | 4 +- src/assets/env.js | 4 +- 4 files changed, 448 insertions(+), 118 deletions(-) diff --git a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.html b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.html index 339dfc4bb..728b7cf77 100644 --- a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.html +++ b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.html @@ -6,48 +6,67 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -
- -
+
+ + + -
-
- - {{ 'labels.inputs.Office' | translate }} - - @for (office of officeData; track office) { - - {{ office.name }} - - } - - @if (openingBalancesForm.controls.officeId.hasError('required')) { - - {{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - } - -
- -
- -
+
+ info + + Bring a branch's existing balances into this system's ledger, one time, as a single balanced entry against + the Opening Balances Contra account below. +
+
+ + {{ 'labels.inputs.Office' | translate }} + + @for (office of officeData; track office) { + + {{ office.name }} + + } + + @if (openingBalancesForm.controls.officeId.hasError('required')) { + + {{ 'labels.inputs.Office' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + } + + +
+ + - @if (openingBalancesData) { -
- - - + @if (openingBalancesData) { + + + +
+ account_balance +
+
Opening Balances Contra Account
+
+ +
+
+ Every debit and credit below posts against this one account, so the whole entry always balances to zero. +
+
+
+ +
+ {{ 'labels.inputs.Currency' | translate }} @for (currency of currencyData; track currency) { @@ -63,7 +82,7 @@ } - + {{ 'labels.inputs.Opening Balances Date' | translate }} } -
-
- {{ 'labels.inputs.Type' | translate }} -
-
- {{ 'labels.inputs.GL Code' | translate }} -
-
- {{ 'labels.inputs.GL Name' | translate }} - {{ 'labels.inputs.Account' | translate }} -
-
- {{ 'labels.inputs.Total Debit' | translate }}: - {{ debitsSum | currency: currencyCode : 'symbol-narrow' : '1.2-2' }} -
-
- {{ 'labels.inputs.Total Credit' | translate }}: - {{ creditsSum | currency: currencyCode : 'symbol-narrow' : '1.2-2' }} -
+
+ + + + +
+
+ {{ 'labels.inputs.Total Debit' | translate }} + {{ + debitsSum | currency: currencyCode : 'symbol-narrow' : '1.2-2' + }} +
+
+ {{ 'labels.inputs.Total Credit' | translate }} + {{ + creditsSum | currency: currencyCode : 'symbol-narrow' : '1.2-2' + }} +
+
+ @if (debitsSum === creditsSum && debitsSum > 0) { + check_circle + Balanced — ready to submit + } @else if (debitsSum === 0 && creditsSum === 0) { + edit_note + Enter each account's opening balance below + } @else { + error + Out of balance by {{ debitsSum - creditsSum | currency: currencyCode : 'symbol-narrow' : '1.2-2' }} + } +
+
+ + + + +
+
{{ 'labels.inputs.GL Code' | translate }}
+
+ {{ 'labels.inputs.GL Name' | translate }} {{ 'labels.inputs.Account' | translate }}
- @for (credit of glAccountEntries.controls; track credit; let i = $index) { -
-
-
- {{ - openingBalancesData.glAccounts[i].glAccountType.value !== - openingBalancesData.glAccounts[i - 1]?.glAccountType.value - ? glAccountTypeLabel(openingBalancesData.glAccounts[i].glAccountType.value) - : '' - }} -
-
- {{ openingBalancesData.glAccounts[i].glAccountCode }} -
-
- {{ openingBalancesData.glAccounts[i].glAccountName }} -
-
- - {{ 'labels.inputs.Debit' | translate }} - - -
-
- - {{ 'labels.inputs.Credit' | translate }} - - -
-
+
{{ 'labels.inputs.Debit' | translate }}
+
{{ 'labels.inputs.Credit' | translate }}
+
+ + @for (credit of glAccountEntries.controls; track credit; let i = $index) { + @if ( + openingBalancesData.glAccounts[i].glAccountType.value !== + openingBalancesData.glAccounts[i - 1]?.glAccountType.value + ) { +
+ {{ glAccountTypeLabel(openingBalancesData.glAccounts[i].glAccountType.value) }}
} -
- } -
+
+
+
{{ openingBalancesData.glAccounts[i].glAccountCode }}
+
{{ openingBalancesData.glAccounts[i].glAccountName }}
+
+ + + +
+
+ + + +
+
+
+ } + +
- @if (openingBalancesData) { - - - - - } - - +
+ + + @if (!(debitsSum === creditsSum && debitsSum > 0)) { + Total Debit must equal Total Credit before this can be submitted + } + +
+ } +
diff --git a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.scss b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.scss index f31f93b1e..14cf2ca5a 100644 --- a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.scss +++ b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.scss @@ -6,14 +6,299 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -.content { - padding-top: 20px; +.mob { + max-width: 960px; +} - div { - word-wrap: break-word; +.mob-card { + margin-bottom: 14px; + border-radius: 8px; - &.header { - font-weight: 500; + &--flush mat-card-content { + padding: 0; + } +} + +.mob-intro { + display: flex; + align-items: flex-start; + gap: 8px; + padding: 10px 14px; + margin-bottom: 14px; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 8px; + color: #1e40af; + font-size: 12px; + line-height: 1.5; + + mat-icon { + font-size: 18px; + width: 18px; + height: 18px; + flex: none; + } +} + +.mob-row { + display: flex; + align-items: flex-start; + gap: 16px; + flex-wrap: wrap; +} + +.mob-office { + flex: 1 1 320px; +} + +.mob-field { + flex: 1 1 240px; +} + +.mob-contra { + display: flex; + align-items: flex-start; + gap: 10px; + padding: 10px 14px; + margin-bottom: 16px; + background: #f8fafc; + border: 1px solid #e2e8f0; + border-left: 4px solid #0ea5e9; + border-radius: 8px; + + mat-icon { + color: #0ea5e9; + margin-top: 2px; + } + + &__label { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.02em; + color: #64748b; + } + + &__value { + font-size: 13px; + font-weight: 600; + color: #0d1b2a; + margin: 2px 0 4px; + } + + &__hint { + font-size: 11px; + color: #64748b; + line-height: 1.4; + } +} + +/* The one figure that decides whether this can be submitted — kept visually separate from the + cards around it so it reads as a status, not just another form section. */ +.mob-balance { + display: flex; + align-items: center; + gap: 24px; + flex-wrap: wrap; + padding: 12px 16px; + margin-bottom: 14px; + background: #fef2f2; + border: 1px solid #fecaca; + border-left: 4px solid #dc2626; + border-radius: 8px; + + &--ok { + background: #f0fdf4; + border-color: #bbf7d0; + border-left-color: #16a34a; + } + + &__figure { + display: flex; + flex-direction: column; + gap: 2px; + } + + &__label { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.02em; + color: #64748b; + } + + &__amt { + font-variant-numeric: tabular-nums; + font-weight: 700; + font-size: 16px; + white-space: nowrap; + + &--dr { + color: #b91c1c; + } + + &--cr { + color: #15803d; + } + } + + &__status { + display: flex; + align-items: center; + gap: 6px; + margin-left: auto; + font-size: 13px; + font-weight: 600; + color: #b91c1c; + + mat-icon { + font-size: 20px; + width: 20px; + height: 20px; + } + } + + &--ok &__status { + color: #15803d; + } +} + +/* Account entry grid: a header row, a section label per account type, then one row per account. */ +.mob-grid { + display: grid; + grid-template-columns: 90px 1fr 160px 160px; + align-items: center; + gap: 8px; + padding: 0 14px; + + &--head { + padding: 12px 14px; + background: #f8fafc; + border-bottom: 1px solid #e2e8f0; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.02em; + color: #64748b; + } + + &__section { + padding: 8px 14px 4px; + margin-top: 6px; + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + color: #0ea5e9; + border-top: 1px solid #e2e8f0; + + &:first-of-type { + border-top: none; + margin-top: 0; + } + } + + &--data { + padding-top: 4px; + padding-bottom: 4px; + border-bottom: 1px solid #f1f5f9; + } + + &__row { + display: contents; + } + + &__code { + font-variant-numeric: tabular-nums; + font-size: 12px; + color: #64748b; + } + + &__name { + font-size: 13px; + color: #0d1b2a; + word-break: break-word; + } + + &__amt { + text-align: right; + } + + &__input { + width: 100%; + + ::ng-deep .mat-mdc-form-field-infix { + padding-top: 10px; + padding-bottom: 10px; + min-height: unset; + } + + ::ng-deep .mat-mdc-text-field-wrapper { + padding: 0 8px; + } + + input { + text-align: right; + font-variant-numeric: tabular-nums; + } + } +} + +.mob-actions { + display: flex; + align-items: center; + gap: 12px; + margin-top: 16px; + padding-bottom: 24px; +} + +.mob-actions__spacer { + flex: 1 1 auto; +} + +.mob-actions__hint { + font-size: 12px; + color: #b91c1c; +} + +@media (width <= 640px) { + .mob-grid { + grid-template-columns: 70px 1fr; + row-gap: 4px; + + &--head { + display: none; + } + + &__row { + display: grid; + grid-template-columns: 70px 1fr; + grid-template-areas: + 'code name' + 'debit debit' + 'credit credit'; + gap: 4px; + padding: 10px 0; + border-bottom: 1px solid #f1f5f9; + } + + &__code { + grid-area: code; + } + + &__name { + grid-area: name; + } + + &__amt:nth-of-type(1) { + grid-area: debit; + } + + &__amt:nth-of-type(2) { + grid-area: credit; + } + + &__amt { + text-align: left; } } } diff --git a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.ts b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.ts index 923463829..b1636d9df 100644 --- a/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.ts +++ b/src/app/accounting/migrate-opening-balances/migrate-opening-balances.component.ts @@ -16,6 +16,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; +import { MatIconModule } from '@angular/material/icon'; /** Custom Services */ import { AccountingService } from '../accounting.service'; @@ -41,7 +42,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; imports: [ ...STANDALONE_SHARED_IMPORTS, GlAccountDisplayComponent, - CurrencyPipe + CurrencyPipe, + MatIconModule ] }) export class MigrateOpeningBalancesComponent implements OnInit, AfterViewInit { diff --git a/src/assets/env.js b/src/assets/env.js index 8493889f7..f2ee5002a 100644 --- a/src/assets/env.js +++ b/src/assets/env.js @@ -17,8 +17,8 @@ window["env"]["apiVersion"] = ''; window["env"]["apiActuator"] = ''; - window["env"]["fineractPlatformTenantId"] = ''; - window["env"]["fineractPlatformTenantIds"] = 'default,socity_bank'; + window["env"]["fineractPlatformTenantId"] = 'abc_bank'; + window["env"]["fineractPlatformTenantIds"] = 'abc_bank'; window['env']['tenantLogoUrl'] = ''; window['env']['tenantLogoUrlDark'] = '';