From f0b4e98e71024383b8e97684ab03b249456a155b Mon Sep 17 00:00:00 2001 From: Sonali Likhitkar Date: Wed, 26 Aug 2026 16:27:36 +0530 Subject: [PATCH] feat(loan-products): extend loan product stepper with legacy account-type fields Add UI-only fields across the details, settings, charges, terms, and accounting steps to mirror the legacy Account Type Creation screen (classification, cheque book, interest, and additional settings). These are stripped from the create/edit payload via CUSTOM_UI_ONLY_FIELDS until a backend mechanism (e.g. a linked data table) exists to persist them. Co-Authored-By: Claude Fable 5 --- .../create-loan-product.component.html | 2 + .../create-loan-product.component.ts | 5 + .../edit-loan-product.component.html | 2 + .../edit-loan-product.component.ts | 5 + .../loan-product-accounting-step.component.ts | 106 ++- .../loan-product-charges-step.component.html | 178 +++- .../loan-product-charges-step.component.scss | 24 + .../loan-product-charges-step.component.ts | 53 +- .../loan-product-details-step.component.html | 302 ++++-- .../loan-product-details-step.component.scss | 45 +- .../loan-product-details-step.component.ts | 123 +-- .../loan-product-settings-step.component.html | 888 ++++++++++++++---- .../loan-product-settings-step.component.scss | 25 +- .../loan-product-settings-step.component.ts | 130 ++- .../loan-product-terms-step.component.html | 124 +-- .../loan-product-terms-step.component.scss | 256 +---- .../loan-product-terms-step.component.ts | 104 +- .../products/loan-products/loan-products.ts | 243 +++++ 18 files changed, 1897 insertions(+), 718 deletions(-) diff --git a/src/app/products/loan-products/create-loan-product/create-loan-product.component.html b/src/app/products/loan-products/create-loan-product/create-loan-product.component.html index 260e066d8..b4eb5fe69 100644 --- a/src/app/products/loan-products/create-loan-product/create-loan-product.component.html +++ b/src/app/products/loan-products/create-loan-product/create-loan-product.component.html @@ -26,6 +26,7 @@
@@ -51,6 +52,7 @@ diff --git a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts index 70bf6bf1f..85b3eb1b0 100644 --- a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts +++ b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts @@ -88,6 +88,7 @@ export class CreateLoanProductComponent implements OnInit { selectedTabIndex = 0; isAdvancedPaymentStrategy = false; + selectedProductSubGroup = ''; paymentAllocation: PaymentAllocation[] = []; creditAllocation: PaymentAllocation[] = []; supportedInterestRefundTypes: StringEnumOptionData[] = []; @@ -144,6 +145,10 @@ export class CreateLoanProductComponent implements OnInit { return this.loanProductTermsStep.loanProductTermsForm; } + setProductSubGroup(value: string) { + this.selectedProductSubGroup = value; + } + advancePaymentStrategy(value: string) { this.isAdvancedPaymentStrategy = LoanProducts.isAdvancedPaymentAllocationStrategy(value); if (this.isAdvancedPaymentStrategy) { diff --git a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html index 8e2da682b..5bc35069e 100644 --- a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html +++ b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html @@ -39,6 +39,7 @@ @@ -56,6 +57,7 @@ diff --git a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts index b5fb93f9b..b4569cf8e 100644 --- a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts +++ b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts @@ -95,6 +95,7 @@ export class EditLoanProductComponent implements OnInit { itemsByDefault: GlobalConfiguration[] = []; isAdvancedPaymentStrategy = false; + selectedProductSubGroup = ''; wasPaymentAllocationChanged = false; paymentAllocation: PaymentAllocation[] = []; creditAllocation: CreditAllocation[] = []; @@ -218,6 +219,10 @@ export class EditLoanProductComponent implements OnInit { this.isAdvancedPaymentStrategy = LoanProducts.isAdvancedPaymentAllocationStrategy(value); } + setProductSubGroup(value: string): void { + this.selectedProductSubGroup = value; + } + buildAdvancedPaymentAllocation(): void { this.advancedPaymentAllocations = this.advancedPaymentStrategy.buildAdvancedPaymentAllocationList( this.loanProductAndTemplate diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-accounting-step/loan-product-accounting-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-accounting-step/loan-product-accounting-step.component.ts index 4b3880fd6..95fb2c7e6 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-accounting-step/loan-product-accounting-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-accounting-step/loan-product-accounting-step.component.ts @@ -210,7 +210,14 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { intOverdueReserveAccountId: accountingMappings.intOverdueReserveAccount?.id || '', undebitedInterestAccountId: accountingMappings.undebitedInterestAccount?.id || '', penalIntCrGlAccountId: accountingMappings.penalIntCrGlAccount?.id || '', - rdMaturedGlAccountId: accountingMappings.rdMaturedGlAccount?.id || '' + rdMaturedGlAccountId: accountingMappings.rdMaturedGlAccount?.id || '', + glAccountId: accountingMappings.glAccount?.id || '', + icChargeGlAccountId: accountingMappings.icChargeGlAccount?.id || '', + inoperativeGlAccountId: accountingMappings.inoperativeGlAccount?.id || '', + creditBalanceLiabilityGlAccountId: accountingMappings.creditBalanceLiabilityGlAccount?.id || '', + creditBalanceAssetGlAccountId: accountingMappings.creditBalanceAssetGlAccount?.id || '', + overdueAccountsGlAccountId: accountingMappings.overdueAccountsGlAccount?.id || '', + rebateGlAccountId: accountingMappings.rebateGlAccount?.id || '' }); if (this.loanProductsTemplate.paymentChannelToFundSourceMappings) { @@ -281,11 +288,8 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { 'receivablePenaltyAccountId', 'intReceivablesGlAccountId', 'intPayableGlAccountId', - 'deafIntPayableGlAccountId', - 'intOverdueReserveAccountId', - 'undebitedInterestAccountId', - 'penalIntCrGlAccountId', - 'rdMaturedGlAccountId' + 'glAccountId', + 'inoperativeGlAccountId' ]; commonFields.forEach((field) => { if (!this.loanProductAccountingForm.contains(field)) { @@ -293,6 +297,26 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { } }); + // Optional custom GL account fields (legacy screenshot fields not marked mandatory) — + // no Validators.required, so mat-form-field does not render a required asterisk for these. + const optionalCommonFields = [ + 'deafIntPayableGlAccountId', + 'intOverdueReserveAccountId', + 'undebitedInterestAccountId', + 'penalIntCrGlAccountId', + 'rdMaturedGlAccountId', + 'icChargeGlAccountId', + 'creditBalanceLiabilityGlAccountId', + 'creditBalanceAssetGlAccountId', + 'overdueAccountsGlAccountId', + 'rebateGlAccountId' + ]; + optionalCommonFields.forEach((field) => { + if (!this.loanProductAccountingForm.contains(field)) { + this.loanProductAccountingForm.addControl(field, new UntypedFormControl('')); + } + }); + if (!this.loanProductAccountingForm.contains('advancedAccountingRules')) { this.loanProductAccountingForm.addControl('advancedAccountingRules', new UntypedFormControl(false)); } @@ -708,15 +732,15 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { { key: 'intReceivablesGlAccountId', label: 'Int. Receivables GL A/c', - inputLabel: 'Int. Receivables GL A/c', + inputLabel: 'Int Receivables GL A/c', controlName: 'intReceivablesGlAccountId', options: this.assetAccountData, - required: false + required: true }, { key: 'deafIntPayableGlAccountId', label: 'Deaf Int. Payble GL A/c', - inputLabel: 'Deaf Int. Payble GL A/c', + inputLabel: 'Deaf Int Payble GL A/c', controlName: 'deafIntPayableGlAccountId', options: this.assetAccountData, required: false @@ -724,7 +748,7 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { { key: 'intOverdueReserveAccountId', label: 'Int. Overdue Reserve A/c (AS)', - inputLabel: 'Int. Overdue Reserve A/c', + inputLabel: 'Int Overdue Reserve A/c', controlName: 'intOverdueReserveAccountId', options: this.assetAccountData, required: false @@ -736,6 +760,38 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { controlName: 'rdMaturedGlAccountId', options: this.assetAccountData, required: false + }, + { + key: 'glAccountId', + label: 'GL A/c No.', + inputLabel: 'GL A/c No', + controlName: 'glAccountId', + options: this.assetAccountData, + required: true + }, + { + key: 'inoperativeGlAccountId', + label: 'InOperative GL A/c', + inputLabel: 'InOperative GL A/c', + controlName: 'inoperativeGlAccountId', + options: this.assetAccountData, + required: true + }, + { + key: 'creditBalanceAssetGlAccountId', + label: 'Cr.Balance Asset GL A/c', + inputLabel: 'Cr Balance Asset GL A/c', + controlName: 'creditBalanceAssetGlAccountId', + options: this.assetAccountData, + required: false + }, + { + key: 'overdueAccountsGlAccountId', + label: 'Overdue Accounts GL A/c No.', + inputLabel: 'Overdue Accounts GL A/c No', + controlName: 'overdueAccountsGlAccountId', + options: this.assetAccountData, + required: false } ], otherMappingsControlName: 'assetsOtherGlMappings', @@ -848,10 +904,18 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { { key: 'penalIntCrGlAccountId', label: 'Penal Int. Cr. GL A/c', - inputLabel: 'Penal Int. Cr. GL A/c', + inputLabel: 'Penal Int Cr GL A/c', controlName: 'penalIntCrGlAccountId', options: this.incomeAccountData, required: false + }, + { + key: 'icChargeGlAccountId', + label: 'I.C. Charge GL A/c No.', + inputLabel: 'IC Charge GL A/c No', + controlName: 'icChargeGlAccountId', + options: this.incomeAccountData, + required: false } ], otherMappingsControlName: 'incomeOtherGlMappings', @@ -903,6 +967,14 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { options: this.expenseAccountData, required: true, deferredBuyDownMerchantOnly: true + }, + { + key: 'rebateGlAccountId', + label: 'Rebate GL A/c No.', + inputLabel: 'Rebate GL A/c No', + controlName: 'rebateGlAccountId', + options: this.expenseAccountData, + required: false } ], otherMappingsControlName: 'expensesOtherGlMappings', @@ -934,10 +1006,10 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { { key: 'intPayableGlAccountId', label: 'Int. Payable GL A/c', - inputLabel: 'Int. Payable GL A/c', + inputLabel: 'Int Payable GL A/c', controlName: 'intPayableGlAccountId', options: this.liabilityAccountData, - required: false + required: true }, { key: 'undebitedInterestAccountId', @@ -946,6 +1018,14 @@ export class LoanProductAccountingStepComponent implements OnInit, OnChanges { controlName: 'undebitedInterestAccountId', options: this.liabilityAccountData, required: false + }, + { + key: 'creditBalanceLiabilityGlAccountId', + label: 'Cr.Balance Liability GL A/c', + inputLabel: 'Cr Balance Liability GL A/c', + controlName: 'creditBalanceLiabilityGlAccountId', + options: this.liabilityAccountData, + required: false } ], otherMappingsControlName: 'liabilitiesOtherGlMappings', diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.html index ec1e817bf..0b193fefc 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.html @@ -6,7 +6,11 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - +
@@ -171,3 +174,174 @@ }
+--> + + +
+
+
+ +

Cheque & Standing Instruction Charges

+
+
+ + Chq. Book Charge + + YES + NO + + + + + Chq. Return Charge + + YES + NO + + + + + I.C. Charge Debit + + YES + NO + + + + + Cash Bundle Charge + + YES + NO + + + + + Cash Bundle Charge With PAN Limit + + + + + Per Cheque Entry Charge + + + + + Per Cheque Entry Service Charge + + + + + Per Inward Cheque Entry Charge + + + + + Per Outward Cheque Entry Charge + + + + + Creditor Standing Instr. Fail Charge + + + + + Debtor Standing Instr. Fail Charge + + + + + Calculate Daily Against Clearing Charge + + YES + NO + + +
+
+ +
+
+ +

Minimum Balance Charges

+
+
+ + Minimum Balance Checking + + Strict + Average + Lenient + + + + + Auto Minimum Balance Charge + + YES + NO + + + + + Calculate Daily Min. Balance Charges + + YES + NO + + + + + Minimum Balance Charge + + YES + NO + + + + + Min. Balance Charge (Rs.) + + + + + Min. Balance Charge For Cheque Issue (Rs.) + + + + + Min. Balance Charge Method + + Flat + Slab + + + + + Months After Min. Balance Charge Calculate + + + + + For Cheque Issue + + + + + For Cheque Issue (Avg.) + + + + + For Withdrawal Slip + + + + + For Withdrawal Slip (Avg.) + + +
+
+
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.scss index d40566222..b80a406a8 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.scss @@ -88,3 +88,27 @@ $gray-900: #202124; .lpch-table { width: 100%; } + +.lpch-section__body { + display: grid; + grid-template-columns: repeat(2, 1fr); + align-items: start; + gap: 18px 16px; + padding: 20px 24px; + + @media (width <= 600px) { + grid-template-columns: 1fr; + } +} + +.lpch-section__body.lpch-grid-4 { + grid-template-columns: repeat(4, 1fr); + + @media (width <= 1100px) { + grid-template-columns: repeat(2, 1fr); + } + + @media (width <= 600px) { + grid-template-columns: 1fr; + } +} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.ts index f914bb42c..09e230b43 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-charges-step/loan-product-charges-step.component.ts @@ -7,7 +7,7 @@ */ import { Component, Input, OnInit, inject } from '@angular/core'; -import { UntypedFormControl } from '@angular/forms'; +import { UntypedFormControl, UntypedFormBuilder, UntypedFormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { TranslateService } from '@ngx-translate/core'; @@ -51,12 +51,16 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatRow, ChargesFilterPipe, ChargesPenaltyFilterPipe, - FormatNumberPipe + FormatNumberPipe, + ReactiveFormsModule ] }) export class LoanProductChargesStepComponent implements OnInit { dialog = inject(MatDialog); private translateService = inject(TranslateService); + private formBuilder = inject(UntypedFormBuilder); + + legacyChargesForm: UntypedFormGroup; @Input() loanProductsTemplate: any; @Input() currencyCode: UntypedFormControl; @@ -76,6 +80,48 @@ export class LoanProductChargesStepComponent implements OnInit { pristine = true; + constructor() { + this.createLegacyChargesForm(); + } + + createLegacyChargesForm() { + this.legacyChargesForm = this.formBuilder.group({ + // Cheque-related charges (legacy "A/c Mas Scr2 Para") + chequeBookChargeEnabled: ['NO'], + chequeReturnChargeEnabled: ['NO'], + icChargeDebitEnabled: ['NO'], + cashBundleChargeEnabled: ['NO'], + cashBundleChargeWithPanLimit: [''], + + // Cheque transaction charges (legacy Page 4) + perChequeEntryCharge: [''], + perChequeEntryServiceCharge: [''], + perInwardChequeEntryCharge: [''], + perOutwardChequeEntryCharge: [''], + + // Standing Instruction fail charges (legacy Page 4) + creditorStandingInstructionFailCharge: [''], + debtorStandingInstructionFailCharge: [''], + + // Minimum Balance Information (legacy Page 2 + Page 4) + minimumBalanceCheckingType: [''], + autoMinimumBalanceCharge: [''], + calculateDailyMinimumBalanceCharges: ['NO'], + minimumBalanceChargeEnabled: ['NO'], + minimumBalanceChargeAmount: [''], + minimumBalanceChargeForChequeIssue: [''], + minimumBalanceChargeMethod: [''], + monthsAfterMinBalanceChargeCalculate: [''], + forChequeIssue: [''], + forChequeIssueAvg: [''], + forWithdrawalSlip: [''], + forWithdrawalSlipAvg: [''], + + // Against Clearing charge (legacy Page 4) + calculateDailyAgainstClearingCharge: ['NO'] + }); + } + ngOnInit() { this.chargeData = this.loanProductsTemplate.chargeOptions; this.overdueChargeData = this.loanProductsTemplate.penaltyOptions @@ -112,7 +158,8 @@ export class LoanProductChargesStepComponent implements OnInit { get loanProductCharges() { return { - charges: this.chargesDataSource + charges: this.chargesDataSource, + ...this.legacyChargesForm.value }; } } diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.html index 49df9f6d2..30a298473 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.html @@ -7,40 +7,144 @@ -->
+
-

{{ 'labels.inputs.Product Name' | translate }} & {{ 'labels.inputs.Description' | translate }}

+

General Information

-
- - {{ 'labels.inputs.Product Name' | translate }} - - - {{ 'labels.inputs.Product Name' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - +
+
+ + Account Type Group + + @for (group of productTypeGroups; track group.id) { + {{ group.label }} + } + + - - {{ 'labels.inputs.Short Name' | translate }} - - - {{ 'labels.inputs.Short Name' | translate }} {{ 'labels.commons.is' | translate }} - {{ 'labels.commons.required' | translate }} - - + @if (availableSubGroups.length) { + + Product Type Sub Group + + @for (subGroup of availableSubGroups; track subGroup.id) { + {{ subGroup.label }} + } + + + } + + + A/c. Type Description + + + {{ 'labels.inputs.Product Name' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + + + + {{ 'labels.inputs.Short Name' | translate }} + + + {{ 'labels.inputs.Short Name' | translate }} {{ 'labels.commons.is' | translate }} + {{ 'labels.commons.required' | translate }} + + + + + A/c Type Code + + + + + MICR Trn. Code + + + + + Reserved Code Srno For ECS + + + + + Reverse ECS No. + + +
+ +
+ + Lock Cheque Info + + YES + NO + + + + + Lock Page 2 Info + + YES + NO + + + + + Computerization Date + + + + + + + PFMS Account Type + + + + + Chq. Print Description + + + + + POS A/c Type Description + + + + + Renewal Dt. Add Months + + + + + Renewal Grace Days + + + + + Doc. Renewal Dt. Add Months + + +
@@ -97,86 +201,94 @@

Interest Information

-
- - Debit Int. Calculation - - @for (opt of yesNoOptions; track opt.value) { - {{ opt.label }} - } - - - - - Separate Penal Int. - - @for (opt of yesNoOptions; track opt.value) { - {{ opt.label }} - } - - - - - Credit Int. Calculation - - @for (opt of yesNoOptions; track opt.value) { - {{ opt.label }} - } - - - - - Sub A/c Type Balance - - @for (opt of yesNoOptions; track opt.value) { - {{ opt.label }} - } - - - - - Final Int. Rounding - - @for (opt of yesNoOptions; track opt.value) { - {{ opt.label }} - } - - - - @if (loanProductDetailsForm.get('finalIntRounding')?.value) { +
+
- Rounding UpTo - + Debit Int. Calculation + + @for (opt of yesNoOptions; track opt.value) { + {{ opt.label }} + } + - } + + + Separate Penal Int. + + @for (opt of yesNoOptions; track opt.value) { + {{ opt.label }} + } + + + + + Final Int. Rounding + + @for (opt of yesNoOptions; track opt.value) { + {{ opt.label }} + } + + + + @if (loanProductDetailsForm.get('finalIntRounding')?.value) { + + Rounding UpTo + + + } +
+ +
+ + Credit Int. Calculation + + @for (opt of yesNoOptions; track opt.value) { + {{ opt.label }} + } + + + + + Sub A/c Type Balance + + @for (opt of yesNoOptions; track opt.value) { + {{ opt.label }} + } + + +
+
+
+ + GL Account mappings for these fields (Int. Receivables, Penal Int. Cr., RD Matured, Int. Payable, Deaf Int. + Payable, Int. Overdue Reserve, UnDebited Interest) are available in the Accounting tab.
- +
- -

Product Classification

+ +

PPS Limit & Write Off Details

- Product Type Group - - @for (group of productTypeGroups; track group.id) { - {{ group.label }} - } + PPS Limit + + + + + Is this Actyp Write Off? + + YES + NO - @if (loanProductDetailsForm.get('productTypeGroup')?.value) { + @if (loanProductDetailsForm.get('isWriteOffAccountType')?.value === 'YES') { - GL Account ({{ glClassificationLabel }}) - - @for (acc of availableGlAccounts; track acc.id) { - ({{ acc.glCode }}) {{ acc.name }} - } - - GL Account is required + Write Off Actyp + }
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.scss index f6a3f62d5..f6032818a 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.scss @@ -46,9 +46,10 @@ $gray-900: #202124; .lpd-grid { display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px 16px; - padding: 16px 24px; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + align-items: start; + gap: 18px 16px; + padding: 20px 24px; @media (width <= 600px) { grid-template-columns: 1fr; @@ -57,6 +58,7 @@ $gray-900: #202124; .lpd-field { width: 100%; + min-width: 0; &--full { grid-column: 1 / -1; @@ -69,6 +71,43 @@ $gray-900: #202124; padding: 4px 0; } +// Two independent vertical columns of fields, side by side +.lpd-two-col { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4px 40px; + padding: 20px 24px; + align-items: start; + + @media (width <= 700px) { + grid-template-columns: 1fr; + } + + &__column { + display: flex; + flex-direction: column; + } +} + +.lpd-info-note { + display: flex; + align-items: flex-start; + gap: 8px; + margin: 0 24px 16px; + padding: 10px 14px; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 8px; + font-size: 12.5px; + color: #1e3a8a; + line-height: 1.5; + + i { + color: #2563eb; + margin-top: 2px; + } +} + // GL Section .lpd-gl-section { border-top: 2px solid #e0f2fe; diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.ts index ded56834c..be0a33192 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-details-step/loan-product-details-step.component.ts @@ -7,7 +7,7 @@ */ /** Angular Imports */ -import { Component, OnInit, Input, inject } from '@angular/core'; +import { Component, OnInit, Input, Output, EventEmitter, inject } from '@angular/core'; import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { Dates } from 'app/core/utils/dates'; @@ -33,6 +33,7 @@ export class LoanProductDetailsStepComponent implements OnInit { private settingsService = inject(SettingsService); @Input() loanProductsTemplate: any; + @Output() productSubGroupChange = new EventEmitter(); loanProductDetailsForm: UntypedFormGroup; @@ -49,6 +50,10 @@ export class LoanProductDetailsStepComponent implements OnInit { this.createLoanProductDetailsForm(); } + assetAccountOptions: any[] = []; + incomeAccountOptions: any[] = []; + liabilityAccountOptions: any[] = []; + ngOnInit() { this.loanProductDetailsForm.patchValue({ name: this.loanProductsTemplate.name, @@ -58,10 +63,6 @@ export class LoanProductDetailsStepComponent implements OnInit { closeDate: this.loanProductsTemplate.closeDate && new Date(this.loanProductsTemplate.closeDate) }); - const mappingOptions = this.loanProductsTemplate?.accountingMappingOptions ?? {}; - this.assetAccountOptions = mappingOptions.assetAccountOptions ?? []; - this.liabilityAccountOptions = mappingOptions.liabilityAccountOptions ?? []; - this.loanProductDetailsForm.patchValue({ debitIntCalculation: this.loanProductsTemplate.debitIntCalculation ?? false, separatePenalInterest: this.loanProductsTemplate.separatePenalInterest ?? false, @@ -70,66 +71,59 @@ export class LoanProductDetailsStepComponent implements OnInit { finalIntRounding: this.loanProductsTemplate.finalIntRounding ?? false, roundingUpTo: this.loanProductsTemplate.roundingUpTo ?? null }); + + const mappingOptions = this.loanProductsTemplate?.accountingMappingOptions ?? {}; + this.assetAccountOptions = mappingOptions.assetAccountOptions ?? []; + this.incomeAccountOptions = mappingOptions.incomeAccountOptions ?? []; + this.liabilityAccountOptions = mappingOptions.liabilityAccountOptions ?? []; + + const accountingMappings = this.loanProductsTemplate?.accountingMappings; + if (accountingMappings) { + this.loanProductDetailsForm.patchValue({ + intReceivablesGlAccountId: accountingMappings.intReceivablesGlAccount?.id || '', + penalIntCrGlAccountId: accountingMappings.penalIntCrGlAccount?.id || '', + rdMaturedGlAccountId: accountingMappings.rdMaturedGlAccount?.id || '', + intPayableGlAccountId: accountingMappings.intPayableGlAccount?.id || '', + deafIntPayableGlAccountId: accountingMappings.deafIntPayableGlAccount?.id || '', + intOverdueReserveAccountId: accountingMappings.intOverdueReserveAccount?.id || '', + undebitedInterestAccountId: accountingMappings.undebitedInterestAccount?.id || '' + }); + } } /** Product Classification data */ readonly productTypeGroups = [ - { id: 'loans', label: 'Loan' }, - { id: 'advanced', label: 'Advanced' } + { id: 'advances', label: 'Advances A/C' }, + { id: 'loans', label: 'Loans A/C' } ]; readonly productTypeSubGroups: Record = { - loans: [ - { id: 'emi', label: 'EMI' }, - { id: 'cc', label: 'CC (Cash Credit)' }, - { id: 'overdraft', label: 'Overdraft' }, - { id: 'warehouse', label: 'Warehouse' }, - { id: 'gold', label: 'Gold' } + // Renewable, Drawing-Power/limit-based revolving credit facilities + advances: [ + { id: 'cc', label: 'Cash Credit (CC)' }, + { id: 'overdraft', label: 'Overdraft (OD)' }, + { id: 'gold', label: 'Gold Loan' }, + { id: 'warehouse', label: 'Warehouse Receipt / Pledge Loan' }, + { id: 'kcc', label: 'Kisan Credit Card (KCC)' }, + { id: 'bills', label: 'Bills Purchased / Discounted' } ], - advanced: [ - { id: 'fd', label: 'FD (Fixed Deposit)' }, - { id: 'rd', label: 'RD (Recurring Deposit)' } + // Fixed disbursement, fixed tenure, EMI-based term credit facilities + loans: [ + { id: 'term', label: 'Term Loan / Long Term Loan' }, + { id: 'personal', label: 'Personal Loan' }, + { id: 'housing', label: 'Housing Loan' }, + { id: 'vehicle', label: 'Vehicle Loan' }, + { id: 'education', label: 'Education Loan' }, + { id: 'business', label: 'Business / MSME Term Loan' }, + { id: 'gold_emi', label: 'Gold EMI Loan' } ] }; - /** Default GL per product type group */ - private readonly glDefaultMap: Record = { - loans: 'asset', - advanced: 'asset' - }; - get availableSubGroups() { const group = this.loanProductDetailsForm.get('productTypeGroup')?.value; return group ? (this.productTypeSubGroups[group] ?? []) : []; } - get glOptions(): string[] { - return [ - 'asset', - 'liability' - ]; - } - - assetAccountOptions: any[] = []; - liabilityAccountOptions: any[] = []; - - get availableGlAccounts(): any[] { - const type = this.loanProductDetailsForm.get('glClassification')?.value; - if (type === 'asset') return this.assetAccountOptions; - if (type === 'liability') return this.liabilityAccountOptions; - return []; - } - - get glClassificationLabel(): string { - const type = this.loanProductDetailsForm.get('glClassification')?.value; - return type === 'liability' ? 'Liability' : 'Asset'; - } - - get selectedGroupLabel(): string { - const group = this.loanProductDetailsForm.get('productTypeGroup')?.value; - return this.productTypeGroups.find((g) => g.id === group)?.label ?? ''; - } - readonly yesNoOptions = [ { value: true, label: 'YES' }, { value: false, label: 'NO' } @@ -150,21 +144,36 @@ export class LoanProductDetailsStepComponent implements OnInit { closeDate: [''], productTypeGroup: [''], productTypeSubGroup: [''], - glClassification: ['asset'], - glAccount: [''], debitIntCalculation: [false], separatePenalInterest: [false], creditIntCalculation: [false], subAccountTypeBalance: [false], finalIntRounding: [false], - roundingUpTo: [null] + roundingUpTo: [null], + + // General Information (legacy Page 1 header fields) + accountTypeCode: [''], + micrTransactionCode: [''], + reservedEcsSerialNumber: [''], + reverseEcsNumber: [''], + lockChequeInfoEnabled: ['NO'], + lockPageTwoInfoEnabled: ['NO'], + computerizationDate: [''], + chequePrintDescription: [''], + posAccountTypeDescription: [''], + pfmsAccountType: [''], + renewalDateAddMonths: [''], + renewalGraceDays: [''], + documentRenewalDateAddMonths: [''], + + // PPS Limit & Write Off Details + ppsLimit: [''], + isWriteOffAccountType: ['NO'], + writeOffAccountTypeCode: [''] }); - // Auto-set GL based on product type group - this.loanProductDetailsForm.get('productTypeGroup')?.valueChanges.subscribe((group: string) => { - const defaultVal = this.glDefaultMap[group] ?? 'asset'; - this.loanProductDetailsForm.get('glClassification')?.setValue(defaultVal); - this.loanProductDetailsForm.get('glAccount')?.setValue(''); + this.loanProductDetailsForm.get('productTypeSubGroup')?.valueChanges.subscribe((subGroup: string) => { + this.productSubGroupChange.emit(subGroup); }); } diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html index 5853a8895..74a9d2b63 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.html @@ -235,209 +235,361 @@
- -
-
- -

Cheque Book Settings

-
-
- - Cheque Book Issue Enabled - - YES - NO - - + + @if (showChequeBookSettings) { + + + + + Cheque Book Settings + + +
+ + Cheque Book Issue Enabled + + YES + NO + + - - Cheque Validation Required - - YES - NO - - + + Cheque Validation Required + + YES + NO + + - - Is First Cheque Book Free - - YES - NO - - + + Is First Cheque Book Free + + YES + NO + + - - Cheque Printing Account Type - - Savings Bank - Current Account - Cash Credit - Overdraft - - + + Cheque Printing Account Type + + Savings Bank + Current Account + Cash Credit + Overdraft + + - - Allow Withdrawal Slip Usage - - YES - NO - - + + Allow Withdrawal Slip Usage + + YES + NO + + - - Maintain Cheque Book Stock Registry - - YES - NO - - + + Maintain Cheque Book Stock Registry + + YES + NO + + - - Free Cheque Books Per Year - - + + Free Cheque Books Per Year + + - - Allow Credit By Cheque Number - - YES - NO - - + + Allow Credit By Cheque Number + + YES + NO + + - - Credit Cheque Validation Required - - YES - NO - - + + Credit Cheque Validation Required + + YES + NO + + - - Grace Days For Stock Statement - - -
-
+ + Grace Days For Stock Statement + + +
+ + } - -
-
- -

Additional Product Settings

-
-
- - Account Type Active For Transactions - - YES - NO - - + + + + + Additional Product Settings + + +
+ + Account Type Active For Transactions + + YES + NO + + - - Sub Type Activity Enabled - - YES - NO - - + + Sub Type Activity Enabled + + YES + NO + + - - Account Opening Charges - - + + Account Opening Charges + + - - Maximum Gold Loan Limit - - + + Maximum Gold Loan Limit + + - - Last Account Number Opened - - + + Gold Loan [Packet No.] With Year? + + YES + NO + + - - Customer Termination Allowed - - YES - NO - - + + Last Account Number Opened + + - - Charges For Cash Credit Above Limit - - + + Customer Termination Allowed + + YES + NO + + - - Death Interest GL Account - - + + Charges For Cash Credit Above Limit + + - - Starting Ledger Number - - + + Death Interest GL Account + + - - Ending Ledger Number - - + + Starting Ledger Number + + - - Current Ledger Number - - + + Ending Ledger Number + + - - Remittance Account Number - - + + Current Ledger Number + + - - Is Non Resident Indian Account - - YES - NO - - + + Remittance Account Number + + - - Debit Clearing GL Account - - + + Is Non Resident Indian Account + + YES + NO + + - - Missed Call Alert Service Active - - YES - NO - - + + Debit Clearing GL Account + + - - Standing Instruction Charge GL Account - - + + Missed Call Alert Service Active + + YES + NO + + - - Standing Instruction Debit Charge Skip Option - - Skip Always - Skip on First Failure - Never Skip - Retry after 24 Hours - - + + Standing Instruction Charge GL Account + + - - Opening Balance Multiplier For Remittance Charges - - -
-
+ + Standing Instruction Debit Charge Skip Option + + Skip Always + Skip on First Failure + Never Skip + Retry after 24 Hours + + + + + Opening Balance Multiplier For Remittance Charges + + + + + A/c Move To InOperative A/c + + YES + NO + + + + + Generate GL Diff Entry + + YES + NO + + + + + Sub Type Wise GL Balance Gen + + YES + NO + + + + + Want To Validation While Deleting Debit Entry + + YES + NO + + + + + Want To RC File Concept + + YES + NO + + + + + A/c Close With Zero Bal. In Open Day Process + + YES + NO + + + + + A/c Close When Bal. Zero At Subled Tran Entry + + YES + NO + + + + + Lmt.Enh/Ag.Clg Screen Display + + YES + NO + + + + + Advance Int. Param In Ledger + + YES + NO + + + + + Vehicle Detail In Master + + YES + NO + + + + + Deleted Chq. Issue + + YES + NO + + + + + DP Reduce In Doc. Renewal Date + + YES + NO + + + + + DP Reduce In Renewal Date + + YES + NO + + + + + Auto Close Day-End + + YES + NO + + + + + Loan Rate From Master + + YES + NO + + + + + Cheque Short Name + + + + + Statement Print + + YES + NO + + + + + NESL Code + + +
+ +
@@ -754,6 +906,85 @@ Add Penal Interest Rate + + + Atyp14 Simple Int. + + YES + NO + + + + + FDOD Margin Type + + + + + Check Master Detail Edited (Passing Pend.) + + YES + NO + + + + + Credit/Debit Int. Calc. Separate + + YES + NO + + + + + On Time Interest Provision + + YES + NO + + + + + Check Against Clearing + + YES + NO + + + + + GST On Penalty + + YES + NO + + + + + Penalty Int. Grace Days + + + + + Over Drawn Int. Rate + + + + + Calculate Daily Limit Enhancement (TOD) + + YES + NO + + + + + FDOD Multiple Int. Rate + + YES + NO + +
@@ -801,6 +1032,306 @@ + + @if (showChannelLimits) { + + + + + Channel & Transaction Limits + + +
+ + Is Mobile App? + + YES + NO + + + + + Is ATM? + + YES + NO + + + + @if (loanProductSettingsForm.value.isAtmEnabled === 'YES') { + + ATM Yearly Charge? + + YES + NO + + + + + ATM Min. Balance + + + } + + + Email Active? + + YES + NO + + + + + Is IMPS? + + YES + NO + + + + + Is UPI? + + YES + NO + + + + + Is POS? + + YES + NO + + + + + Is BBPS? + + YES + NO + + + + + Inter Bank Limit (Per Day) + + + + + Inter Bank Limit (Per Transaction) + + + + + NEFT/RTGS Limit (Per Day) + + + + + NEFT/RTGS Limit (Per Transaction) + + + + + NEFT Cutoff Limit + + + + + RTGS Cutoff Limit + + + + + NEFT/RTGS Min. Balance + + + + + Is Charge Req. NEFT/RTGS (CBS)? + + YES + NO + + + + + Is Charge Req. NEFT/RTGS (Mobile)? + + YES + NO + + + + @if (loanProductSettingsForm.value.isImpsEnabled === 'YES') { + + IMPS Limit (Per Day) + + + + + IMPS Limit (Per Transaction) + + + + + IMPS Limit (Per Month) + + + + + IMPS Min. Limit + + + + + IMPS Monthly Transaction Count + + + } +
+
+ } + + @if ( + showChannelLimits && + (loanProductSettingsForm.value.isPosEnabled === 'YES' || loanProductSettingsForm.value.isAtmEnabled === 'YES') + ) { + + + + + POS Facility & ATM CSV Settings + + +
+ + Max Per Transaction Limit (ATM) + + + + + Max Day Transaction Limit (ATM) + + + + + Max Per Transaction Limit (POS) + + + + + Max Day Transaction Limit (POS) + + + + + Max Per Transaction Limit (ECOM) + + + + + Max Day Transaction Limit (ECOM) + + + + + Max Per Transaction Limit (UPI) + + + + + Max Day Transaction Limit (UPI) + + + + + ATM CSV Product Code + + + + + ATM CSV Type Code + + +
+
+ } + + + + + + Auto Interest Post Parameters + + +
+ + Auto Int. Post Type + + Monthly + Quarterly + Half Yearly + Yearly + + + + + Auto Int. Post When + + Month End + Fix Day + + + + @if (loanProductSettingsForm.value.autoInterestPostWhen === 'FIX_DAY') { + + Fix Day + + + } + + + Auto Last Int. Date + + +
+
+ + @if (showForeclosureSettings) { + + + + + Foreclosure / Early Account Closure + + +
+ + Calculate Early A/c Close Charge? + + YES + NO + + + + @if (loanProductSettingsForm.value.calculateEarlyAccountCloseCharge === 'YES') { + + Early A/c Close Charge + + + + + Early A/c Close Period (In Months) + + + } +
+
+ } +
+
@@ -883,6 +1414,11 @@ + + Grace Days After Overdue For Moratorium A/c + + + {{ 'labels.inputs.Delinquency Bucket' | translate }} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.scss index 50934aecc..6390274af 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.scss @@ -50,8 +50,9 @@ &__body { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 4px 16px; - padding: 16px 24px; + align-items: start; + gap: 18px 16px; + padding: 20px 24px; @media (width <= 600px) { grid-template-columns: 1fr; @@ -83,6 +84,26 @@ grid-column: span 3; } +.lps-narrow { + max-width: 160px; +} + +.lps-accordion { + margin-top: 16px; + + .lps-section__body { + padding: 16px 24px 20px; + } + + mat-panel-title { + display: flex; + align-items: center; + gap: 10px; + font-size: 14px; + font-weight: 600; + } +} + .lps-checkbox-row { display: flex; align-items: center; diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts index d230afc79..da9fee4c7 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-settings-step/loan-product-settings-step.component.ts @@ -21,6 +21,12 @@ import { ProcessingStrategyService } from '../../services/processing-strategy.se import { MatTooltip } from '@angular/material/tooltip'; import { MatCheckbox } from '@angular/material/checkbox'; import { MatIconButton } from '@angular/material/button'; +import { + MatAccordion, + MatExpansionPanel, + MatExpansionPanelHeader, + MatExpansionPanelTitle +} from '@angular/material/expansion'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; @@ -34,6 +40,10 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; MatTooltip, MatCheckbox, MatIconButton, + MatAccordion, + MatExpansionPanel, + MatExpansionPanelHeader, + MatExpansionPanelTitle, FaIconComponent, ReactiveFormsModule ] @@ -45,8 +55,41 @@ export class LoanProductSettingsStepComponent implements OnInit { @Input() toEdit: boolean; @Input() loanProductsTemplate: any; @Input() isLinkedToFloatingInterestRates: UntypedFormControl; + @Input() productSubGroup: string; @Output() advancePaymentStrategy = new EventEmitter(); + /** Sub-groups (from Details step) that are current-account-linked, channel-heavy products */ + readonly channelEnabledSubGroups = [ + 'cc', + 'overdraft' + ]; + + /** Sub-groups that are fixed-tenure, EMI-based term loans (foreclosure applies to these) */ + readonly termLoanSubGroups = [ + 'term', + 'personal', + 'housing', + 'vehicle', + 'education', + 'business', + 'gold_emi' + ]; + + get showChannelLimits(): boolean { + return !this.productSubGroup || this.channelEnabledSubGroups.includes(this.productSubGroup); + } + + get showChequeBookSettings(): boolean { + return !this.productSubGroup || ![ + 'gold', + 'gold_emi' + ].includes(this.productSubGroup); + } + + get showForeclosureSettings(): boolean { + return !this.productSubGroup || this.termLoanSubGroups.includes(this.productSubGroup); + } + loanProductSettingsForm: UntypedFormGroup; amortizationTypeData: any; @@ -366,6 +409,24 @@ export class LoanProductSettingsStepComponent implements OnInit { standingInstructionChargeGLAccount: [''], standingInstructionDebitChargeSkipOption: [''], openingBalanceMultiplierForRemittanceCharges: [''], + accountMoveToInoperativeEnabled: ['NO'], + generateGlDiffEntryEnabled: ['NO'], + subTypeWiseGlBalanceGenerationEnabled: ['NO'], + validateBeforeDeletingDebitEntryEnabled: ['NO'], + rcFileConceptEnabled: ['NO'], + accountCloseZeroBalanceInOpenDayProcess: ['NO'], + accountCloseZeroBalanceAtSubledgerTranEntry: ['NO'], + limitEnhancementAgainstClearingScreenDisplayEnabled: ['NO'], + advanceInterestParameterInLedgerEnabled: ['NO'], + vehicleDetailInMasterEnabled: ['NO'], + deletedChequeIssueEnabled: ['NO'], + dpReduceInDocumentRenewalDateEnabled: ['NO'], + dpReduceInRenewalDateEnabled: ['NO'], + autoCloseAtDayEndEnabled: ['NO'], + loanRateFromMasterEnabled: ['NO'], + chequeShortName: [''], + statementPrintEnabled: ['YES'], + neslCode: [''], // Interest Related Parameters drawingPowerAndLimitGenerationProcedure: ['NORMAL D.P. ENTRY IS CONSIDER'], @@ -385,7 +446,7 @@ export class LoanProductSettingsStepComponent implements OnInit { penaltyInterestDateDifferentThanRegularInterest: ['YES'], fixedDepositOverdraftCertificateSortOrder: ['ORDER ON INTEREST RATE'], useDocumentSubmissionDateForInterest: ['NO'], - loanManagementSystemRenewalPenaltyActive: [''], + loanManagementSystemRenewalPenaltyActive: ['NO'], minimumNormalInterestAmount: [''], minimumInterestCalculationMethod: [''], minimumAgainstClearingInterestAmount: [''], @@ -409,6 +470,18 @@ export class LoanProductSettingsStepComponent implements OnInit { nonPerformingAssetPenalInterestRate: [''], fixedDepositOverdraftPenalInterestRateUpdateInBranchProcess: ['YES'], addPenalInterestRate: [''], + atyp14SimpleInterestEnabled: ['NO'], + fixedDepositOverdraftMarginType: [''], + checkMasterDetailEditedPassingPendingEnabled: ['NO'], + creditDebitInterestCalculationSeparateEnabled: ['NO'], + onTimeInterestProvisionEnabled: ['NO'], + checkAgainstClearingEnabled: ['NO'], + gstOnPenaltyEnabled: ['NO'], + penaltyInterestGraceDays: [''], + overdrawnInterestRate: [''], + calculateDailyLimitEnhancementTodEnabled: ['NO'], + fixedDepositOverdraftMultipleInterestRateEnabled: ['NO'], + graceDaysAfterOverdueForMoratorium: [''], // Credit Bureau Settings (CIBIL) cibilAccountType: [''], @@ -426,7 +499,60 @@ export class LoanProductSettingsStepComponent implements OnInit { isFloatingRate: [false], foreclosureChargesApplicable: ['NO'], keyFactStatementEnabled: [true], - annualPercentageRateCalculationEnabled: [true] + annualPercentageRateCalculationEnabled: [true], + + // Channel & Transaction Limits + isMobileAppEnabled: ['NO'], + isAtmEnabled: ['NO'], + atmYearlyChargeEnabled: ['NO'], + atmMinimumBalance: [''], + emailActiveEnabled: ['NO'], + isImpsEnabled: ['NO'], + isUpiEnabled: ['NO'], + isPosEnabled: ['NO'], + isBbpsEnabled: ['NO'], + interBankLimitPerDay: [''], + interBankLimitPerTransaction: [''], + neftRtgsLimitPerDay: [''], + neftRtgsLimitPerTransaction: [''], + neftCutoffLimit: [''], + rtgsCutoffLimit: [''], + neftRtgsMinimumBalance: [''], + isChargeRequiredNeftRtgsCbs: [''], + isChargeRequiredNeftRtgsMobile: [''], + impsLimitPerDay: [''], + impsLimitPerTransaction: [''], + impsLimitPerMonth: [''], + impsMinLimit: [''], + impsMonthlyTransactionCount: [''], + + // POS Facility + maxPerTransactionLimitAtm: [''], + maxDayTransactionLimitAtm: [''], + maxPerTransactionLimitPos: [''], + maxDayTransactionLimitPos: [''], + maxPerTransactionLimitEcom: [''], + maxDayTransactionLimitEcom: [''], + maxPerTransactionLimitUpi: [''], + maxDayTransactionLimitUpi: [''], + + // ATM CSV File Related Other Details + atmCsvProductCode: [''], + atmCsvTypeCode: [''], + + // Auto Interest Post Parameters + autoInterestPostType: [''], + autoInterestPostWhen: [''], + autoInterestPostFixDay: [''], + autoLastInterestDate: [''], + + // Foreclosure / Early Account Closure + calculateEarlyAccountCloseCharge: ['NO'], + earlyAccountCloseCharge: [''], + earlyAccountClosePeriodInMonths: [''], + + // Gold Loan Specific + goldLoanPacketNumberWithYearEnabled: ['NO'] }); } diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.html index 6e765fbe3..7b1940a68 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.html @@ -264,90 +264,56 @@ }
- +
-

Interest Rate Slabs

+

Interest Rate Detail

-
- -
- - -
- - -
- @for (genGroup of slabGroups; track $index) { -
- {{ interestSlabDefinitions[$index].label }} -
- -
- Gen -
- - % -
-
- -
- Spl -
- - % -
-
-
-
- } -
- - -
- - @if (fixedRateGroup.get('hasFixed').value) { -
- - % -
- } -
+
+ + + + + + + + + + + + + + + + + + @for (row of interestRateDetailGroups; track $index) { + + + + + + + + + + } + +
Interest TypeCalculationNormal CategorySpecial CategoryPeriod
Mini. RateMaxi. RateMini. RateMaxi. Rate
{{ interestRateDetailTypes[$index] }} + + + +
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.scss index bda5c6392..d4f7af28d 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.scss @@ -199,175 +199,42 @@ $shadow-hover: 0 4px 12px rgb(37 99 235 / 10%); padding: 8px 4px; } -// ─── Interest Rate Slabs — Option C (2-column grid) ────────────────────────── -.lpt-slab-c { +// ─── Interest Rate Detail table (legacy Page 1 grid) ───────────────────────── +.lpt-ird-table-wrap { padding: 16px 24px 20px; - display: flex; - flex-direction: column; - gap: 0; + overflow-x: auto; } -// Particular row -.lpt-slab-c-particular { - display: flex; - align-items: center; - gap: 14px; - padding-bottom: 14px; - border-bottom: 1px solid $border; - margin-bottom: 12px; - flex-wrap: wrap; -} - -.lpt-slab-c-particular-label { - font-size: 12px; - font-weight: 700; - color: $text-secondary; - text-transform: uppercase; - letter-spacing: 0.05em; - white-space: nowrap; -} - -.lpt-slab-c-name-input { - flex: 1; - max-width: 320px; - padding: 7px 12px; - border: 1px solid $border; - border-radius: 8px; - font-size: 13.5px; - font-weight: 600; - color: $text-primary; - background: $surface; - outline: none; - transition: - border-color 0.15s, - box-shadow 0.15s; - - &::placeholder { - color: #b0b8c4; - font-weight: 400; - } - - &:focus { - border-color: $primary; - box-shadow: 0 0 0 3px rgb(37 99 235 / 10%); - } -} - -// General / Special tab toggle -.lpt-slab-tabs { - display: flex; - gap: 6px; - margin-left: auto; -} - -.lpt-slab-tab { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 16px; - border: 1.5px solid $border; - border-radius: 20px; - background: $surface; +.lpt-ird-table { + width: 100%; + border-collapse: collapse; font-size: 12.5px; - font-weight: 600; - color: $text-secondary; - cursor: pointer; - transition: all 0.15s; - i { + th, + td { + border: 1px solid $border; + padding: 6px 8px; + text-align: center; + } + + thead th { + background: $surface-alt; + font-weight: 700; + color: $text-secondary; + text-transform: uppercase; + letter-spacing: 0.03em; font-size: 11px; } - - &:hover { - border-color: $primary; - color: $primary; - } - - &--active { - background: $primary; - border-color: $primary; - color: $surface; - box-shadow: 0 2px 8px rgb(37 99 235 / 25%); - } } -// 2-column slab grid -.lpt-slab-c-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px 16px; - - @media (width <= 540px) { - grid-template-columns: 1fr; - } -} - -.lpt-slab-c-item { - display: flex; - align-items: center; - justify-content: space-between; - gap: 10px; - padding: 8px 12px; - border: 1px solid $border; - border-radius: 8px; - background: $surface; - transition: - border-color 0.15s, - box-shadow 0.15s; - - &:focus-within { - border-color: $primary; - box-shadow: 0 0 0 3px rgb(37 99 235 / 8%); - } -} - -// General + Special pair inside each card -.lpt-slab-c-rate-pair { - display: flex; - gap: 8px; - align-items: center; -} - -.lpt-slab-c-rate-field { - display: flex; - align-items: center; - gap: 4px; -} - -.lpt-slab-c-rate-label { - font-size: 10px; - font-weight: 700; - color: $primary; - background: #eff6ff; - padding: 2px 5px; - border-radius: 4px; +.lpt-ird-type { + text-align: left !important; + font-weight: 600; + color: $text-primary; white-space: nowrap; - - &--special { - color: #92400e; - background: #fef9c3; - } } -.lpt-slab-c-range { - font-size: 12.5px; - font-weight: 500; - color: $text-label; - flex: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -// Input + suffix wrapper -.lpt-slab-c-input-wrap { - display: flex; - align-items: center; - gap: 4px; - flex-shrink: 0; -} - -.lpt-slab-c-input { +.lpt-ird-input { width: 70px; padding: 4px 6px; border: 1px solid $border; @@ -379,79 +246,26 @@ $shadow-hover: 0 4px 12px rgb(37 99 235 / 10%); background: $surface-alt; outline: none; transition: border-color 0.15s; - appearance: textfield; - - &::-webkit-outer-spin-button, - &::-webkit-inner-spin-button { - appearance: none; - } &:focus { border-color: $primary; background: $primary-light; } - - &--fixed { - width: 90px; - } } -.lpt-slab-c-suffix { - font-size: 12px; - font-weight: 700; - color: $text-secondary; - user-select: none; - - &--special { - color: #92400e; - } -} - -.lpt-slab-c-input--special { - &:focus { - border-color: #f59e0b; - background: #fef9c3; - } -} - -.lpt-slab-c-error { - font-size: 10px; - color: #ef4444; -} - -// Fixed Interest Rate row (below grid) -.lpt-slab-c-fixed { - display: flex; - align-items: center; - gap: 20px; - margin: 12px -24px -20px; - padding: 12px 16px; - border-top: 2px dashed $primary-border; - background: $primary-light; - border-radius: 0 0 $radius-card $radius-card; - padding-left: 24px; - padding-right: 24px; -} - -.lpt-slab-c-fixed-toggle { - display: flex; - align-items: center; - gap: 8px; - cursor: pointer; +.lpt-ird-select { + width: 100%; + min-width: 90px; + padding: 4px 6px; + border: 1px solid $border; + border-radius: 6px; font-size: 13px; font-weight: 600; - color: $primary; - user-select: none; + color: $text-primary; + background: $surface; + outline: none; - i { - font-size: 12px; - opacity: 0.7; + &:focus { + border-color: $primary; } } - -.lpt-slab-c-checkbox { - accent-color: $primary; - width: 15px; - height: 15px; - cursor: pointer; -} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.ts index 9e457b6d8..baf888790 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-terms-step/loan-product-terms-step.component.ts @@ -57,24 +57,23 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges { repaymentFrequencyTypeData: any; repaymentStartDateTypeOptions: any; - readonly interestSlabDefinitions = [ - { label: 'Upto 10,000', maxAmount: 10000 }, - { label: 'Upto 25,000', maxAmount: 25000 }, - { label: 'Upto 1,00,000', maxAmount: 100000 }, - { label: 'Upto 2,00,000', maxAmount: 200000 }, - { label: 'Upto 5,00,000', maxAmount: 500000 }, - { label: 'Upto 10,00,000', maxAmount: 1000000 }, - { label: 'Upto 15,00,000', maxAmount: 1500000 }, - { label: 'Upto 20,00,000', maxAmount: 2000000 }, - { label: 'Upto 25,00,000', maxAmount: 2500000 }, - { label: 'More than 25,00,000', maxAmount: null } + // Legacy "Interest Rate Detail" table — 4 interest types x Normal/Special category x Min/Max Rate x Period + readonly interestRateDetailTypes = [ + 'Normal Debit', + 'Normal Credit', + 'Against Clearing', + 'Penalty' ]; - interestRateSlabsArray: FormArray; - specialSlabsArray: FormArray; - fixedRateGroup: FormGroup; - particularLabel = new FormControl(''); - activeSlabTab: 'general' | 'special' = 'general'; + readonly interestRateDetailPeriods = [ + 'DAILY', + 'MONTHLY', + 'QUARTERLY', + 'HALF YEARLY', + 'YEARLY' + ]; + + interestRateDetailArray: FormArray; constructor() { this.createLoanProductTermsForm(); @@ -134,35 +133,32 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges { } createLoanProductTermsForm() { - this.interestRateSlabsArray = new FormArray( - this.interestSlabDefinitions.map( + this.interestRateDetailArray = new FormArray( + this.interestRateDetailTypes.map( () => new FormGroup({ - interestRate: new FormControl(null, [ + calculation: new FormControl(false), + normalMinRate: new FormControl(null, [ Validators.min(0), Validators.max(100) - ]) + ]), + normalMaxRate: new FormControl(null, [ + Validators.min(0), + Validators.max(100) + ]), + specialMinRate: new FormControl(null, [ + Validators.min(0), + Validators.max(100) + ]), + specialMaxRate: new FormControl(null, [ + Validators.min(0), + Validators.max(100) + ]), + period: new FormControl('') }) ) ); - this.specialSlabsArray = new FormArray( - this.interestSlabDefinitions.map( - () => - new FormGroup({ - interestRate: new FormControl(null, [ - Validators.min(0), - Validators.max(100) - ]) - }) - ) - ); - - this.fixedRateGroup = new FormGroup({ - hasFixed: new FormControl(false), - fixedAmount: new FormControl({ value: null, disabled: true }, [Validators.min(0)]) - }); - this.loanProductTermsForm = this.formBuilder.group({ isLinkedToFloatingInterestRates: [false], allowApprovedDisbursedAmountsOverApplied: [false], @@ -287,15 +283,6 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges { } }); - this.fixedRateGroup.get('hasFixed').valueChanges.subscribe((hasFixed: boolean) => { - if (hasFixed) { - this.fixedRateGroup.get('fixedAmount').enable(); - } else { - this.fixedRateGroup.get('fixedAmount').disable(); - this.fixedRateGroup.get('fixedAmount').setValue(null); - } - }); - this.zeroInterest.valueChanges.subscribe((zeroInterest) => { if (zeroInterest) { this.loanProductTermsForm.get('minInterestRatePerPeriod').patchValue(0); @@ -322,16 +309,8 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges { }); } - get slabGroups(): FormGroup[] { - return this.interestRateSlabsArray.controls as FormGroup[]; - } - - get activeSlabGroups(): FormGroup[] { - return this.interestRateSlabsArray.controls as FormGroup[]; - } - - get specialSlabGroups(): FormGroup[] { - return this.specialSlabsArray.controls as FormGroup[]; + get interestRateDetailGroups(): FormGroup[] { + return this.interestRateDetailArray.controls as FormGroup[]; } get loanProductTerms() { @@ -349,15 +328,10 @@ export class LoanProductTermsStepComponent implements OnInit, OnChanges { minInterestRatePerPeriod: normalizeDecimal(formValue.minInterestRatePerPeriod), interestRatePerPeriod: normalizeDecimal(formValue.interestRatePerPeriod), maxInterestRatePerPeriod: normalizeDecimal(formValue.maxInterestRatePerPeriod), - interestRateSlabs: this.interestRateSlabsArray.getRawValue().map((slab, i) => ({ - maxAmount: this.interestSlabDefinitions[i].maxAmount, - label: this.interestSlabDefinitions[i].label, - interestRate: slab.interestRate - })), - fixedRate: (() => { - const fr = this.fixedRateGroup.getRawValue(); - return fr.hasFixed ? fr.fixedAmount : null; - })() + interestRateDetail: this.interestRateDetailArray.getRawValue().map((row, i) => ({ + interestType: this.interestRateDetailTypes[i], + ...row + })) }; } diff --git a/src/app/products/loan-products/loan-products.ts b/src/app/products/loan-products/loan-products.ts index 884b0a087..2d31b2b24 100644 --- a/src/app/products/loan-products/loan-products.ts +++ b/src/app/products/loan-products/loan-products.ts @@ -9,6 +9,246 @@ import { Injectable, inject } from '@angular/core'; import { SettingsService } from 'app/settings/settings.service'; +// Custom, UI-only fields grafted onto the loan product form to mirror the legacy +// "Account Type Creation" screen. Fineract's LoanProductDataValidator rejects any +// unrecognised parameter, so these are stripped from the payload until a backend +// mechanism (e.g. a linked Data Table) exists to persist them. +const CUSTOM_UI_ONLY_FIELDS: string[] = [ + // Details step — classification & legacy header fields + 'productTypeGroup', + 'productTypeSubGroup', + 'debitIntCalculation', + 'separatePenalInterest', + 'creditIntCalculation', + 'subAccountTypeBalance', + 'finalIntRounding', + 'roundingUpTo', + 'accountTypeCode', + 'micrTransactionCode', + 'reservedEcsSerialNumber', + 'reverseEcsNumber', + 'lockChequeInfoEnabled', + 'lockPageTwoInfoEnabled', + 'computerizationDate', + 'chequePrintDescription', + 'posAccountTypeDescription', + 'pfmsAccountType', + 'renewalDateAddMonths', + 'documentRenewalDateAddMonths', + 'ppsLimit', + 'isWriteOffAccountType', + 'writeOffAccountTypeCode', + 'renewalGraceDays', + // Settings step — Cheque Book Settings + 'chequeBookIssueEnabled', + 'chequeValidationRequired', + 'isFirstChequeBookFree', + 'chequePrintingAccountType', + 'allowWithdrawalSlipUsage', + 'maintainChequeBookStockRegistry', + 'freeChequeBooksPerYear', + 'allowCreditByChequeNumber', + 'creditChequeValidationRequired', + 'graceDaysForStockStatement', + // Settings step — Additional Product Settings + 'accountTypeActiveForTransactions', + 'subTypeActivityEnabled', + 'accountOpeningCharges', + 'maximumGoldLoanLimit', + 'lastAccountNumberOpened', + 'customerTerminationAllowed', + 'chargesForCashCreditAboveLimit', + 'deathInterestGLAccount', + 'startingLedgerNumber', + 'endingLedgerNumber', + 'currentLedgerNumber', + 'remittanceAccountNumber', + 'isNonResidentIndianAccount', + 'debitClearingGLAccount', + 'missedCallAlertServiceActive', + 'standingInstructionChargeGLAccount', + 'standingInstructionDebitChargeSkipOption', + 'openingBalanceMultiplierForRemittanceCharges', + 'goldLoanPacketNumberWithYearEnabled', + 'accountMoveToInoperativeEnabled', + 'generateGlDiffEntryEnabled', + 'subTypeWiseGlBalanceGenerationEnabled', + 'validateBeforeDeletingDebitEntryEnabled', + 'rcFileConceptEnabled', + 'accountCloseZeroBalanceInOpenDayProcess', + 'accountCloseZeroBalanceAtSubledgerTranEntry', + 'limitEnhancementAgainstClearingScreenDisplayEnabled', + 'advanceInterestParameterInLedgerEnabled', + 'vehicleDetailInMasterEnabled', + 'deletedChequeIssueEnabled', + 'dpReduceInDocumentRenewalDateEnabled', + 'dpReduceInRenewalDateEnabled', + 'autoCloseAtDayEndEnabled', + 'loanRateFromMasterEnabled', + 'chequeShortName', + 'statementPrintEnabled', + 'neslCode', + // Settings step — Interest Related Parameters + 'drawingPowerAndLimitGenerationProcedure', + 'advancesInterestCalculationMethod', + 'againstInterestCalculationEnabled', + 'dayWiseAgainstClearingInterestRounding', + 'interestCalculationOneFourthMethod', + 'againstClearingInterestProcedureType', + 'considerDebitClosingAmountForAgainstClearing', + 'interestRoundingMethod', + 'penaltyInterestCalculationEnabled', + 'penaltyInterestCalculationMethod', + 'penaltyInterestProcedureNumber', + 'overdrawnInterestCalculationMethod', + 'calculateOverdrawnInterestAfterRenewal', + 'interestOnCreditBalance', + 'penaltyInterestDateDifferentThanRegularInterest', + 'fixedDepositOverdraftCertificateSortOrder', + 'useDocumentSubmissionDateForInterest', + 'loanManagementSystemRenewalPenaltyActive', + 'minimumNormalInterestAmount', + 'minimumInterestCalculationMethod', + 'minimumAgainstClearingInterestAmount', + 'limitIncreaseUptoInterestAmountInInterestCalculation', + 'minimumPenaltyInterestAmount', + 'daysForLimitIncreaseUptoInterestAmount', + 'additionalInterestRateForFixedDepositOverdraft', + 'considerDdPayorderInAgainstClearingInterestCalculation', + 'graceDaysAfterRenewDate', + 'applyUndebitedInterestConceptEnabled', + 'interestRegisterPrintFormatType', + 'normalGraceDaysAfterOverdue', + 'allowAgainstClearingEntry', + 'allowNoBalanceEntry', + 'fixedDepositOverdraftPenaltyInterestCombinedWithNormalInterest', + 'allowNoBalanceEntryWithPassword', + 'undebitedSimpleInterestAccountWise', + 'dailyInterestCalculationEnabled', + 'dailyInterestCalculationStartDate', + 'nonPerformingAssetPenalInterestRateUpdate', + 'nonPerformingAssetPenalInterestRate', + 'fixedDepositOverdraftPenalInterestRateUpdateInBranchProcess', + 'addPenalInterestRate', + 'atyp14SimpleInterestEnabled', + 'fixedDepositOverdraftMarginType', + 'checkMasterDetailEditedPassingPendingEnabled', + 'creditDebitInterestCalculationSeparateEnabled', + 'onTimeInterestProvisionEnabled', + 'checkAgainstClearingEnabled', + 'gstOnPenaltyEnabled', + 'penaltyInterestGraceDays', + 'overdrawnInterestRate', + 'calculateDailyLimitEnhancementTodEnabled', + 'fixedDepositOverdraftMultipleInterestRateEnabled', + 'graceDaysAfterOverdueForMoratorium', + // Settings step — Credit Bureau Settings (CIBIL) + 'cibilAccountType', + 'cibilCommercialAccountType', + 'highmarkAccountType', + 'highmarkCommercialAccountType', + 'experianAccountType', + 'experianCommercialAccountType', + 'equifaxAccountType', + 'equifaxCommercialAccountType', + // Settings step — RBI Compliance & Product Category + 'loanProductCategory', + 'penalChargeMethod', + 'isFloatingRate', + 'foreclosureChargesApplicable', + 'keyFactStatementEnabled', + 'annualPercentageRateCalculationEnabled', + // Settings step — Channel & Transaction Limits + 'isMobileAppEnabled', + 'isAtmEnabled', + 'atmYearlyChargeEnabled', + 'atmMinimumBalance', + 'emailActiveEnabled', + 'isImpsEnabled', + 'isUpiEnabled', + 'isPosEnabled', + 'isBbpsEnabled', + 'interBankLimitPerDay', + 'interBankLimitPerTransaction', + 'neftRtgsLimitPerDay', + 'neftRtgsLimitPerTransaction', + 'neftCutoffLimit', + 'rtgsCutoffLimit', + 'neftRtgsMinimumBalance', + 'isChargeRequiredNeftRtgsCbs', + 'isChargeRequiredNeftRtgsMobile', + 'impsLimitPerDay', + 'impsLimitPerTransaction', + 'impsLimitPerMonth', + 'impsMinLimit', + 'impsMonthlyTransactionCount', + // Settings step — POS Facility & ATM CSV Settings + 'maxPerTransactionLimitAtm', + 'maxDayTransactionLimitAtm', + 'maxPerTransactionLimitPos', + 'maxDayTransactionLimitPos', + 'maxPerTransactionLimitEcom', + 'maxDayTransactionLimitEcom', + 'maxPerTransactionLimitUpi', + 'maxDayTransactionLimitUpi', + 'atmCsvProductCode', + 'atmCsvTypeCode', + // Settings step — Auto Interest Post Parameters + 'autoInterestPostType', + 'autoInterestPostWhen', + 'autoInterestPostFixDay', + 'autoLastInterestDate', + // Settings step — Foreclosure / Early Account Closure + 'calculateEarlyAccountCloseCharge', + 'earlyAccountCloseCharge', + 'earlyAccountClosePeriodInMonths', + // Terms step + 'debitBalanceAllow', + 'allowDebitTransAfterDueDate', + 'branchLevelAccountType', + 'interestRateDetail', + // Charges step — legacy cheque / standing instruction / minimum balance charges + 'chequeBookChargeEnabled', + 'chequeReturnChargeEnabled', + 'icChargeDebitEnabled', + 'cashBundleChargeEnabled', + 'cashBundleChargeWithPanLimit', + 'perChequeEntryCharge', + 'perChequeEntryServiceCharge', + 'perInwardChequeEntryCharge', + 'perOutwardChequeEntryCharge', + 'creditorStandingInstructionFailCharge', + 'debtorStandingInstructionFailCharge', + 'minimumBalanceCheckingType', + 'autoMinimumBalanceCharge', + 'calculateDailyMinimumBalanceCharges', + 'minimumBalanceChargeEnabled', + 'minimumBalanceChargeAmount', + 'minimumBalanceChargeForChequeIssue', + 'minimumBalanceChargeMethod', + 'monthsAfterMinBalanceChargeCalculate', + 'forChequeIssue', + 'forChequeIssueAvg', + 'forWithdrawalSlip', + 'forWithdrawalSlipAvg', + 'calculateDailyAgainstClearingCharge', + // Accounting step — custom GL account mappings + 'intReceivablesGlAccountId', + 'intPayableGlAccountId', + 'deafIntPayableGlAccountId', + 'intOverdueReserveAccountId', + 'undebitedInterestAccountId', + 'penalIntCrGlAccountId', + 'rdMaturedGlAccountId', + 'glAccountId', + 'icChargeGlAccountId', + 'inoperativeGlAccountId', + 'creditBalanceLiabilityGlAccountId', + 'creditBalanceAssetGlAccountId', + 'overdueAccountsGlAccountId', + 'rebateGlAccountId' +]; + @Injectable({ providedIn: 'root' }) @@ -49,6 +289,9 @@ export class LoanProducts { delete loanProduct.allowAttributeConfiguration; delete loanProduct.advancedAccountingRules; + // Remove custom, UI-only fields not yet recognised by the Fineract backend + CUSTOM_UI_ONLY_FIELDS.forEach((field) => delete loanProduct[field]); + // In Fineract, the POST and PUT endpoints for /v1/loanproducts have a typo in the field // allowPartialPeriodInterestCalculation. Until that is fixed, we need to replace the field name in the payload. loanProduct.allowPartialPeriodInterestCalculation = loanProduct.allowPartialPeriodInterestCalculation;