Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,8 @@ <h3 class="mat-h3 flex-fill">{{ 'labels.inputs.Configurable Terms and Settings'
}
}

@if (loanProductService.isLoanProduct && loanProduct.charges.length) {
<!-- Working Capital products may come back with `charges` absent or null when none are associated. -->
@if (loanProduct.charges?.length) {
<div class="flex-fill layout-row-wrap responsive-column">
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
<mat-divider [inset]="true"></mat-divider>
Expand Down Expand Up @@ -1000,40 +1001,43 @@ <h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
<tr mat-header-row *matHeaderRowDef="chargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: chargesDisplayedColumns"></tr>
</table>
<h3 class="mat-h3 flex-fill">{{ 'labels.inputs.Overdue Charges' | translate }}</h3>
<mat-divider [inset]="true"></mat-divider>
<table
class="mat-elevation-z1 flex-100"
mat-table
[dataSource]="loanProduct.charges | chargesPenaltyFilter: true"
>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.name + ', ' + overdueCharge.currency.displaySymbol }}
</td>
</ng-container>
<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Charge Type' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeCalculationType.value | translateKey: 'catalogs' }}
</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.amount | formatNumber }}
</td>
</ng-container>
<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeTimeType.value | translateKey: 'catalogs' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="chargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: chargesDisplayedColumns"></tr>
</table>
<!-- Working Capital products do not support penalties yet. -->
@if (loanProductService.isLoanProduct) {
<h3 class="mat-h3 flex-fill">{{ 'labels.inputs.Overdue Charges' | translate }}</h3>
<mat-divider [inset]="true"></mat-divider>
<table
class="mat-elevation-z1 flex-100"
mat-table
[dataSource]="loanProduct.charges | chargesPenaltyFilter: true"
>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.name + ', ' + overdueCharge.currency.displaySymbol }}
</td>
</ng-container>
<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Charge Type' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeCalculationType.value | translateKey: 'catalogs' }}
</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.amount | formatNumber }}
</td>
</ng-container>
<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeTimeType.value | translateKey: 'catalogs' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="chargesDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: chargesDisplayedColumns"></tr>
</table>
}
</div>
}
@if (isAdvancedPaymentAllocation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,22 +113,18 @@
<mifosx-loan-product-terms-step [loanProductsTemplate]="loanProductsTemplate"></mifosx-loan-product-terms-step>
</mat-step>

@if (loanProductService.isLoanProduct) {
<mat-step>
<ng-template matStepLabel
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.CHARGES' | translate }}</ng-template
>
<mat-step>
<ng-template matStepLabel
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.CHARGES' | translate }}</ng-template
>

<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductsTemplate"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="
loanProductService.isLoanProduct ? loanProductSettingsForm.get('multiDisburseLoan') : null
"
>
</mifosx-loan-product-charges-step>
</mat-step>
}
<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductsTemplate"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="loanProductService.isLoanProduct ? loanProductSettingsForm.get('multiDisburseLoan') : null"
>
</mifosx-loan-product-charges-step>
</mat-step>

@if (isAdvancedPaymentStrategy) {
<mat-step [stepControl]="loanIncomeCapitalizationForm">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ export class CreateLoanProductClassicComponent extends LoanProductBaseComponent
...this.loanProductCurrencyStep.loanProductCurrency,
...this.loanProductTermsStep.loanProductTerms,
...this.loanProductSettingsStep.loanProductSettings,
...this.loanProductChargesStep.loanProductCharges,
...this.loanProductAccountingStep.loanProductAccounting
};
loanProduct['paymentAllocation'] = this.paymentAllocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,22 +113,18 @@
<mifosx-loan-product-terms-step [loanProductsTemplate]="loanProductAndTemplate"></mifosx-loan-product-terms-step>
</mat-step>

@if (loanProductService.isLoanProduct) {
<mat-step completed>
<ng-template matStepLabel
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.CHARGES' | translate }}</ng-template
>
<mat-step completed>
<ng-template matStepLabel
><strong>{{ getProductTypeLabel(true) }} : </strong>{{ 'labels.inputs.CHARGES' | translate }}</ng-template
>

<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductAndTemplate"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="
loanProductService.isLoanProduct ? loanProductSettingsForm.get('multiDisburseLoan') : null
"
>
</mifosx-loan-product-charges-step>
</mat-step>
}
<mifosx-loan-product-charges-step
[loanProductsTemplate]="loanProductAndTemplate"
[currencyCode]="loanProductCurrencyForm.get('currencyCode')"
[multiDisburseLoan]="loanProductService.isLoanProduct ? loanProductSettingsForm.get('multiDisburseLoan') : null"
>
</mifosx-loan-product-charges-step>
</mat-step>

@if (isAdvancedPaymentStrategy) {
<mat-step [stepControl]="loanIncomeCapitalizationForm" completed>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ export class EditLoanProductComponent extends LoanProductBaseComponent implement
!this.loanProductCurrencyForm.pristine ||
!this.loanProductTermsForm.pristine ||
!this.loanProductSettingsForm.pristine ||
!(this.loanProductChargesStep?.pristine ?? true) ||
!(this.loanProductAccountingForm?.pristine ?? true) ||
this.wasPaymentAllocationChanged
);
Expand Down Expand Up @@ -397,6 +398,7 @@ export class EditLoanProductComponent extends LoanProductBaseComponent implement
...this.loanProductCurrencyStep.loanProductCurrency,
...this.loanProductTermsStep.loanProductTerms,
...this.loanProductSettingsStep.loanProductSettings,
...this.loanProductChargesStep.loanProductCharges,
...this.loanProductAccountingStep.loanProductAccounting
};
loanProduct['paymentAllocation'] = this.paymentAllocation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<mat-label>{{ 'labels.inputs.Charge' | translate }}</mat-label>
<mat-select #charge>
@for (
charge of chargeData | chargesFilter: chargesDataSource : currencyCode.value : multiDisburseLoan.value;
charge of chargeData | chargesFilter: chargesDataSource : currencyCode.value : multiDisburseLoan?.value;
track charge
) {
<mat-option [value]="charge">
Expand Down Expand Up @@ -76,86 +76,89 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>

<mat-divider class="flex-98"></mat-divider>

<div class="flex-98">
<h3 class="mat-h3">{{ 'labels.inputs.Overdue Charges' | translate }}</h3>
</div>

<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Overdue Charge' | translate }}</mat-label>
<mat-select #overdueCharge>
@for (
overdueCharge of overdueChargeData | chargesFilter: chargesDataSource : currencyCode.value;
track overdueCharge
) {
<mat-option [value]="overdueCharge">
{{ overdueCharge.name }}
</mat-option>
}
</mat-select>
</mat-form-field>

<div class="flex-48 align-center">
<button
type="button"
mat-raised-button
color="primary"
(click)="addCharge(overdueCharge)"
[disabled]="!overdueCharge.value"
<!-- Working Capital products do not support penalties yet, so the overdue block is Term Loan only. -->
@if (loanProductService.isLoanProduct) {
<mat-divider class="flex-98"></mat-divider>

<div class="flex-98">
<h3 class="mat-h3">{{ 'labels.inputs.Overdue Charges' | translate }}</h3>
</div>

<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Overdue Charge' | translate }}</mat-label>
<mat-select #overdueCharge>
@for (
overdueCharge of overdueChargeData | chargesFilter: chargesDataSource : currencyCode.value;
track overdueCharge
) {
<mat-option [value]="overdueCharge">
{{ overdueCharge.name }}
</mat-option>
}
</mat-select>
</mat-form-field>

<div class="flex-48 align-center">
<button
type="button"
mat-raised-button
color="primary"
(click)="addCharge(overdueCharge)"
[disabled]="!overdueCharge.value"
>
<fa-icon icon="plus" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Add' | translate }}
</button>
</div>

<table
class="flex-98 mat-elevation-z1"
mat-table
[dataSource]="chargesDataSource | chargesPenaltyFilter: true"
#overdueChargesTable
[hidden]="overdueChargesTable.dataSource.length === 0"
>
<fa-icon icon="plus" class="m-r-10"></fa-icon>
{{ 'labels.buttons.Add' | translate }}
</button>
</div>

<table
class="flex-98 mat-elevation-z1"
mat-table
[dataSource]="chargesDataSource | chargesPenaltyFilter: true"
#overdueChargesTable
[hidden]="overdueChargesTable.dataSource.length === 0"
>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.name + ', ' + overdueCharge.currency.displaySymbol }}
</td>
</ng-container>

<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeCalculationType.value | translateKey: 'catalogs' }}
</td>
</ng-container>

<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.amount | formatNumber }}
</td>
</ng-container>

<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeTimeType.value | translateKey: 'catalogs' }}
</td>
</ng-container>

<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
<button mat-icon-button color="warn" (click)="deleteCharge(overdueCharge)">
<fa-icon icon="trash"></fa-icon>
</button>
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.name + ', ' + overdueCharge.currency.displaySymbol }}
</td>
</ng-container>

<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeCalculationType.value | translateKey: 'catalogs' }}
</td>
</ng-container>

<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.amount | formatNumber }}
</td>
</ng-container>

<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Collected On' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
{{ overdueCharge.chargeTimeType.value | translateKey: 'catalogs' }}
</td>
</ng-container>

<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
<td mat-cell *matCellDef="let overdueCharge">
<button mat-icon-button color="warn" (click)="deleteCharge(overdueCharge)">
<fa-icon icon="trash"></fa-icon>
</button>
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
}
</div>

<div class="layout-row responsive-column align-center gap-2px margin-t">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class LoanProductChargesStepComponent extends LoanProductBaseComponent im
pristine = true;

ngOnInit() {
this.chargeData = this.loanProductsTemplate.chargeOptions;
this.chargeData = this.loanProductsTemplate.chargeOptions || [];
this.overdueChargeData = this.loanProductsTemplate.penaltyOptions
? this.loanProductsTemplate.penaltyOptions.filter(
(penalty: any) => penalty.chargeTimeType.code === 'chargeTimeType.overdueInstallment'
Expand Down
20 changes: 8 additions & 12 deletions src/app/products/loan-products/loan-products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,14 @@ export class LoanProducts {
const dateFormat: string = this.settingsService.dateFormat;
const locale: string = this.settingsService.language.code;

const loanProduct = this.loanProductService.isLoanProduct
? {
...loanProductData,
charges: (loanProductData.charges || []).map((charge: any) => ({ id: charge.id })),
dateFormat,
locale
}
: {
...loanProductData,
dateFormat,
locale
};
// Both product types accept the optional `charges` parameter as a list of `{ id }` references, and
// both replace the whole association list on update, so the mapping is shared.
const loanProduct = {
...loanProductData,
charges: (loanProductData.charges || []).map((charge: any) => ({ id: charge.id })),
dateFormat,
locale
};
// Remove unnecessary properties
delete loanProduct.allowAttributeConfiguration;
delete loanProduct.advancedAccountingRules;
Expand Down
Loading