merge angular-17 into dev to upgrade from Angular v16 to v17

This commit is contained in:
gkbishnoi07
2025-06-05 15:51:43 +02:00
committed by Adam Saghy
parent 94e37d129c
commit 1d6b6fd743
65 changed files with 4565 additions and 4571 deletions
@@ -263,7 +263,7 @@ export class CreateStandingInstructionsComponent implements OnInit {
/** Refine Object
* Removes the object param with null or '' values
*/
refineObject(dataObj: Object) {
refineObject(dataObj: { [key: string]: any }) {
const propNames = Object.getOwnPropertyNames(dataObj);
for (let i = 0; i < propNames.length; i++) {
const propName = propNames[i];
@@ -43,6 +43,9 @@ export class CenterActionsComponent {
) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const name = this.route.snapshot.params['action'];
this.actions[name] = true;
if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -24,6 +24,7 @@ export class ClientActionsComponent {
'Accept Transfer': boolean;
'Reject Transfer': boolean;
Reactivate: boolean;
Activate: boolean;
'Undo Rejection': boolean;
'Add Charge': boolean;
'Take Survey': boolean;
@@ -41,6 +42,7 @@ export class ClientActionsComponent {
'Accept Transfer': false,
'Reject Transfer': false,
Reactivate: false,
Activate: false,
'Undo Rejection': false,
'Add Charge': false,
'Take Survey': false,
@@ -57,7 +59,7 @@ export class ClientActionsComponent {
private router: Router
) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const name = this.route.snapshot.params['name'];
const name = this.route.snapshot.params['name'] as keyof typeof this.actions;
this.actions[name] = true;
}
}
@@ -72,7 +72,7 @@ export class TakeSurveyComponent {
// TODO: document the function
groupBy(array: any, func: any) {
const groups = {};
const groups: { [key: string]: any[] } = {};
array.forEach((ele: any) => {
const group = JSON.stringify(func(ele));
groups[group] = groups[group] || [];
@@ -39,7 +39,7 @@
</mat-form-field>
<mat-checkbox formControlName="isDependent" labelPosition="before" class="flex-50-minus-25px">
>{{ 'labels.inputs.Is Dependent' | translate }}?
{{ 'labels.inputs.Is Dependent' | translate }}?
</mat-checkbox>
<mat-form-field class="flex-50-minus-25px">
@@ -52,7 +52,10 @@ export class IndividualCollectionSheetComponent implements OnInit {
/** checks and stores the local storage values */
Success: boolean;
/** Bulk Disbursement Transactions Data */
bulkDisbursementTransactionsData = {};
bulkDisbursementTransactionsData: {
bulkRepaymentTransactions?: any[];
bulkSavingsDueTransactions?: any[];
} = {};
/** Bulk Repayment Transactions Data */
bulkRepaymentTransactions: any[] = [];
/** Bulk Savings Due Data */
@@ -261,7 +264,16 @@ export class IndividualCollectionSheetComponent implements OnInit {
if (response.data) {
if (type === 'loans') {
const totalDue = this.getLoanTotalDueAmount(selectedData);
const loanTransaction = {
const loanTransaction: {
loanId: any;
transactionAmount: number;
paymentTypeId?: string;
accountNumber?: any;
checkNumber?: number;
routingCode?: string;
receiptNumber?: number;
bankNumber?: number;
} = {
loanId: selectedData.loanId,
transactionAmount: totalDue
};
@@ -279,7 +291,17 @@ export class IndividualCollectionSheetComponent implements OnInit {
if (isNaN(dueAmount)) {
dueAmount = 0;
}
const savingsTransaction = {
const savingsTransaction: {
savingsId: any;
transactionAmount: any;
depositAccountType: number;
accountNumber?: any;
checkNumber?: number;
routingCode?: string;
receiptNumber?: number;
bankNumber?: number;
paymentTypeId?: string;
} = {
savingsId: selectedData.savingsId,
transactionAmount: dueAmount,
depositAccountType:
@@ -10,7 +10,7 @@ import { environment } from '../../../environments/environment';
import { SettingsService } from 'app/settings/settings.service';
/** Http request (default) options headers. */
const httpOptions = {
const httpOptions: { headers: { [key: string]: string } } = {
headers: {
'Fineract-Platform-TenantId': environment.fineractPlatformTenantId
}
+2 -1
View File
@@ -107,7 +107,8 @@ export class HttpCacheService {
*/
setPersistence(persistence?: 'local' | 'session') {
this.cleanCache();
this.storage = persistence === 'local' || persistence === 'session' ? window[persistence + 'Storage'] : null;
this.storage =
persistence === 'local' ? window.localStorage : persistence === 'session' ? window.sessionStorage : null;
this.loadCacheData();
}
@@ -41,6 +41,8 @@ export class FixedDepositsAccountActionsComponent {
*/
constructor(private route: ActivatedRoute) {
const name = this.route.snapshot.params['name'];
this.actions[name] = true;
if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -5,6 +5,7 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { ActivatedRoute, Router } from '@angular/router';
import { Currency, PaymentType } from 'app/shared/models/general.model';
import { TransactionCommand, TransactionTypeFlags } from '../../../transaction.model';
@Component({
selector: 'mifosx-fixed-deposits-cash-transaction',
@@ -23,9 +24,9 @@ export class FixedDepositsCashTransactionComponent implements OnInit {
/** Flag to enable payment details fields. */
addPaymentDetailsFlag: Boolean = false;
/** transaction type flag to render required UI */
transactionType: { deposit: boolean; withdrawal: boolean } = { deposit: false, withdrawal: false };
transactionType: TransactionTypeFlags = { deposit: false, withdrawal: false };
/** transaction command for submit request */
transactionCommand: string;
transactionCommand: TransactionCommand;
actionName: string;
/** saving account's Id */
accountId: string;
@@ -53,8 +54,14 @@ export class FixedDepositsCashTransactionComponent implements OnInit {
this.paymentTypeOptions = data.fixedDepositsAccountActionData.paymentTypeOptions;
});
this.actionName = this.route.snapshot.params['name'];
this.transactionCommand = this.actionName.toLowerCase();
this.transactionType[this.transactionCommand] = true;
const lowerName = this.actionName.toLowerCase();
if (lowerName === 'deposit' || lowerName === 'withdrawal') {
this.transactionCommand = lowerName;
this.transactionType[this.transactionCommand] = true;
} else {
throw new Error(`Invalid transaction action: ${this.actionName}`);
}
this.accountId = this.route.parent.snapshot.params['fixedDepositAccountId'];
}
@@ -8,6 +8,7 @@ import { RecurringDepositsService } from '../../recurring-deposits.service';
import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { Currency } from 'app/shared/models/general.model';
import { TransactionCommand, TransactionTypeFlags } from '../../../transaction.model';
/**
* Deposits Recurring Deposits Account Component
@@ -39,8 +40,8 @@ export class DepositRecurringDepositsAccountComponent implements OnInit {
action: string;
actionName: string;
transactionCommand: string;
transactionType: { deposit: boolean; withdrawal: boolean } = { deposit: false, withdrawal: false };
transactionCommand: TransactionCommand;
transactionType: TransactionTypeFlags = { deposit: false, withdrawal: false };
/**
* Retrieves action details transactions template data from `resolve`
@@ -66,13 +67,18 @@ export class DepositRecurringDepositsAccountComponent implements OnInit {
data.recurringDepositsAccountActionData.outstandingChargeAmount > 0
) {
this.outstandingChargeAmount = data.recurringDepositsAccountActionData.outstandingChargeAmount;
this.transactionAmount = this.transactionAmount + this.outstandingChargeAmount;
this.transactionAmount += this.outstandingChargeAmount;
}
});
this.actionName = this.route.snapshot.params['name'];
this.action = this.actionName.toLowerCase();
this.transactionCommand = this.action.toLowerCase();
this.transactionType[this.transactionCommand] = true;
if (this.action === 'deposit' || this.action === 'withdrawal') {
this.transactionCommand = this.action;
this.transactionType[this.transactionCommand] = true;
} else {
throw new Error(`Invalid transaction action: ${this.actionName}`);
}
this.accountId = this.route.parent.snapshot.params['recurringDepositAccountId'];
}
@@ -47,6 +47,8 @@ export class RecurringDepositsAccountActionsComponent {
}
});
const name = this.route.snapshot.params['name'];
this.actions[name] = true;
if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -69,8 +69,7 @@
{{ 'labels.inputs.Note' | translate }}
</div>
<div class="flex-50">
*ngIf="transactionData.note">
<div class="flex-50" *ngIf="transactionData.note">
{{ transactionData.note }}
</div>
+5
View File
@@ -0,0 +1,5 @@
export type TransactionCommand = 'deposit' | 'withdrawal';
export type TransactionTypeFlags = {
[key in TransactionCommand]: boolean;
};
@@ -44,6 +44,8 @@ export class GroupActionsComponent {
) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
const action = this.route.snapshot.params['action'];
this.actions[action] = true;
if (action && action in this.actions) {
this.actions[action as keyof typeof this.actions] = true;
}
}
}
@@ -85,7 +85,7 @@ export class LoansAccountDatatableStepComponent implements OnInit {
get payload(): any {
const dateFormat = this.settingsService.dateFormat;
const datatableDataValues = this.datatableForm.value;
const data = {
const data: { [key: string]: any } = {
locale: this.settingsService.language.code
};
let existDate = false;
@@ -15,6 +15,12 @@ import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
import { Currency } from 'app/shared/models/general.model';
import { CodeName, OptionData } from 'app/shared/models/option-data.model';
interface DisbursementData {
id?: number;
principal: number;
expectedDisbursementDate: string | Date;
}
/**
* Create Loans Account Terms Step
*/
@@ -62,7 +68,7 @@ export class LoansAccountTermsStepComponent implements OnInit, OnChanges {
/** Client Active Loan Data */
clientActiveLoanData: any;
/** Multi Disbursement Data */
disbursementDataSource: {}[] = [];
disbursementDataSource: DisbursementData[] = [];
/** Loan repayment strategies */
transactionProcessingStrategyOptions: any = [];
repaymentStrategyDisabled = false;
@@ -24,7 +24,9 @@ export class EditRepaymentScheduleComponent implements OnInit {
/** Indicates If the Schedule has been validated */
wasValidated = false;
/** Stores the Repayment Schedule data */
repaymentScheduleDetails: any[] | null = null;
repaymentScheduleDetails: {
periods: { period?: number; dueDate: string; totalDueForPeriod?: number; changed?: boolean }[];
} | null = null;
/** Stores the Installments changed */
repaymentScheduleChanges: any = {};
@@ -56,7 +56,12 @@ export class RescheduleLoanTabComponent {
if (response.confirm) {
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const payload = {
const payload: {
dateFormat: string;
locale: string;
approvedOnDate?: string;
rejectedOnDate?: string;
} = {
dateFormat,
locale
};
@@ -386,7 +386,7 @@ export class TransactionsTabComponent implements OnInit {
value: this.dateUtils.parseDate(transactionDate),
type: 'datetime-local',
required: true,
minDate: transaction.date,
minDate: this.dateUtils.parseDate(transaction.date),
order: 1
}),
new InputBase({
@@ -43,8 +43,7 @@
</mat-form-field>
<div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75">
(click)="addPaymentDetails()">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
<mat-slide-toggle>
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
@@ -25,9 +25,7 @@
[routerLink]="[routeMap[row.objectType], row.objectId]"
></tr>
<tr *matNoDataRow>
<td [attr.colspan]="displayedColumns.length" style="text-align: center; padding: 16px; color: #999">
You don't have any notifications
</td>
<td [attr.colspan]="displayedColumns.length">You don't have any notifications</td>
</tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
@@ -37,7 +37,7 @@ export class CreateHolidayComponent implements OnInit {
// Stores office data in a trie-like structure
officesTrie: any;
// Stores office data for access from DOM via Office ID
officesDict = {};
officesDict: { [key: string]: any } = {};
// Angular Material Tree Configuration start ------------
@@ -100,7 +100,7 @@ export class CreateHolidayComponent implements OnInit {
});
}
constructOfficeHierarchy() {
const trie = {};
const trie: Record<string, any> = {};
// Iterates over all the offices
this.officesData.forEach((office: any) => {
this.officesDict[office.id] = office;
@@ -114,7 +114,7 @@ export class CreateHolidayComponent implements OnInit {
// Temporary variable to store current object
let root = trie;
let root: Record<string, any> = trie;
if (hierarchy.length === 0) {
root[office.id] = {};
@@ -161,7 +161,7 @@ export class BusinessRuleParametersComponent implements OnInit, OnChanges {
formattedResponse[newKey] = value;
break;
case 'select':
formattedResponse[newKey] = value['id'];
formattedResponse[newKey] = (value as { id: string | number })['id'];
break;
case 'date':
const dateFormat = this.settingsService.dateFormat;
+1 -1
View File
@@ -48,6 +48,6 @@ export class StatusLookupPipe implements PipeTransform {
'smsCampaignStatus.closed': 'status-closed',
'purchasedSharesStatusType.applied': 'status-pending'
};
return cssClassNameLookup[status];
return cssClassNameLookup[status as keyof typeof cssClassNameLookup] ?? 'status-unknown';
}
}
@@ -91,7 +91,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
this.clientClassificationData = this.fixedDepositProductsTemplate.chartTemplate.clientClassificationOptions;
this.incentiveTypeData = this.fixedDepositProductsTemplate.chartTemplate.incentiveTypeOptions;
if (!(this.fixedDepositProductsTemplate === undefined)) {
if (this.fixedDepositProductsTemplate) {
this.assignFormData();
}
}
@@ -145,7 +145,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
formArray.push(chartSlabInfo);
// Iterate for every slab in chartSlab
const chartIncentiveControl = chartDetailControl.controls['chartSlabs']['controls'][j];
const chartIncentiveControl = (chartDetailControl.controls['chartSlabs'] as UntypedFormArray).controls[j];
// Iterate to input all the incentive for particular chart slab
this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => {
@@ -158,8 +158,8 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
chartIncentiveDetail.attributeName,
Validators.required
],
attribureValue: [
chartIncentiveDetail.attribureValue,
attributeValue: [
chartIncentiveDetail.attributeValue,
Validators.required
],
conditionType: [
@@ -175,7 +175,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
Validators.required
]
});
const newFormArray = chartIncentiveControl['controls']['incentives'] as UntypedFormArray;
const newFormArray = (chartIncentiveControl as UntypedFormGroup).controls['incentives'] as UntypedFormArray;
newFormArray.push(incentiveInfo);
});
});
@@ -183,8 +183,8 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
}
getChartsDetailsData() {
this.chartDetailData.forEach((chartData: any) => {
const chart = {
this.chartDetailData.forEach((chartData: ChartData) => {
const chart: Chart = {
endDate: chartData.endDate ? new Date(chartData.endDate) : '',
fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '',
isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount,
@@ -193,7 +193,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
chartSlabs: this.getChartSlabsData(chartData)
};
if (chartData.id) {
chart['id'] = chartData.id;
chart.id = chartData.id;
}
this.chartsDetail.push(chart);
});
@@ -213,7 +213,17 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
}
chartSlabData.forEach((eachChartSlabData: any) => {
const chartSlab = {
const chartSlab: {
id?: any;
periodType: any;
amountRangeFrom: any;
amountRangeTo: any;
annualInterestRate: any;
description: any;
fromPeriod: any;
toPeriod: any;
incentives: any[];
} = {
periodType: eachChartSlabData.periodType.id,
amountRangeFrom: eachChartSlabData.amountRangeFrom,
amountRangeTo: eachChartSlabData.amountRangeTo,
@@ -221,7 +231,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
description: eachChartSlabData.description ? eachChartSlabData.description : '',
fromPeriod: eachChartSlabData.fromPeriod,
toPeriod: eachChartSlabData.toPeriod,
incentives: this.getIncentivesData(chartSlabData)
incentives: this.getIncentivesData(eachChartSlabData)
};
if (eachChartSlabData.id) {
chartSlab['id'] = eachChartSlabData.id;
@@ -468,3 +478,28 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
return fixedDepositProductInterestRateChart;
}
}
interface ChartData {
id?: number;
endDate?: string;
fromDate?: string;
isPrimaryGroupingByAmount: boolean;
name: string;
description: string;
chartSlabs: ChartSlab[];
}
interface ChartSlab {
periodType?: string;
fromPeriod?: number;
toPeriod?: number;
amountRangeFrom?: number;
amountRangeTo?: number;
annualInterestRate?: number;
description?: string;
}
interface Chart extends Omit<ChartData, 'endDate' | 'fromDate'> {
endDate: Date | string;
fromDate: Date | string;
}
@@ -378,7 +378,7 @@
<div class="flex-fill layout-row">
<span class="flex-47">{{ 'labels.inputs.Repayment Strategy' | translate }}:</span>
<span class="flex-53" class="repayment-strategy">{{
<span class="flex-53 repayment-strategy">{{
loanProduct.transactionProcessingStrategyName | translateKey: 'catalogs'
}}</span>
</div>
@@ -563,7 +563,7 @@
<span class="flex-53">{{ loanProduct.canUseForTopup | yesNo }}</span>
</div>
<h3 class="mat-h3" class="flex-fill">{{ 'labels.heading.Interest Recalculation' | translate }}</h3>
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Interest Recalculation' | translate }}</h3>
<mat-divider [inset]="true"></mat-divider>
@@ -212,7 +212,7 @@
<span class="flex-48 hide-lt-md"></span>
<div style="display: flex; justify-content: flex-start; width: 100%">
<div class="full-width-flex">
<div *ngIf="isAdvancedTransactionProcessingStrategy">
<h3 class="mat-h4 flex-98">{{ 'labels.inputs.Loan Charge-off behaviour' | translate }}</h3>
-2
View File
@@ -21,14 +21,12 @@
<fa-icon
(click)="arrowBooleansToggle(0); $event.stopPropagation()"
*ngIf="!arrowBooleans[0]"
style="z-index: 1000"
icon="arrow-down"
size="md"
></fa-icon>
<fa-icon
(click)="arrowBooleansToggle(0); $event.stopPropagation()"
*ngIf="arrowBooleans[0]"
style="z-index: 1000"
icon="arrow-up"
size="md"
></fa-icon>
@@ -145,7 +145,7 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
formArray.push(chartSlabInfo);
// Iterate for every slab in chartSlab
const chartIncentiveControl = chartDetailControl.controls['chartSlabs']['controls'][j];
const chartIncentiveControl = (chartDetailControl.controls['chartSlabs'] as UntypedFormArray).controls[j];
// Iterate to input all the incentive for particular chart slab
this.chartsDetail[i].chartSlabs[j].incentives.forEach((chartIncentiveDetail: any) => {
@@ -175,7 +175,7 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
Validators.required
]
});
const newFormArray = chartIncentiveControl['controls']['incentives'] as UntypedFormArray;
const newFormArray = (chartIncentiveControl as UntypedFormGroup).controls['incentives'] as UntypedFormArray;
newFormArray.push(incentiveInfo);
});
});
@@ -184,7 +184,14 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
getChartsDetailsData() {
this.chartDetailData.forEach((chartData: any) => {
const chart = {
const chart: {
id?: any;
endDate: string | Date;
fromDate: string | Date;
isPrimaryGroupingByAmount: any;
name: any;
chartSlabs: any[];
} = {
endDate: chartData.endDate ? new Date(chartData.endDate) : '',
fromDate: chartData.fromDate ? new Date(chartData.fromDate) : '',
isPrimaryGroupingByAmount: chartData.isPrimaryGroupingByAmount,
@@ -212,7 +219,17 @@ export class RecurringDepositProductInterestRateChartStepComponent implements On
}
chartSlabData.forEach((eachChartSlabData: any) => {
const chartSlab = {
const chartSlab: {
id?: any;
periodType: any;
amountRangeFrom: any;
amountRangeTo: any;
annualInterestRate: any;
description: any;
fromPeriod: any;
toPeriod: any;
incentives: any[];
} = {
periodType: eachChartSlabData.periodType.id,
amountRangeFrom: eachChartSlabData.amountRangeFrom,
amountRangeTo: eachChartSlabData.amountRangeTo,
@@ -13,7 +13,7 @@ import { SelectOption } from '../common-models/select-option.model';
import { Dates } from 'app/core/utils/dates';
import { GlobalConfiguration } from 'app/system/configurations/global-configurations-tab/configuration.model';
import * as XLSX from 'xlsx';
import * as ExcelJS from 'exceljs';
import { AlertService } from 'app/core/alert/alert.service';
/**
@@ -251,7 +251,7 @@ export class RunReportComponent implements OnInit {
formattedResponse[newKey] = value;
break;
case 'select':
formattedResponse[newKey] = value['id'];
formattedResponse[newKey] = (value as { id: string | number })['id'];
break;
case 'date':
if (this.isTableReport()) {
@@ -339,18 +339,46 @@ export class RunReportComponent implements OnInit {
});
}
exportToXLS(reportName: string, csvData: any, displayedColumns: string[]): void {
async exportToXLS(reportName: string, csvData: any, displayedColumns: string[]): Promise<void> {
const fileName = `${reportName}.xlsx`;
// Format data for ExcelJS
const data = csvData.map((object: any) => {
const row = {};
const row: Record<string, any> = {};
for (let i = 0; i < displayedColumns.length; i++) {
row[displayedColumns[i]] = object.row[i];
}
return row;
});
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, { header: displayedColumns });
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'report');
XLSX.writeFile(wb, fileName);
// Create workbook and worksheet
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('report');
// Add header
worksheet.addRow(displayedColumns);
// Add data rows
data.forEach((rowObj: any) => {
worksheet.addRow(displayedColumns.map((col) => rowObj[col]));
});
// Write to buffer and trigger download
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
// Native download logic (no FileSaver)
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}, 0);
}
}
@@ -14,7 +14,7 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen
import { environment } from 'environments/environment';
import { ProgressBarService } from 'app/core/progress-bar/progress-bar.service';
import * as XLSX from 'xlsx';
import * as ExcelJS from 'exceljs';
/**
* Table and SMS Component
@@ -143,16 +143,33 @@ export class TableAndSmsComponent implements OnChanges {
exportToXLS(): void {
const fileName = `${this.dataObject.report.name}.xlsx`;
const data = this.csvData.map((object: any) => {
const row = {};
const row: { [key: string]: any } = {};
for (let i = 0; i < this.displayedColumns.length; i++) {
row[this.displayedColumns[i]] = object.row[i];
}
return row;
});
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(data, { header: this.displayedColumns });
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Report');
XLSX.writeFile(wb, fileName);
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Report');
// Add header row
worksheet.addRow(this.displayedColumns);
// Add data rows
data.forEach((rowObj: any) => {
worksheet.addRow(this.displayedColumns.map((col) => rowObj[col]));
});
workbook.xlsx.writeBuffer().then((buffer: any) => {
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'filename.xlsx';
a.click();
URL.revokeObjectURL(url);
});
}
/**
@@ -7,6 +7,15 @@ import { SettingsService } from 'app/settings/settings.service';
import { Currency } from 'app/shared/models/general.model';
import { SystemService } from 'app/system/system.service';
type TransactionCommandType = 'holdamount' | 'blockaccount' | 'blockdeposit' | 'blockwithdrawal';
interface TransactionType {
holdamount: boolean;
blockaccount: boolean;
blockdeposit: boolean;
blockwithdrawal: boolean;
}
@Component({
selector: 'mifosx-manage-savings-account',
templateUrl: './manage-savings-account.component.html',
@@ -22,16 +31,11 @@ export class ManageSavingsAccountComponent implements OnInit {
manageSavingsAccountForm: UntypedFormGroup;
/** Savings Account Id */
savingAccountId: string;
transactionCommand: string;
transactionCommand: TransactionCommandType;
reasonOptions: any = [];
transactionType: {
holdamount: boolean;
blockaccount: boolean;
blockdeposit: boolean;
blockwithdrawal: boolean;
} = {
transactionType: TransactionType = {
holdamount: false,
blockaccount: false,
blockdeposit: false,
@@ -130,7 +134,7 @@ export class ManageSavingsAccountComponent implements OnInit {
submit() {
let command = '';
let payload = {};
let payload: { transactionAmount?: number; [key: string]: any } = {};
if (this.transactionType.holdamount) {
const manageSavingsAccountFormData = this.manageSavingsAccountForm.value;
@@ -68,7 +68,9 @@ export class SavingAccountActionsComponent {
this.currency = data.savingsAccountActionData.currency;
}
});
const name = this.route.snapshot.params['name'];
this.actions[name] = true;
const name = this.route.snapshot.params['name'] as string;
if (name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -66,7 +66,7 @@ export class SavingsAccountTransactionsComponent implements OnInit {
}
});
this.transactionCommand = this.route.snapshot.params['name'].toLowerCase();
this.transactionType[this.transactionCommand] = true;
this.transactionType[this.transactionCommand as 'deposit' | 'withdrawal'] = true;
this.savingAccountId = this.route.snapshot.params['savingAccountId'];
}
@@ -85,7 +85,7 @@ export class SavingsAccountViewComponent implements OnInit {
taskPermissionName: 'CREATE_ACCOUNTTRANSFER'
});
}
if (this.savingsAccountData.externalId && environment.interbankTransfers === 'true') {
if (this.savingsAccountData.externalId && environment.interbankTransfers) {
this.buttonConfig.addOption({
name: 'Interbank Transfer',
taskPermissionName: 'CREATE_ACCOUNTTRANSFER'
@@ -38,8 +38,7 @@
</mat-form-field>
<div class="flex-fill">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75">
(click)="addPaymentDetails()">
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
<mat-slide-toggle>
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
@@ -0,0 +1,15 @@
import { Component, Input } from '@angular/core';
/* eslint-disable @angular-eslint/component-selector */
/* eslint-disable @angular-eslint/prefer-standalone */
@Component({
selector: 'ngx-mat-datetime-picker',
template: `
<mat-datepicker-toggle [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
`,
standalone: false
})
export class DatetimePickerStubComponent {
@Input() enableMeridian: boolean = true;
}
@@ -50,14 +50,12 @@
<mat-label>{{ formfield.label }}</mat-label>
<input
matInput
[ngxMatDatetimePicker]="datetimePicker"
type="datetime-local"
[min]="formfield.minDate"
[max]="formfield.maxDate"
[formControlName]="formfield.controlName"
[required]="formfield.required"
/>
<mat-datepicker-toggle matSuffix [for]="datetimePicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #datetimePicker [enableMeridian]="true"></ngx-mat-datetime-picker>
<mat-error *ngIf="form.controls[formfield.controlName].hasError('required')">
{{ formfield.label }} {{ 'labels.commons.is' | translate }}
<strong>{{ 'labels.commons.required' | translate }}</strong>
@@ -1,13 +1,25 @@
import { FormfieldBase } from './formfield-base';
interface DatepickerOptions {
minDate?: Date;
maxDate?: Date;
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
type?: string;
}
export class DatepickerBase extends FormfieldBase {
controlType = 'datepicker';
minDate: Date;
maxDate: Date;
constructor(options: {} = {}) {
constructor(options: DatepickerOptions = {}) {
super(options);
this.minDate = options['minDate'] || new Date(2000, 0, 1);
this.maxDate = options['maxDate'] || new Date();
this.minDate = options.minDate || new Date(2000, 0, 1);
this.maxDate = options.maxDate || new Date();
}
}
@@ -1,13 +1,29 @@
import { FormfieldBase } from './formfield-base';
// Define the base options interface based on FormfieldBase requirements
interface FormfieldBaseOptions {
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
// Extend the base options for DateTimePicker
interface DateTimePickerOptions extends FormfieldBaseOptions {
minDate?: Date;
maxDate?: Date;
}
export class DateTimepickerBase extends FormfieldBase {
controlType = 'datetimepicker';
minDate: Date;
maxDate: Date;
constructor(options: {} = {}) {
constructor(options: DateTimePickerOptions = {}) {
super(options);
this.minDate = options['minDate'] || new Date(2000, 0, 1);
this.maxDate = options['maxDate'] || new Date();
this.minDate = options.minDate || new Date(2000, 0, 1);
this.maxDate = options.maxDate || new Date();
}
}
@@ -1,11 +1,25 @@
import { FormfieldBase } from './formfield-base';
interface InputBaseOptions extends FormfieldBaseOptions {
type?: string;
[key: string]: any;
}
interface FormfieldBaseOptions {
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
export class InputBase extends FormfieldBase {
controlType = 'input';
type: string;
constructor(options: {} = {}) {
constructor(options: InputBaseOptions = {}) {
super(options);
this.type = options['type'] || 'text';
this.type = options.type || 'text';
}
}
@@ -1,15 +1,27 @@
import { FormfieldBase } from './formfield-base';
interface SelectOption {
label: string;
value: string;
data: {}[];
}
interface SelectBaseOptions {
options?: SelectOption;
controlType?: string;
controlName?: string;
label?: string;
value?: any;
required?: boolean;
order?: number;
}
export class SelectBase extends FormfieldBase {
controlType = 'select';
options: {
label: string;
value: string;
data: {}[];
};
options: SelectOption;
constructor(options: {} = {}) {
constructor(options: SelectBaseOptions = {}) {
super(options);
this.options = options['options'];
this.options = options.options || { label: '', value: '', data: [] };
}
}
+11 -6
View File
@@ -36,7 +36,7 @@ import { EntityDatatableTabComponent } from './tabs/entity-datatable-tab/entity-
import { DatatableSingleRowComponent } from './tabs/entity-datatable-tab/datatable-single-row/datatable-single-row.component';
import { DatatableMultiRowComponent } from './tabs/entity-datatable-tab/datatable-multi-row/datatable-multi-row.component';
import { SvgIconComponent } from './svg-icon/svg-icon.component';
import { NgxMatDatetimePickerModule, NgxMatNativeDateModule } from '@angular-material-components/datetime-picker';
// import { NgxMatDatetimePickerModule, NgxMatNativeDateModule } from '@angular-material-components/datetime-picker';
import { ViewJournalEntryComponent } from './accounting/view-journal-entry/view-journal-entry.component';
import { ViewJournalEntryTransactionComponent } from './accounting/view-journal-entry-transaction/view-journal-entry-transaction.component';
import { AccountNumberComponent } from './account-number/account-number.component';
@@ -51,6 +51,7 @@ import { LongTextComponent } from './long-text/long-text.component';
import { DropdownComponent } from './dropdown/dropdown.component';
import { InputAmountComponent } from './input-amount/input-amount.component';
import { InputPasswordComponent } from './input-password/input-password.component';
import { DatetimePickerStubComponent } from './datetime-picker-stub/datetime-picker-stub.component'; // import Datetime Picker Stub
/**
* Shared Module
@@ -65,9 +66,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
ReactiveFormsModule,
TranslateModule,
PipesModule,
DirectivesModule,
NgxMatDatetimePickerModule,
NgxMatNativeDateModule
DirectivesModule
// NgxMatDatetimePickerModule,
// NgxMatNativeDateModule
],
declarations: [
FormfieldComponent,
@@ -108,7 +109,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
LongTextComponent,
DropdownComponent,
InputAmountComponent,
InputPasswordComponent
InputPasswordComponent,
DatetimePickerStubComponent // temporarily added stub for datetime picker
],
exports: [
FileUploadComponent,
@@ -143,7 +146,9 @@ import { InputPasswordComponent } from './input-password/input-password.componen
ThemeToggleComponent,
LongTextComponent,
DropdownComponent,
InputAmountComponent
InputAmountComponent,
DatetimePickerStubComponent // Export stub for datetime picker
]
})
export class SharedModule {}
@@ -44,6 +44,8 @@ export class SharesAccountActionsComponent {
*/
constructor(private route: ActivatedRoute) {
const name = this.route.snapshot.params['name'];
this.actions[name] = true;
if (name && name in this.actions) {
this.actions[name as keyof typeof this.actions] = true;
}
}
}
@@ -8,31 +8,48 @@ import { PopoverService } from '../../configuration-wizard/popover/popover.servi
import { ConfigurationWizardService } from '../../configuration-wizard/configuration-wizard.service';
import { SystemService } from '../system.service';
interface Permission {
code: string;
id: number;
selected: boolean;
grouping?: string;
}
interface PermissionGroup {
permissions: Permission[];
}
interface PermissionData {
[key: string]: PermissionGroup;
}
interface SubmitPermissionData {
permissions: {
[key: string]: boolean;
};
}
@Component({
selector: 'mifosx-configure-maker-checker-tasks',
templateUrl: './configure-maker-checker-tasks.component.html',
styleUrls: ['./configure-maker-checker-tasks.component.scss']
})
export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewInit {
permissionsData: any;
permissionsData: Permission[] = [];
groupings: string[] = [];
currentGrouping = '';
tempPermissionUIData: PermissionData = {};
permissions: PermissionGroup = { permissions: [] };
formData = {};
isDisabled = true;
newEntry: any;
selectedItem = '';
previousGrouping = '';
checkboxesChanged: Boolean = false;
currentGrouping: string;
formGroup: UntypedFormGroup;
backupform: UntypedFormGroup;
permissions: {
permissions: { code: string; id: number }[];
};
tempPermissionUIData: {
permissions: { code: string }[];
}[];
/* Reference of edit button */
@ViewChild('buttonEdit') buttonEdit: ElementRef<any>;
/* Template for popover on edit button */
@@ -95,29 +112,33 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
});
}
setMakerCheckerTask() {
this.tempPermissionUIData = [
{
permissions: []
}
];
for (const i in this.permissionsData) {
if (this.permissionsData[i]) {
if (this.permissionsData[i].grouping !== this.currentGrouping) {
this.currentGrouping = this.permissionsData[i].grouping;
this.groupings.push(this.currentGrouping);
this.tempPermissionUIData[this.currentGrouping] = { permissions: [] };
}
const temp = { code: this.permissionsData[i].code, id: i, selected: this.permissionsData[i].selected };
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
setMakerCheckerTask(): void {
this.tempPermissionUIData = {};
for (const permission of this.permissionsData) {
if (permission.grouping !== this.currentGrouping) {
this.currentGrouping = permission.grouping || '';
this.groupings.push(this.currentGrouping);
this.tempPermissionUIData[this.currentGrouping] = { permissions: [] };
}
const temp: Permission = {
code: permission.code,
id: permission.id,
selected: permission.selected
};
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
}
}
showPermissions(grouping: string) {
this.permissions = this.tempPermissionUIData[grouping];
this.selectedItem = grouping;
this.previousGrouping = grouping;
showPermissions(grouping: string): void {
const group = this.tempPermissionUIData[grouping];
if (group) {
this.permissions = group;
this.selectedItem = grouping;
this.previousGrouping = grouping;
}
}
permissionName = function (name: any) {
@@ -175,17 +196,20 @@ export class ConfigureMakerCheckerTasksComponent implements OnInit, AfterViewIni
this.formGroup.controls.roster.disable();
}
submit() {
const value = this.formGroup.get('roster').value;
const data = {};
const permissionData = {
submit(): void {
const value = this.formGroup.get('roster')?.value;
const permissionData: SubmitPermissionData = {
permissions: {}
};
for (let i = 0; i < value.length; i++) {
data[value[i].code] = value[i].selected;
if (Array.isArray(value)) {
value.forEach((item) => {
if (item.code && typeof item.selected === 'boolean') {
permissionData.permissions[item.code] = item.selected;
}
});
}
permissionData.permissions = data;
this.formGroup.controls.roster.disable();
this.formGroup.get('roster')?.disable();
this.checkboxesChanged = false;
this.isDisabled = true;
this.systemService.updateMakerCheckerPermission(permissionData).subscribe((response: any) => {});
@@ -108,7 +108,7 @@
<br />
<div class="layout-row-wrap responsive-column">
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }}<span style="color: red">*</span></p>
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }}<span class="red">*</span></p>
<button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>
@@ -108,7 +108,7 @@
<br />
<div class="layout-row-wrap responsive-column">
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }} <span style="color: red">*</span></p>
<p class="mat-title flex-20">{{ 'labels.inputs.Events' | translate }} <span class="red">*</span></p>
<button mat-raised-button class="AddEventButton flex-20" type="button" color="primary" (click)="addEvent()">
<fa-icon icon="plus" class="m-r-10"></fa-icon>
@@ -9,7 +9,12 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
import { SystemService } from 'app/system/system.service';
import { JobStep } from './workflow-diagram/workflow-diagram.component';
export interface JobStep {
stepName: string;
stepDescription: string;
order: number;
}
@Component({
selector: 'mifosx-workflow-jobs',
@@ -21,7 +26,7 @@ export class WorkflowJobsComponent implements OnInit {
jobNameOptions: any = [];
jobStepsData: any = [];
jobAvailableStepsData: any = [];
jobAvailableStepsData: JobStep[] = [];
jobStepsDataBase: any = [];
jobStepName: String = null;
@@ -98,7 +98,7 @@
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill" ="48">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label>
<input matInput maxlength="255" required formControlName="text" />
<mat-error *ngIf="question.controls.text.hasError('required')">
@@ -74,7 +74,7 @@
</mat-error>
</mat-form-field>
<mat-form-field class="flex-fill" ="48">
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Text' | translate }}</mat-label>
<input matInput maxlength="255" required formControlName="text" />
<mat-error *ngIf="question.get('text').hasError('required')">
@@ -1,6 +1,6 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormGroup, Validators, FormArray } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import * as _ from 'lodash';
@@ -45,12 +45,14 @@ export class ViewRoleComponent implements OnInit {
backupform: UntypedFormGroup;
/** Temporarily stores Permission data */
tempPermissionUIData: {
permissions: { code: string }[];
}[];
[key: string]: {
permissions: { code: string; id: number; selected?: boolean }[];
};
} = {};
/** Stores permissions */
permissions: {
permissions: { code: string; id: number }[];
};
} = { permissions: [] };
/**
* Retrieves the roledetails data from `resolve`.
@@ -121,11 +123,7 @@ export class ViewRoleComponent implements OnInit {
* Groups the permissions based on rules
*/
groupRules() {
this.tempPermissionUIData = [
{
permissions: []
}
];
this.tempPermissionUIData = {};
for (const i in this.rolePermissionService.permissionUsageData) {
if (this.rolePermissionService.permissionUsageData[i]) {
if (this.rolePermissionService.permissionUsageData[i].grouping !== this.currentGrouping) {
@@ -135,7 +133,7 @@ export class ViewRoleComponent implements OnInit {
}
const temp = {
code: this.rolePermissionService.permissionUsageData[i].code,
id: i,
id: +i,
selected: this.rolePermissionService.permissionUsageData[i].selected
};
this.tempPermissionUIData[this.currentGrouping].permissions.push(temp);
@@ -177,7 +175,7 @@ export class ViewRoleComponent implements OnInit {
name = name || '';
// replace '_' with ' '
name = name.replace(/_/g, ' ');
// for reorts replace read with view
// for reports replace read with view
if (this.previousGrouping === 'report') {
name = name.replace(/READ/g, 'View');
}
@@ -185,7 +183,7 @@ export class ViewRoleComponent implements OnInit {
}
/**
* Backups the valued
* Backups the values
*/
backupCheckValues() {
this.backupform = _.cloneDeep(this.formGroup) as UntypedFormGroup;
@@ -220,7 +218,7 @@ export class ViewRoleComponent implements OnInit {
*/
submit() {
const value = this.formGroup.get('roster').value;
const data = {};
const data: { [key: string]: boolean } = {};
const permissionData = {
permissions: {}
};
@@ -238,8 +236,9 @@ export class ViewRoleComponent implements OnInit {
* Selects all the permission of a particular role
*/
selectAll() {
const roster = this.formGroup.get('roster') as FormArray;
for (let i = 0; i < this.permissions.permissions.length; i++) {
this.formGroup.controls.roster['controls'][this.permissions.permissions[i].id].patchValue({
roster.at(this.permissions.permissions[i].id).patchValue({
selected: true
});
}
@@ -249,8 +248,9 @@ export class ViewRoleComponent implements OnInit {
* Deselects all the permissions of a particular role
*/
deselectAll() {
const roster = this.formGroup.get('roster') as FormArray;
for (let i = 0; i < this.permissions.permissions.length; i++) {
this.formGroup.controls.roster['controls'][this.permissions.permissions[i].id].patchValue({
roster.at(this.permissions.permissions[i].id).patchValue({
selected: false
});
}
@@ -15,6 +15,12 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { TranslateService } from '@ngx-translate/core';
interface OfficeNode {
id: number;
name: string;
loans: any[];
}
@Component({
selector: 'mifosx-loan-approval',
templateUrl: './loan-approval.component.html',
@@ -32,7 +38,7 @@ export class LoanApprovalComponent {
/** Row Selection Data */
selection: SelectionModel<any>;
/** Map data */
idToNodeMap = {};
idToNodeMap: { [key: number]: OfficeNode } = {};
/** Grouped Office Data */
officesArray: any[];
/** List of Requests */
@@ -79,15 +85,15 @@ export class LoanApprovalComponent {
});
this.loans.forEach((loanEle: any) => {
if (loanEle.status.pendingApproval) {
let tempOffice = {};
let tempOffice: OfficeNode | undefined;
if (loanEle.clientOfficeId) {
tempOffice = this.idToNodeMap[loanEle.clientOfficeId];
tempOffice['loans'].push(loanEle);
} else {
if (loanEle.group) {
tempOffice = this.idToNodeMap[loanEle.group.officeId];
tempOffice['loans'].push(loanEle);
}
} else if (loanEle.group?.officeId) {
tempOffice = this.idToNodeMap[loanEle.group.officeId];
}
if (tempOffice) {
tempOffice.loans.push(loanEle);
}
}
});
@@ -15,6 +15,13 @@ import { SettingsService } from 'app/settings/settings.service';
import { Dates } from 'app/core/utils/dates';
import { TranslateService } from '@ngx-translate/core';
interface RescheduleFormData {
dateFormat: string;
locale: string;
approvedOnDate?: string;
rejectedOnDate?: string;
}
@Component({
selector: 'mifosx-reschedule-loan',
templateUrl: './reschedule-loan.component.html',
@@ -107,14 +114,14 @@ export class RescheduleLoanComponent {
const dateFormat = this.settingsService.dateFormat;
const transactionDate = this.dateUtils.formatDate(this.settingsService.businessDate, dateFormat);
const locale = this.settingsService.language.code;
const formData = {
const formData: RescheduleFormData = {
dateFormat,
locale
};
if (command === 'approve') {
formData['approvedOnDate'] = transactionDate;
formData.approvedOnDate = transactionDate;
} else {
formData['rejectedOnDate'] = transactionDate;
formData.rejectedOnDate = transactionDate;
}
const listSelectedAccounts = this.selection.selected;
this.batchRequests = [];