diff --git a/src/app/features/products/loan-product-form.component.test.ts b/src/app/features/products/loan-product-form.component.test.ts index eb2df224b..98fd2325b 100644 --- a/src/app/features/products/loan-product-form.component.test.ts +++ b/src/app/features/products/loan-product-form.component.test.ts @@ -87,33 +87,42 @@ const TEMPLATE = { buyDownFeeCalculationTypeOptions: [{ code: 'FLAT', value: 'Flat' }], buyDownFeeStrategyOptions: [{ code: 'EQUAL_AMORTIZATION', value: EQUAL_AMORTIZATION_LABEL }], interestRecalculationCompoundingTypeOptions: [ - { id: 0, code: 'interestRecalculationCompoundingMethod.none', description: 'None' }, - { id: 1, code: 'interestRecalculationCompoundingMethod.fee', description: 'Fee' }, + { id: 0, code: 'interestRecalculationCompoundingMethod.none', value: 'None' }, + { id: 1, code: 'interestRecalculationCompoundingMethod.fee', value: 'Fee' }, ], interestRecalculationFrequencyTypeOptions: [ { id: 1, code: 'interestRecalculationFrequencyType.same.as.repayment.period', - description: 'Same as repayment period', + value: 'Same as repayment period', }, - { id: 2, code: 'interestRecalculationFrequencyType.daily', description: 'Daily' }, + { id: 2, code: 'interestRecalculationFrequencyType.daily', value: 'Daily' }, ], rescheduleStrategyTypeOptions: [ { id: 1, code: 'loanRescheduleStrategyMethod.reduce.emi.amount', - description: 'Reduce EMI amount', + value: 'Reduce EMI amount', }, ], preClosureInterestCalculationStrategyOptions: [ { id: 1, - code: 'preClosureInterestCalculationStrategy.tillPreClosureDate', - description: 'Till pre-close date', + code: 'loanPreClosureInterestCalculationStrategy.tillPreClosureDate', + value: 'Till pre-close date', }, ], repaymentStartDateTypeOptions: [ - { id: 1, code: 'repaymentStartDateType.disbursement', description: 'Disbursement date' }, + { + id: 1, + code: 'repaymentStartDateType.disbursementDate', + value: 'Disbursement Date', + }, + { + id: 2, + code: 'repaymentStartDateType.submittedOnDate', + value: 'Submitted On Date', + }, ], chargeOffBehaviourOptions: [ { code: 'REGULAR', value: 'Regular' }, @@ -492,7 +501,33 @@ describe('LoanProductFormComponent', () => { expect(component.capitalizedIncomeTypeOptions()).toHaveLength(2); expect(component.capitalizedIncomeStrategyOptions()[0].value).toBe(EQUAL_AMORTIZATION_LABEL); expect(component.chargeOffBehaviourOptions()).toHaveLength(2); - expect(component.repaymentStartDateTypeOptions()).toHaveLength(1); + expect(component.repaymentStartDateTypeOptions()).toHaveLength(2); + }); + + it('renders every template enum label from the live response shape', () => { + component.onInterestRecalculationChange(true); + component.onCompoundingMethodChange(1); + fixture.detectChanges(); + + const labels = (testId: string) => + Array.from( + fixture.nativeElement + .querySelector(`[data-testid="${CSS.escape(testId)}"]`) + .querySelectorAll('ion-select-option'), + ).map((option) => option.textContent.trim()); + + expect(labels('loan-product-compounding-method')).toEqual(['None', 'Fee']); + expect(labels('loan-product-reschedule-strategy')).toEqual(['Reduce EMI amount']); + expect(labels('loan-product-rest-frequency')).toEqual(['Same as repayment period', 'Daily']); + expect(labels('loan-product-compounding-frequency')).toEqual([ + 'Same as repayment period', + 'Daily', + ]); + expect(labels('loan-product-pre-closure-strategy')).toEqual(['Till pre-close date']); + expect(labels('loan-product-repayment-start-date-type')).toEqual([ + 'Disbursement Date', + 'Submitted On Date', + ]); }); }); diff --git a/src/app/features/products/loan-product-form.component.ts b/src/app/features/products/loan-product-form.component.ts index 10c996ecf..1e9231d15 100644 --- a/src/app/features/products/loan-product-form.component.ts +++ b/src/app/features/products/loan-product-form.component.ts @@ -87,6 +87,13 @@ import { TooltipDirective } from '../../shared/directives/tooltip.directive'; */ const DAILY_INTEREST_CALCULATION_PERIOD = 0; +/** + * Fineract serializes enum options as `{ id, code, value }` (`BaseEnumOptionData`). The generated + * loan-product models declare `description` instead, which the server does not send; see #653. + * Drop this compatibility type once the models are regenerated from the corrected contract. + */ +type TemplateEnumOption = T & { value?: string }; + @Component({ selector: 'app-loan-product-form', standalone: true, @@ -992,7 +999,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of compoundingTypeOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1019,7 +1026,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of rescheduleStrategyOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1046,7 +1053,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of recalculationFrequencyOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1098,7 +1105,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of recalculationFrequencyOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1152,7 +1159,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of preClosureStrategyOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1216,7 +1223,7 @@ const DAILY_INTEREST_CALCULATION_PERIOD = 0; > @for (option of repaymentStartDateTypeOptions(); track option.id) { {{ - option.description + enumLabel(option) }} } @@ -1421,17 +1428,21 @@ export class LoanProductFormComponent implements OnInit { readonly compoundingMethod = signal(undefined); readonly restFrequencyType = signal(undefined); readonly compoundingFrequencyType = signal(undefined); - readonly compoundingTypeOptions = signal( - [], - ); + readonly compoundingTypeOptions = signal< + TemplateEnumOption[] + >([]); readonly recalculationFrequencyOptions = signal< - GetLoanProductsInterestRecalculationCompoundingFrequencyType[] + TemplateEnumOption[] + >([]); + readonly rescheduleStrategyOptions = signal< + TemplateEnumOption[] >([]); - readonly rescheduleStrategyOptions = signal([]); readonly preClosureStrategyOptions = signal< - GetLoanProductsPreClosureInterestCalculationStrategy[] + TemplateEnumOption[] + >([]); + readonly repaymentStartDateTypeOptions = signal< + TemplateEnumOption[] >([]); - readonly repaymentStartDateTypeOptions = signal([]); readonly chargeOffBehaviourOptions = signal([]); /** @@ -1497,6 +1508,10 @@ export class LoanProductFormComponent implements OnInit { this.product.update((product) => ({ ...product, [field]: value })); } + protected enumLabel(option: { value?: string; description?: string; code?: string }): string { + return option.value ?? option.description ?? option.code ?? ''; + } + /** Applies multiple related product fields in one signal notification. */ private patchProductFields(patch: Partial): void { this.product.update((product) => ({ ...product, ...patch }));