From 174a2e7b6b08956e3f8ca3a08823ed7b020a6f8b Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Sun, 4 Oct 2026 16:02:15 +0530 Subject: [PATCH] fix(accounting,deposits): allow future dates in premature close and GL search, fix FD/RD accounting mappings --- .../search-journal-entry.component.html | 7 +-- .../search-journal-entry.component.ts | 4 +- ...posit-product-accounting-step.component.ts | 58 ++++++++++++++++- ...posit-product-accounting-step.component.ts | 62 +++++++++++++++++-- 4 files changed, 119 insertions(+), 12 deletions(-) diff --git a/src/app/accounting/search-journal-entry/search-journal-entry.component.html b/src/app/accounting/search-journal-entry/search-journal-entry.component.html index f04105114..a5f7af1fc 100644 --- a/src/app/accounting/search-journal-entry/search-journal-entry.component.html +++ b/src/app/accounting/search-journal-entry/search-journal-entry.component.html @@ -279,7 +279,7 @@
- + @@ -288,7 +288,7 @@
- + @@ -357,7 +357,6 @@ matInput [matDatepicker]="dpSubFrom" [min]="minDate" - [max]="maxDate" [formControl]="submittedOnDateFrom" /> @@ -368,7 +367,7 @@
- + diff --git a/src/app/accounting/search-journal-entry/search-journal-entry.component.ts b/src/app/accounting/search-journal-entry/search-journal-entry.component.ts index cf8330511..a6b2aa257 100644 --- a/src/app/accounting/search-journal-entry/search-journal-entry.component.ts +++ b/src/app/accounting/search-journal-entry/search-journal-entry.component.ts @@ -90,7 +90,7 @@ export class SearchJournalEntryComponent implements OnInit, OnDestroy, AfterView // ── Misc ────────────────────────────────────────────────────────────────── minDate = new Date(2000, 0, 1); - maxDate = new Date(); + maxDate: Date = null; /** Accounting features switched off for this installation — see disabled-features.ts. */ disabledFeatures = DISABLED_ACCOUNTING_FEATURES; @@ -208,7 +208,7 @@ export class SearchJournalEntryComponent implements OnInit, OnDestroy, AfterView } ngOnInit() { - this.maxDate = this.settingsService.businessDate; + this.maxDate = null; this.paginator.pageSize = 10; this.restoreState(); this.setFilteredOffices(); diff --git a/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-accounting-step/fixed-deposit-product-accounting-step.component.ts b/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-accounting-step/fixed-deposit-product-accounting-step.component.ts index 0f6bb338f..e1004052a 100644 --- a/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-accounting-step/fixed-deposit-product-accounting-step.component.ts +++ b/src/app/products/fixed-deposit-products/fixed-deposit-product-stepper/fixed-deposit-product-accounting-step/fixed-deposit-product-accounting-step.component.ts @@ -24,6 +24,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; type AccountingSectionKey = 'assets' | 'liabilities' | 'expenses' | 'income'; +const SAVINGS_INTEREST_PAYABLE_ACCOUNT_NAME = 'Savings Interest Payable'; +const FIXED_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME = 'Fixed Deposit Interest Paid'; +const SAVINGS_INTEREST_PAID_ACCOUNT_NAME = 'Savings Interest Paid'; + type AccountingRowConfig = { key: string; label: string; @@ -128,6 +132,7 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha feesReceivableAccountId: [''], penaltiesReceivableAccountId: [''], interestPayableAccountId: [''], + savingsInterestPaidAccountId: [''], escheatLiabilityId: [''], assetsOtherGlMappings: this.formBuilder.array([]), liabilitiesOtherGlMappings: this.formBuilder.array([]), @@ -158,6 +163,20 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha return ''; } + private extractNamedGlMapping( + otherGlMappings: any[], + accountName: string, + controlName: string, + options: GLAccount[] + ): any[] { + const match = (otherGlMappings || []).find((mapping) => mapping?.accountName === accountName); + if (match) { + const glAccountId = match.glAccountId || options.find((option) => option.glCode === match.glCode)?.id || ''; + this.fixedDepositProductAccountingForm.get(controlName)?.patchValue(glAccountId); + } + return (otherGlMappings || []).filter((mapping) => mapping?.accountName !== accountName); + } + private patchAccountingValues(mappings: any) { this.fixedDepositProductAccountingForm.patchValue({ savingsReferenceAccountId: this.extractAccountId( @@ -200,7 +219,18 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha glMappings?.liabilities || [], this.liabilityAccountOptions ); - this.setOtherGlMappings('expensesOtherGlMappings', glMappings?.expenses || [], this.expenseAccountOptions); + const fromExpenses = this.extractNamedGlMapping( + this.extractNamedGlMapping( + glMappings?.expenses || [], + FIXED_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME, + 'savingsInterestPaidAccountId', + this.expenseAccountOptions + ), + SAVINGS_INTEREST_PAID_ACCOUNT_NAME, + 'savingsInterestPaidAccountId', + this.expenseAccountOptions + ); + this.setOtherGlMappings('expensesOtherGlMappings', fromExpenses, this.expenseAccountOptions); this.setOtherGlMappings('incomeOtherGlMappings', glMappings?.income || [], this.incomeAccountOptions); } } @@ -266,10 +296,26 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha })) .filter((item: { accountName: string; glCode: string }) => !!item.accountName || !!item.glCode); + const namedAsOtherGlMapping = (controlName: string, accountName: string, options: GLAccount[]) => { + const glAccountId = this.fixedDepositProductAccountingForm.get(controlName)?.value; + if (!glAccountId) { + return []; + } + const glCode = options.find((o) => o.id === glAccountId)?.glCode || ''; + return glCode ? [{ accountName, glCode }] : []; + }; + const otherGlMappings = { assets: map('assetsOtherGlMappings', this.assetAccountOptions), liabilities: map('liabilitiesOtherGlMappings', this.liabilityAccountOptions), - expenses: map('expensesOtherGlMappings', this.expenseAccountOptions), + expenses: [ + ...namedAsOtherGlMapping( + 'savingsInterestPaidAccountId', + FIXED_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME, + this.expenseAccountOptions + ), + ...map('expensesOtherGlMappings', this.expenseAccountOptions) + ], income: map('incomeOtherGlMappings', this.incomeAccountOptions) }; return Object.values(otherGlMappings).some((v) => v.length) ? otherGlMappings : null; @@ -416,6 +462,13 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha controlName: 'interestOnSavingsAccountId', options: this.expenseAccountOptions, required: true + }, + { + key: 'savingsInterestPaidAccountId', + label: 'Fixed Deposit Interest Paid', + inputLabel: 'Fixed deposit interest paid', + controlName: 'savingsInterestPaidAccountId', + options: this.expenseAccountOptions } ], otherMappingsControlName: 'expensesOtherGlMappings', @@ -456,6 +509,7 @@ export class FixedDepositProductAccountingStepComponent implements OnInit, OnCha liabilitiesOtherGlMappings, expensesOtherGlMappings, incomeOtherGlMappings, + savingsInterestPaidAccountId, ...accounting } = this.fixedDepositProductAccountingForm.value; const otherGlMappings = this.getOtherGlMappings(); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts index 3ceaa248a..6d3332921 100644 --- a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts @@ -24,6 +24,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; type AccountingSectionKey = 'assets' | 'liabilities' | 'expenses' | 'income'; +const SAVINGS_INTEREST_PAYABLE_ACCOUNT_NAME = 'Savings Interest Payable'; +const RECURRING_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME = 'Recurring Deposit Interest Paid'; +const SAVINGS_INTEREST_PAID_ACCOUNT_NAME = 'Savings Interest Paid'; + type AccountingRowConfig = { key: string; label: string; @@ -122,6 +126,7 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { feesReceivableAccountId: [''], penaltiesReceivableAccountId: [''], interestPayableAccountId: [''], + savingsInterestPaidAccountId: [''], escheatLiabilityId: [''], assetsOtherGlMappings: this.formBuilder.array([]), liabilitiesOtherGlMappings: this.formBuilder.array([]), @@ -136,6 +141,20 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { }); } + private extractNamedGlMapping( + otherGlMappings: any[], + accountName: string, + controlName: string, + options: GLAccount[] + ): any[] { + const match = (otherGlMappings || []).find((mapping) => mapping?.accountName === accountName); + if (match) { + const glAccountId = match.glAccountId || options.find((option) => option.glCode === match.glCode)?.id || ''; + this.recurringDepositProductAccountingForm.get(controlName)?.patchValue(glAccountId); + } + return (otherGlMappings || []).filter((mapping) => mapping?.accountName !== accountName); + } + private patchAccountingValues(mappings: any) { this.recurringDepositProductAccountingForm.patchValue({ savingsReferenceAccountId: mappings.savingsReferenceAccount?.id || '', @@ -158,7 +177,18 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { glMappings?.liabilities || [], this.liabilityAccountOptions ); - this.setOtherGlMappings('expensesOtherGlMappings', glMappings?.expenses || [], this.expenseAccountOptions); + const fromExpenses = this.extractNamedGlMapping( + this.extractNamedGlMapping( + glMappings?.expenses || [], + RECURRING_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME, + 'savingsInterestPaidAccountId', + this.expenseAccountOptions + ), + SAVINGS_INTEREST_PAID_ACCOUNT_NAME, + 'savingsInterestPaidAccountId', + this.expenseAccountOptions + ); + this.setOtherGlMappings('expensesOtherGlMappings', fromExpenses, this.expenseAccountOptions); this.setOtherGlMappings('incomeOtherGlMappings', glMappings?.income || [], this.incomeAccountOptions); } } @@ -224,10 +254,26 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { })) .filter((item: { accountName: string; glCode: string }) => !!item.accountName || !!item.glCode); + const namedAsOtherGlMapping = (controlName: string, accountName: string, options: GLAccount[]) => { + const glAccountId = this.recurringDepositProductAccountingForm.get(controlName)?.value; + if (!glAccountId) { + return []; + } + const glCode = options.find((o) => o.id === glAccountId)?.glCode || ''; + return glCode ? [{ accountName, glCode }] : []; + }; + const otherGlMappings = { assets: map('assetsOtherGlMappings', this.assetAccountOptions), liabilities: map('liabilitiesOtherGlMappings', this.liabilityAccountOptions), - expenses: map('expensesOtherGlMappings', this.expenseAccountOptions), + expenses: [ + ...namedAsOtherGlMapping( + 'savingsInterestPaidAccountId', + RECURRING_DEPOSIT_INTEREST_PAID_ACCOUNT_NAME, + this.expenseAccountOptions + ), + ...map('expensesOtherGlMappings', this.expenseAccountOptions) + ], income: map('incomeOtherGlMappings', this.incomeAccountOptions) }; return Object.values(otherGlMappings).some((v) => v.length) ? otherGlMappings : null; @@ -360,11 +406,18 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { rows: [ { key: 'interestOnSavingsAccountId', - label: 'Interest On Savings Account', - inputLabel: 'Interest on savings account', + label: 'Interest On Recurring Deposits', + inputLabel: 'Interest on recurring deposits', controlName: 'interestOnSavingsAccountId', options: this.expenseAccountOptions, required: true + }, + { + key: 'savingsInterestPaidAccountId', + label: 'Recurring Deposit Interest Paid', + inputLabel: 'Recurring deposit interest paid', + controlName: 'savingsInterestPaidAccountId', + options: this.expenseAccountOptions } ], otherMappingsControlName: 'expensesOtherGlMappings', @@ -405,6 +458,7 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit { liabilitiesOtherGlMappings, expensesOtherGlMappings, incomeOtherGlMappings, + savingsInterestPaidAccountId, ...accounting } = this.recurringDepositProductAccountingForm.value; const otherGlMappings = this.getOtherGlMappings();