Files
cbsnexora/src/app/deposits/fixed-deposits/fixed-deposit-account-stepper/fixed-deposit-account-maturity-terms-step/fixed-deposit-account-maturity-terms-step.component.ts
T
niteshandClaude Sonnet 5 e58fd3c79a
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
feat(deposits): sync linked account with maturity terms, add deposit certificate printing
Fixed and Recurring Deposit wizards now bidirectionally sync the Product tab's
linked-account selection with the new Terms tab's Transfer-to-Savings account,
disable the Withdraw Deposit maturity instruction end-to-end, and card-style
the Transfer to Savings picker to match the existing linked-account UI. Adds
a printable FD/RD deposit certificate from the account view page, following
the existing letter-mgmt certificate pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 11:05:25 +05:30

118 lines
4.9 KiB
TypeScript

/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/** Angular Imports */
import { Component, Input, OnChanges, SimpleChanges, inject } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, UntypedFormControl, Validators } from '@angular/forms';
import { MatCheckbox } from '@angular/material/checkbox';
import { MatIcon } from '@angular/material/icon';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Fixed Deposit Account Maturity Terms Step -- what happens to this account at maturity
* (Withdraw / Transfer to Savings / Reinvest) and the pre-mature-closure penalty, decided
* per account rather than silently inherited from the product.
*/
@Component({
selector: 'mifosx-fixed-deposit-account-maturity-terms-step',
templateUrl: './fixed-deposit-account-maturity-terms-step.component.html',
styleUrls: ['./fixed-deposit-account-maturity-terms-step.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
MatCheckbox,
MatIcon
]
})
export class FixedDepositAccountMaturityTermsStepComponent implements OnChanges {
private formBuilder = inject(UntypedFormBuilder);
@Input() fixedDepositsAccountTemplate: any;
@Input() fixedDepositsAccountProductTemplate: any;
/** Account already linked elsewhere in the wizard (the Details step's Deposit Account Link) --
* pre-fills Transfer to Savings so the officer doesn't have to pick the same account twice. */
@Input() linkedSavingsAccountId: number | null = null;
closureSettingsForm: UntypedFormGroup;
maturityInstructionOptions: any[] = [];
savingsAccountsData: any[] = [];
preClosurePenalInterestOnTypeData: any[] = [];
constructor() {
this.closureSettingsForm = this.formBuilder.group({
maturityInstructionId: [''],
preClosurePenalApplicable: [false],
preClosurePenalInterest: [
'',
Validators.min(0)
],
preClosurePenalInterestOnTypeId: ['']
});
this.closureSettingsForm.get('maturityInstructionId').valueChanges.subscribe((value: number) => {
// 200 = Transfer to Savings -- Withdraw Deposit (100) needs no target account, and both
// Reinvest options (300/400) open a brand-new FD instead, so they ignore this field too.
if (value === 200) {
this.closureSettingsForm.addControl(
'transferToSavingsId',
new UntypedFormControl(this.linkedSavingsAccountId ?? '', Validators.required)
);
} else {
this.closureSettingsForm.removeControl('transferToSavingsId');
}
});
}
ngOnChanges(changes: SimpleChanges) {
if (changes.linkedSavingsAccountId) {
const control = this.closureSettingsForm.get('transferToSavingsId');
if (control && !control.value && this.linkedSavingsAccountId) {
control.setValue(this.linkedSavingsAccountId);
}
}
if (this.fixedDepositsAccountProductTemplate) {
// Withdraw Deposit (id 100) books the maturity proceeds out of the bank's cash/vault the moment
// the account matures, before the customer has actually collected it -- disabled everywhere.
this.maturityInstructionOptions = (
this.fixedDepositsAccountProductTemplate.maturityInstructionOptions ?? []
).filter((option: any) => option.id !== 100);
this.savingsAccountsData = this.fixedDepositsAccountProductTemplate.savingsAccounts ?? [];
this.preClosurePenalInterestOnTypeData =
this.fixedDepositsAccountProductTemplate.preClosurePenalInterestOnTypeOptions ?? [];
if (!this.closureSettingsForm.get('preClosurePenalApplicable').dirty) {
this.closureSettingsForm.patchValue({
preClosurePenalApplicable: this.fixedDepositsAccountProductTemplate.preClosurePenalApplicable ?? false,
preClosurePenalInterest: this.fixedDepositsAccountProductTemplate.preClosurePenalInterest ?? '',
preClosurePenalInterestOnTypeId:
this.fixedDepositsAccountProductTemplate.preClosurePenalInterestOnType?.id ?? ''
});
}
}
}
/** The linked-savings account for the transfer-to-savings maturity instruction, once picked. */
get selectedTransferAccount(): any {
const id = this.closureSettingsForm.value.transferToSavingsId;
if (!id) return null;
return this.savingsAccountsData.find((account: any) => account.id === id) ?? null;
}
clearTransferAccount(): void {
this.closureSettingsForm.get('transferToSavingsId')?.setValue('');
}
/** Chosen maturity/closure settings, ready to merge into the submit payload. */
get closureSettings() {
const settings = this.closureSettingsForm.getRawValue();
for (const key in settings) {
if (settings[key] === '') {
delete settings[key];
}
}
return settings;
}
}