Files
cbsnexora/src/app/deposits/recurring-deposits/recurring-deposits-account-stepper/recurring-deposits-account-charges-step/recurring-deposits-account-charges-step.component.ts
T

275 lines
8.8 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, OnInit, Input, OnChanges, inject } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
/** Dialog Components */
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
/** Custom Services */
import { DatepickerBase } from 'app/shared/form-dialog/formfield/model/datepicker-base';
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { Charge, Currency } from 'app/shared/models/general.model';
import { MatButton, MatIconButton } from '@angular/material/button';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import {
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow
} from '@angular/material/table';
import { MatStepperPrevious, MatStepperNext } from '@angular/material/stepper';
import { DateFormatPipe } from '../../../../pipes/date-format.pipe';
import { FormatNumberPipe } from '../../../../pipes/format-number.pipe';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Recurring Deposit Account Charges Step
*/
@Component({
selector: 'mifosx-recurring-deposits-account-charges-step',
templateUrl: './recurring-deposits-account-charges-step.component.html',
styleUrls: ['./recurring-deposits-account-charges-step.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
FaIconComponent,
MatTable,
MatColumnDef,
MatHeaderCellDef,
MatHeaderCell,
MatCellDef,
MatCell,
MatIconButton,
MatHeaderRowDef,
MatHeaderRow,
MatRowDef,
MatRow,
MatStepperPrevious,
MatStepperNext,
DateFormatPipe,
FormatNumberPipe
]
})
export class RecurringDepositsAccountChargesStepComponent implements OnInit, OnChanges {
dialog = inject(MatDialog);
private dateUtils = inject(Dates);
private settingsService = inject(SettingsService);
@Input() recurringDepositsAccountTemplate: any;
@Input() recurringDepositsAccountProductTemplate: any;
@Input() currencyCode: UntypedFormControl;
@Input() recurringDepositAccountFormValid: boolean;
/** Charges Data */
chargeData: any[] = [];
/** Charges Data Source */
chargesDataSource: {}[] = [];
/** Charges table columns */
displayedColumns: string[] = [
'name',
'chargeCalculationType',
'amount',
'chargeTimeType',
'date',
'repaymentsEvery',
'action'
];
/** Component is pristine if there has been no changes by user interaction */
pristine = true;
/** For Edit Recurring Deposits Account Form */
isChargesPatched = false;
/** Currency Code */
currency: Currency | null = null;
ngOnInit() {
this.chargesDataSource = [];
if (this.recurringDepositsAccountTemplate.id && this.recurringDepositsAccountTemplate.charges) {
// Edit mode: load saved charges from existing account
this.chargesDataSource =
this.recurringDepositsAccountTemplate.charges.map((charge: any) => ({ ...charge, id: charge.chargeId })) || [];
this.isChargesPatched = true;
}
}
ngOnChanges() {
if (this.currency == null) {
if (this.recurringDepositsAccountTemplate.currency) {
this.currency = this.recurringDepositsAccountTemplate.currency;
} else if (
this.recurringDepositsAccountProductTemplate &&
this.recurringDepositsAccountProductTemplate.currency
) {
this.currency = this.recurringDepositsAccountProductTemplate.currency;
}
}
if (this.recurringDepositsAccountProductTemplate) {
this.chargeData = this.recurringDepositsAccountProductTemplate.chargeOptions.filter(
(c: Charge) => c.currency.code === this.currency?.code
);
// New account: pre-populate charges from product template
if (!this.isChargesPatched && !this.recurringDepositsAccountTemplate?.id) {
const productCharges = this.recurringDepositsAccountProductTemplate.charges;
if (Array.isArray(productCharges) && productCharges.length > 0) {
this.chargesDataSource = productCharges.map((charge: any) => ({ ...charge, id: charge.chargeId }));
}
this.isChargesPatched = true;
}
}
}
/**
* Add a charge
*/
addCharge(charge: any) {
this.chargesDataSource = this.chargesDataSource.concat([charge.value]);
charge.value = '';
this.pristine = false;
}
/**
* Edits the Charge Amount
* @param {any} charge Charge
*/
editChargeAmount(charge: any) {
const formfields: FormfieldBase[] = [
new InputBase({
controlName: 'amount',
label: 'Amount',
value: charge.amount,
type: 'number',
required: false
})
];
const data = {
title: 'Edit Charge Amount',
layout: { addButtonText: 'Confirm' },
formfields: formfields
};
const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data });
editNoteDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
const newCharge = { ...charge, amount: response.data.value.amount };
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge);
this.chargesDataSource = this.chargesDataSource.concat([]);
}
});
this.pristine = false;
}
/**
* Edits the Charge Date
* @param {any} charge Charge
*/
editChargeDate(charge: any) {
const formfields: FormfieldBase[] = [
new DatepickerBase({
controlName: 'date',
label: 'Date',
value: charge.dueDate || charge.feeOnMonthDay || '',
type: 'datetime-local',
required: false
})
];
const data = {
title: 'Edit Charge Date',
layout: { addButtonText: 'Confirm' },
formfields: formfields
};
const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data });
editNoteDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
let newCharge: any;
const dateFormat = this.settingsService.dateFormat;
const date = this.dateUtils.formatDate(response.data.value.date, dateFormat);
switch (charge.chargeTimeType.value) {
case 'Specified due date':
case 'Weekly Fee':
newCharge = { ...charge, dueDate: date };
break;
case 'Annual Fee':
newCharge = { ...charge, feeOnMonthDay: date };
break;
}
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge);
this.chargesDataSource = this.chargesDataSource.concat([]);
}
});
this.pristine = false;
}
/**
* Edits the Charge Fee Interval
* @param {any} charge Charge
*/
editChargeFeeInterval(charge: any) {
const formfields: FormfieldBase[] = [
new InputBase({
controlName: 'feeInterval',
label: 'Fee Interval',
value: charge.feeInterval,
type: 'text',
required: false
})
];
const data = {
title: 'Edit Charge Fee Interval',
layout: { addButtonText: 'Confirm' },
formfields: formfields
};
const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data });
editNoteDialogRef.afterClosed().subscribe((response: any) => {
if (response.data) {
const newCharge = { ...charge, feeInterval: response.data.value.feeInterval };
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1, newCharge);
this.chargesDataSource = this.chargesDataSource.concat([]);
}
});
this.pristine = false;
}
/**
* Delete a particular charge
* @param charge Charge
*/
deleteCharge(charge: any) {
const deleteChargeDialogRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `charge ${charge.name}` }
});
deleteChargeDialogRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1);
this.chargesDataSource = this.chargesDataSource.concat([]);
this.pristine = false;
}
});
}
/**
* Returns Recurring Deposits Account Charges Form
*/
get recurringDepositAccountCharges() {
return {
charges: this.chargesDataSource
};
}
}