Loan product using externalId input field

This commit is contained in:
Jose Alberto Hernandez
2024-11-28 11:37:58 -06:00
committed by Jose Alberto Hernandez
parent 1aed445156
commit 497fc3b9d9
9 changed files with 68 additions and 50 deletions
@@ -14,6 +14,11 @@
<span fxFlex="53%">{{ loanProduct.shortName }}</span> <span fxFlex="53%">{{ loanProduct.shortName }}</span>
</div> </div>
<div fxFlexFill *ngIf="loanProduct.externalId">
<span fxFlex="47%">{{ 'labels.inputs.External Id' | translate}}:</span>
<span fxFlex="53%">{{ loanProduct.externalId }}</span>
</div>
<div fxFlexFill *ngIf="loanProduct.fundId"> <div fxFlexFill *ngIf="loanProduct.fundId">
<span fxFlex="47%">{{ 'labels.inputs.Fund' | translate}}:</span> <span fxFlex="47%">{{ 'labels.inputs.Fund' | translate}}:</span>
<span fxFlex="53%">{{ loanProduct.fundName }}</span> <span fxFlex="53%">{{ loanProduct.fundName }}</span>
@@ -928,14 +933,14 @@
<ng-container matColumnDef="chargeOffReasonCodeValueId"> <ng-container matColumnDef="chargeOffReasonCodeValueId">
<th mat-header-cell *matHeaderCellDef> {{'labels.inputs.Charge-off reason' | translate}} </th> <th mat-header-cell *matHeaderCellDef> {{'labels.inputs.Charge-off reason' | translate}} </th>
<td mat-cell *matCellDef="let chargeOffReasonsToExpenseMapping"> <td mat-cell *matCellDef="let chargeOffReasonsToExpenseMapping">
{{ chargeOffReasonsToExpenseMapping.chargeOffReason.name }} {{ chargeOffReasonsToExpenseMapping.chargeOffReasonsCodeValue.name }}
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="expenseGLAccountId"> <ng-container matColumnDef="expenseGLAccountId">
<th mat-header-cell *matHeaderCellDef> {{'labels.inputs.Expense Account' | translate}} </th> <th mat-header-cell *matHeaderCellDef> {{'labels.inputs.Expense Account' | translate}} </th>
<td mat-cell *matCellDef="let chargeOffReasonsToExpenseMapping"> <td mat-cell *matCellDef="let chargeOffReasonsToExpenseMapping">
{{ chargeOffReasonsToExpenseMapping.expenseGLAccount.name }} ({{ chargeOffReasonsToExpenseMapping.chargeOffExpenseAccount.glCode }}) {{ chargeOffReasonsToExpenseMapping.chargeOffExpenseAccount.name }}
</td> </td>
</ng-container> </ng-container>
@@ -1,6 +1,6 @@
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { DelinquencyBucket, LoanProduct } from '../../models/loan-product.model'; import { DelinquencyBucket, LoanProduct } from '../../models/loan-product.model';
import {AccountingMapping, Charge, ChargeOffReasonsToExpenseMapping, ChargeToIncomeAccountMapping, GLAccount, PaymentChannelToFundSourceMapping, PaymentType, PaymentTypeOption} from '../../../../shared/models/general.model'; import {AccountingMapping, Charge, ChargeOffReasonsToGLAccountMapping, ChargeToIncomeAccountMapping, GLAccount, PaymentChannelToFundSourceMapping, PaymentType, PaymentTypeOption} from '../../../../shared/models/general.model';
import { AdvancePaymentAllocationData, CreditAllocation, PaymentAllocation } from '../../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; import { AdvancePaymentAllocationData, CreditAllocation, PaymentAllocation } from '../../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model';
import { LoanProducts } from '../../loan-products'; import { LoanProducts } from '../../loan-products';
import { CodeName, OptionData, StringEnumOptionData } from '../../../../shared/models/option-data.model'; import { CodeName, OptionData, StringEnumOptionData } from '../../../../shared/models/option-data.model';
@@ -36,7 +36,7 @@ export class LoanProductSummaryComponent implements OnInit, OnChanges {
paymentChannelToFundSourceMappings: PaymentChannelToFundSourceMapping[] = []; paymentChannelToFundSourceMappings: PaymentChannelToFundSourceMapping[] = [];
feeToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = []; feeToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = [];
penaltyToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = []; penaltyToIncomeAccountMappings: ChargeToIncomeAccountMapping[] = [];
chargeOffReasonsToExpenseMappings: ChargeOffReasonsToExpenseMapping[] = []; chargeOffReasonsToExpenseMappings: ChargeOffReasonsToGLAccountMapping[] = [];
constructor(private accounting: Accounting) { } constructor(private accounting: Accounting) { }
@@ -65,7 +65,7 @@ export class LoanProductSummaryComponent implements OnInit, OnChanges {
this.paymentChannelToFundSourceMappings = this.loanProduct.paymentChannelToFundSourceMappings || []; this.paymentChannelToFundSourceMappings = this.loanProduct.paymentChannelToFundSourceMappings || [];
this.feeToIncomeAccountMappings = this.loanProduct.feeToIncomeAccountMappings || []; this.feeToIncomeAccountMappings = this.loanProduct.feeToIncomeAccountMappings || [];
this.penaltyToIncomeAccountMappings = this.loanProduct.penaltyToIncomeAccountMappings || []; this.penaltyToIncomeAccountMappings = this.loanProduct.penaltyToIncomeAccountMappings || [];
this.chargeOffReasonsToExpenseMappings = this.loanProduct.chargeOffReasonsToExpenseMappings || []; this.chargeOffReasonsToExpenseMappings = this.loanProduct.chargeOffReasonToGLAccountMappings || [];
} else { } else {
this.accountingMappings = {}; this.accountingMappings = {};
@@ -133,14 +133,9 @@ export class LoanProductSummaryComponent implements OnInit, OnChanges {
} }
this.chargeOffReasonsToExpenseMappings = []; this.chargeOffReasonsToExpenseMappings = [];
if (this.loanProduct.chargeOffReasonsToExpenseMappings?.length > 0) { if (this.loanProduct.chargeOffReasonToGLAccountMappings?.length > 0) {
this.loanProduct.chargeOffReasonsToExpenseMappings.forEach((m: ChargeOffReasonsToExpenseMapping) => { this.loanProduct.chargeOffReasonToGLAccountMappings.forEach((m: ChargeOffReasonsToGLAccountMapping) => {
this.chargeOffReasonsToExpenseMappings.push({ this.chargeOffReasonsToExpenseMappings.push(m);
chargeOffReasonCodeValueId: m.chargeOffReasonCodeValueId,
chargeOffReason: this.optionDataLookUp(m.chargeOffReasonCodeValueId, this.loanProductsTemplate.chargeOffReasonOptions),
expenseGLAccountId: m.expenseGLAccountId,
expenseGLAccount: this.glAccountLookUp(m.expenseGLAccountId, expenseAccountData)
});
}); });
} }
} }
@@ -343,7 +338,7 @@ export class LoanProductSummaryComponent implements OnInit, OnChanges {
return (this.loanProduct.paymentChannelToFundSourceMappings?.length > 0 return (this.loanProduct.paymentChannelToFundSourceMappings?.length > 0
|| this.loanProduct.feeToIncomeAccountMappings?.length > 0 || this.loanProduct.feeToIncomeAccountMappings?.length > 0
|| this.loanProduct.penaltyToIncomeAccountMappings?.length > 0 || this.loanProduct.penaltyToIncomeAccountMappings?.length > 0
|| this.loanProduct.chargeOffReasonsToExpenseMappings?.length > 0); || this.loanProduct.chargeOffReasonToGLAccountMappings?.length > 0);
} }
getAccountingRuleName(value: string): string { getAccountingRuleName(value: string): string {
@@ -342,8 +342,6 @@
{{'labels.buttons.Add' | translate}} {{'labels.buttons.Add' | translate}}
</button> </button>
</div> </div>
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="chargeOffReasonsToExpenseMappings.value" *ngIf="chargeOffReasonsToExpenseMappings.value.length !== 0"> <table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="chargeOffReasonsToExpenseMappings.value" *ngIf="chargeOffReasonsToExpenseMappings.value.length !== 0">
<ng-container matColumnDef="chargeOffReasonCodeValueId"> <ng-container matColumnDef="chargeOffReasonCodeValueId">
@@ -8,7 +8,7 @@ import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.componen
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
import {ChargeOffReasonsToExpenseMapping} from '../../../../shared/models/general.model'; import { ChargeOffReasonsToGLAccountMapping } from 'app/shared/models/general.model';
@Component({ @Component({
selector: 'mifosx-loan-product-accounting-step', selector: 'mifosx-loan-product-accounting-step',
@@ -107,8 +107,8 @@ export class LoanProductAccountingStepComponent implements OnInit {
this.formBuilder.array((this.loanProductsTemplate.penaltyToIncomeAccountMappings || []).map((penaltyIncome: any) => this.formBuilder.array((this.loanProductsTemplate.penaltyToIncomeAccountMappings || []).map((penaltyIncome: any) =>
({ chargeId: penaltyIncome.charge.id, incomeAccountId: penaltyIncome.incomeAccount.id })))); ({ chargeId: penaltyIncome.charge.id, incomeAccountId: penaltyIncome.incomeAccount.id }))));
this.loanProductAccountingForm.setControl('chargeOffReasonsToExpenseMappings', this.loanProductAccountingForm.setControl('chargeOffReasonsToExpenseMappings',
this.formBuilder.array((this.loanProductsTemplate.chargeOffReasonsToExpenseMappings || []).map((m: ChargeOffReasonsToExpenseMapping) => this.formBuilder.array((this.loanProductsTemplate.chargeOffReasonsToExpenseMappings || []).map((m: ChargeOffReasonsToGLAccountMapping) =>
({ chargeOffReasonCodeValueId: m.chargeOffReasonCodeValueId, expenseGLAccountId: m.expenseGLAccountId })))); ({ chargeOffReasonCodeValueId: m.chargeOffReasonsCodeValue.id, expenseGLAccountId: m.chargeOffExpenseAccount.id }))));
} }
} }
@@ -324,25 +324,27 @@ export class LoanProductAccountingStepComponent implements OnInit {
} }
getChargeOffReasonExpenseFormfields(values?: any) { getChargeOffReasonExpenseFormfields(values?: any) {
const formfields: FormfieldBase[] = [ if (values != null) {
new SelectBase({ const formfields: FormfieldBase[] = [
controlName: 'chargeOffReasonCodeValueId', new SelectBase({
label: 'Charge-off reason', controlName: 'chargeOffReasonCodeValueId',
value: values ? values.chargeOffReasonCodeValueId : this.chargeOffReasonOptions[0].id, label: 'Charge-off reason',
options: { label: 'name', value: 'id', data: this.chargeOffReasonOptions }, value: values ? values.chargeOffReasonCodeValueId : this.chargeOffReasonOptions[0].id,
required: true, options: { label: 'name', value: 'id', data: this.chargeOffReasonOptions },
order: 1 required: true,
}), order: 1
new SelectBase({ }),
controlName: 'expenseGLAccountId', new SelectBase({
label: 'Expense Account', controlName: 'expenseGLAccountId',
value: values ? values.expenseGLAccountId : this.expenseAccountData[0].id, label: 'Expense Account',
options: { label: 'name', value: 'id', data: this.expenseAccountData }, value: values ? values.expenseGLAccountId : this.expenseAccountData[0].id,
required: true, options: { label: 'name', value: 'id', data: this.expenseAccountData },
order: 2 required: true,
}) order: 2
]; })
return formfields; ];
return formfields;
}
} }
get isAccountingAccrualBased() { get isAccountingAccrualBased() {
@@ -2,7 +2,7 @@
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" fxLayoutAlign.gt-sm="start center"> <div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" fxLayoutAlign.gt-sm="start center">
<mat-form-field fxFlex="72%"> <mat-form-field fxFlex="98%">
<mat-label>{{'labels.inputs.Product Name' | translate}}</mat-label> <mat-label>{{'labels.inputs.Product Name' | translate}}</mat-label>
<input matInput formControlName="name" matTooltip="{{ 'tooltips.Product name is a unique identifier' | translate}}" required> <input matInput formControlName="name" matTooltip="{{ 'tooltips.Product name is a unique identifier' | translate}}" required>
<mat-error> <mat-error>
@@ -10,7 +10,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="24%"> <mat-form-field fxFlex="48%">
<mat-label>{{'labels.inputs.Short Name' | translate}}</mat-label> <mat-label>{{'labels.inputs.Short Name' | translate}}</mat-label>
<input matInput formControlName="shortName" maxlength="4" matTooltip="{{ 'tooltips.Short name is a unique identifier' | translate}}" required> <input matInput formControlName="shortName" maxlength="4" matTooltip="{{ 'tooltips.Short name is a unique identifier' | translate}}" required>
<mat-error> <mat-error>
@@ -18,6 +18,11 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>{{'labels.inputs.External Id' | translate}}</mat-label>
<input matInput formControlName="externalId" matTooltip="{{ 'tooltips.External Id is a unique identifier' | translate}}">
</mat-form-field>
<mat-form-field fxFlex="48%"> <mat-form-field fxFlex="48%">
<mat-label>{{'labels.inputs.Fund' | translate}}</mat-label> <mat-label>{{'labels.inputs.Fund' | translate}}</mat-label>
<mat-select matTooltip="{{ 'tooltips.Loan products may be assigned' | translate}}" formControlName="fundId"> <mat-select matTooltip="{{ 'tooltips.Loan products may be assigned' | translate}}" formControlName="fundId">
@@ -42,6 +42,7 @@ export class LoanProductDetailsStepComponent implements OnInit {
'name': this.loanProductsTemplate.name, 'name': this.loanProductsTemplate.name,
'shortName': this.loanProductsTemplate.shortName, 'shortName': this.loanProductsTemplate.shortName,
'description': this.loanProductsTemplate.description, 'description': this.loanProductsTemplate.description,
'externalId': this.loanProductsTemplate.externalId,
'fundId': this.loanProductsTemplate.fundId, 'fundId': this.loanProductsTemplate.fundId,
'startDate': this.loanProductsTemplate.startDate && new Date(this.loanProductsTemplate.startDate), 'startDate': this.loanProductsTemplate.startDate && new Date(this.loanProductsTemplate.startDate),
'closeDate': this.loanProductsTemplate.closeDate && new Date(this.loanProductsTemplate.closeDate), 'closeDate': this.loanProductsTemplate.closeDate && new Date(this.loanProductsTemplate.closeDate),
@@ -54,6 +55,7 @@ export class LoanProductDetailsStepComponent implements OnInit {
'name': ['', Validators.required], 'name': ['', Validators.required],
'shortName': ['', Validators.required], 'shortName': ['', Validators.required],
'description': [''], 'description': [''],
'externalId': [''],
'fundId': [''], 'fundId': [''],
'startDate': [''], 'startDate': [''],
'closeDate': [''], 'closeDate': [''],
@@ -1,4 +1,4 @@
import {AccountingMapping, ChargeOffReasonsToExpenseMapping, ChargeToIncomeAccountMapping, Currency, PaymentChannelToFundSourceMapping} from 'app/shared/models/general.model'; import {AccountingMapping, ChargeOffReasonsToGLAccountMapping, ChargeToIncomeAccountMapping, Currency, PaymentChannelToFundSourceMapping} from 'app/shared/models/general.model';
import { OptionData, StringEnumOptionData } from 'app/shared/models/option-data.model'; import { OptionData, StringEnumOptionData } from 'app/shared/models/option-data.model';
import { CreditAllocation, PaymentAllocation } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; import { CreditAllocation, PaymentAllocation } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model';
@@ -125,7 +125,7 @@ export interface LoanProduct {
paymentChannelToFundSourceMappings?: PaymentChannelToFundSourceMapping[]; paymentChannelToFundSourceMappings?: PaymentChannelToFundSourceMapping[];
feeToIncomeAccountMappings?: ChargeToIncomeAccountMapping[]; feeToIncomeAccountMappings?: ChargeToIncomeAccountMapping[];
penaltyToIncomeAccountMappings?: ChargeToIncomeAccountMapping[]; penaltyToIncomeAccountMappings?: ChargeToIncomeAccountMapping[];
chargeOffReasonsToExpenseMappings?: ChargeOffReasonsToExpenseMapping[]; chargeOffReasonToGLAccountMappings?: ChargeOffReasonsToGLAccountMapping[];
enableAccrualActivityPosting?: boolean; enableAccrualActivityPosting?: boolean;
supportedInterestRefundTypes?: StringEnumOptionData[]; supportedInterestRefundTypes?: StringEnumOptionData[];
} }
+5 -3
View File
@@ -74,9 +74,11 @@ export class FooterComponent implements OnInit, OnDestroy {
this.getConfigurations(); this.getConfigurations();
this.server = this.settingsService.server; this.server = this.settingsService.server;
this.versionService.getBackendInfo().subscribe((data: any) => { this.versionService.getBackendInfo().subscribe((data: any) => {
const buildVersion: string = data.git.build.version.split('-'); if (data.git && data.git.build && data.git.build.version) {
this.versions.fineract.version = buildVersion[0]; const buildVersion: string = data.git.build.version.split('-');
this.versions.fineract.hash = buildVersion[1]; this.versions.fineract.version = buildVersion[0];
this.versions.fineract.hash = buildVersion[1];
}
}); });
} }
} }
+14 -5
View File
@@ -39,11 +39,20 @@ export interface PaymentChannelToFundSourceMapping {
fundSourceAccount: AccountingMapping; fundSourceAccount: AccountingMapping;
} }
export interface ChargeOffReasonsToExpenseMapping { export interface ChargeOffReasonsToGLAccountMapping {
chargeOffReasonCodeValueId: number; chargeOffReasonCodeValueId?: number;
expenseGLAccountId: number; chargeOffReason? : OptionData;
chargeOffReason?: OptionData; chargeOffReasonsCodeValue?: ChargeOffReasonsCodeValue;
expenseGLAccount?: AccountingMapping; chargeOffExpenseAccount?: AccountingMapping;
}
export interface ChargeOffReasonsCodeValue {
active: boolean;
description: string;
id: number;
mandatory: boolean;
name: string;
position?: number;
} }
export interface PaymentType { export interface PaymentType {