feat: add Current Account module, DIP verification, charges integration, and translations
- Current Account module with full CRUD, transactions, charges, hold/release, block/unblock - Current Products management under Products module - DIP mobile number verification with real API call to /lookup/check - Sanctions verification dialog - Charges support for Current Account (chargeAppliesTo=5) in create/edit - Fixed permissions from SAVINGSACCOUNT to CURRENTACCOUNT across all current account components - Added all missing translation keys for Current Account in en-US.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
73aa69ee02
commit
0a32d7135e
@@ -170,6 +170,14 @@ export class CreateChargeComponent implements OnInit {
|
||||
this.chargeCalculationTypeData = this.chargesTemplateData.shareChargeCalculationTypeOptions;
|
||||
this.chargeTimeTypeData = this.chargesTemplateData.shareChargeTimeTypeOptions;
|
||||
break;
|
||||
case 5: // Current Account — uses same options as Savings
|
||||
this.chargeCalculationTypeData =
|
||||
this.chargesTemplateData.currentAccountChargeCalculationTypeOptions ||
|
||||
this.chargesTemplateData.savingsChargeCalculationTypeOptions;
|
||||
this.chargeTimeTypeData =
|
||||
this.chargesTemplateData.currentAccountChargeTimeTypeOptions ||
|
||||
this.chargesTemplateData.savingsChargeTimeTypeOptions;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -188,7 +196,7 @@ export class CreateChargeComponent implements OnInit {
|
||||
if (this.chargeForm.get('chargeTimeType').value !== 12 && chargeCalculationType.id === 5) {
|
||||
return false;
|
||||
}
|
||||
if (this.chargeForm.get('chargeAppliesTo').value === 2) {
|
||||
if (this.chargeForm.get('chargeAppliesTo').value === 2 || this.chargeForm.get('chargeAppliesTo').value === 5) {
|
||||
if (
|
||||
!(
|
||||
this.chargeForm.get('chargeTimeType').value === 5 ||
|
||||
@@ -216,7 +224,7 @@ export class CreateChargeComponent implements OnInit {
|
||||
chargeCalculationType === 4 ||
|
||||
chargeCalculationType === 5
|
||||
);
|
||||
} else if (chargeAppliesTo === 2) {
|
||||
} else if (chargeAppliesTo === 2 || chargeAppliesTo === 5) {
|
||||
return (chargeTimeType === 16 || chargeTimeType === 5) && chargeCalculationType === 2;
|
||||
} else if (chargeAppliesTo === 4) {
|
||||
return (chargeTimeType === 14 || chargeTimeType === 15) && chargeCalculationType === 2;
|
||||
@@ -248,6 +256,10 @@ export class CreateChargeComponent implements OnInit {
|
||||
this.chargeForm.removeControl('incomeAccountId');
|
||||
this.chargeForm.get('penalty').setValue(false);
|
||||
break;
|
||||
case 5: // Current Account — same as Savings
|
||||
this.chargeForm.removeControl('chargePaymentMode');
|
||||
this.chargeForm.removeControl('incomeAccountId');
|
||||
break;
|
||||
}
|
||||
this.chargeForm.get('chargeCalculationType').reset();
|
||||
this.chargeForm.get('chargeTimeType').reset();
|
||||
|
||||
@@ -154,6 +154,15 @@ export class EditChargeComponent implements OnInit {
|
||||
this.addFeeFrequency = false;
|
||||
break;
|
||||
}
|
||||
case 'Current Account': {
|
||||
this.chargeTimeTypeOptions =
|
||||
this.chargeData.currentAccountChargeTimeTypeOptions || this.chargeData.savingsChargeTimeTypeOptions;
|
||||
this.chargeCalculationTypeOptions =
|
||||
this.chargeData.currentAccountChargeCalculationTypeOptions ||
|
||||
this.chargeData.savingsChargeCalculationTypeOptions;
|
||||
this.addFeeFrequency = false;
|
||||
break;
|
||||
}
|
||||
case 'Shares': {
|
||||
this.chargeTimeTypeOptions = this.chargeData.shareChargeTimeTypeOptions;
|
||||
this.chargeCalculationTypeOptions = this.chargeData.shareChargeCalculationTypeOptions;
|
||||
|
||||
@@ -36,6 +36,7 @@ export enum ChargeAppliesToCode {
|
||||
ChargeAppliesToLoan = 'chargeAppliesTo.loan',
|
||||
ChargeAppliesToSavings = 'chargeAppliesTo.savings',
|
||||
ChargeAppliesToShares = 'chargeAppliesTo.shares',
|
||||
ChargeAppliesToCurrentAccount = 'chargeAppliesTo.currentAccount',
|
||||
ChargeCalculationTypeFlat = 'chargeCalculationType.flat',
|
||||
ChargeCalculationTypePercentOfAmount = 'chargeCalculationType.percent.of.amount',
|
||||
ChargeCalculationTypePercentOfAmountAndInterest = 'chargeCalculationType.percent.of.amount.and.interest',
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<div class="container">
|
||||
<mat-stepper orientation="vertical" [linear]="false" class="mat-elevation-z8" labelPosition="bottom">
|
||||
<ng-template matStepperIcon="number"><fa-icon icon="pencil-alt" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="edit"><fa-icon icon="pencil-alt" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="done"><fa-icon icon="check" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="error"><fa-icon icon="exclamation-triangle" size="lg"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="preview"><fa-icon icon="eye" size="sm"></fa-icon></ng-template>
|
||||
|
||||
<mat-step [stepControl]="detailsForm">
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.DETAILS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-details-step></mifosx-saving-product-details-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="currencyForm">
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.CURRENCY' | translate }}</ng-template>
|
||||
<mifosx-saving-product-currency-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
></mifosx-saving-product-currency-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="termsForm">
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.TERMS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-terms-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
></mifosx-saving-product-terms-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="settingsForm">
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.SETTINGS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-settings-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
></mifosx-saving-product-settings-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.CHARGES' | translate }}</ng-template>
|
||||
<mifosx-saving-product-charges-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
[currencyCode]="currencyForm.get('currencyCode')"
|
||||
></mifosx-saving-product-charges-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="accountingForm">
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template>
|
||||
<mifosx-saving-product-accounting-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[isDormancyTrackingActive]="settingsForm.get('isDormancyTrackingActive')"
|
||||
[savingProductFormValid]="formValid"
|
||||
[allowOverdraft]="settingsForm.get('allowOverdraft')"
|
||||
></mifosx-saving-product-accounting-step>
|
||||
</mat-step>
|
||||
|
||||
@if (formValid) {
|
||||
<mat-step state="preview" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
|
||||
<mifosx-saving-product-preview-step
|
||||
[savingProductsTemplate]="currentProductsTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[savingProduct]="currentProduct"
|
||||
[taskPermission]="'CREATE_CURRENTPRODUCT'"
|
||||
(submitEvent)="submit()"
|
||||
></mifosx-saving-product-preview-step>
|
||||
</mat-step>
|
||||
}
|
||||
</mat-stepper>
|
||||
</div>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
fa-icon {
|
||||
position: relative;
|
||||
left: 5%;
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
import { Component, ViewChild, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SavingProductDetailsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-details-step/saving-product-details-step.component';
|
||||
import { SavingProductCurrencyStepComponent } from '../../saving-products/saving-product-stepper/saving-product-currency-step/saving-product-currency-step.component';
|
||||
import { SavingProductTermsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-terms-step/saving-product-terms-step.component';
|
||||
import { SavingProductSettingsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-settings-step/saving-product-settings-step.component';
|
||||
import { SavingProductChargesStepComponent } from '../../saving-products/saving-product-stepper/saving-product-charges-step/saving-product-charges-step.component';
|
||||
import { SavingProductAccountingStepComponent } from '../../saving-products/saving-product-stepper/saving-product-accounting-step/saving-product-accounting-step.component';
|
||||
import { SavingProductPreviewStepComponent } from '../../saving-products/saving-product-stepper/saving-product-preview-step/saving-product-preview-step.component';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Accounting } from 'app/core/utils/accounting';
|
||||
import { MatStepper, MatStepperIcon, MatStep, MatStepLabel } from '@angular/material/stepper';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-create-current-product',
|
||||
templateUrl: './create-current-product.component.html',
|
||||
styleUrls: ['./create-current-product.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatStepper,
|
||||
MatStepperIcon,
|
||||
FaIconComponent,
|
||||
MatStep,
|
||||
MatStepLabel,
|
||||
SavingProductDetailsStepComponent,
|
||||
SavingProductCurrencyStepComponent,
|
||||
SavingProductTermsStepComponent,
|
||||
SavingProductSettingsStepComponent,
|
||||
SavingProductChargesStepComponent,
|
||||
SavingProductAccountingStepComponent,
|
||||
SavingProductPreviewStepComponent
|
||||
]
|
||||
})
|
||||
export class CreateCurrentProductComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private productsService = inject(ProductsService);
|
||||
private router = inject(Router);
|
||||
private settingsService = inject(SettingsService);
|
||||
private accounting = inject(Accounting);
|
||||
|
||||
@ViewChild(SavingProductDetailsStepComponent, { static: true }) detailsStep: SavingProductDetailsStepComponent;
|
||||
@ViewChild(SavingProductCurrencyStepComponent, { static: true }) currencyStep: SavingProductCurrencyStepComponent;
|
||||
@ViewChild(SavingProductTermsStepComponent, { static: true }) termsStep: SavingProductTermsStepComponent;
|
||||
@ViewChild(SavingProductSettingsStepComponent, { static: true }) settingsStep: SavingProductSettingsStepComponent;
|
||||
@ViewChild(SavingProductChargesStepComponent, { static: true }) chargesStep: SavingProductChargesStepComponent;
|
||||
@ViewChild(SavingProductAccountingStepComponent, { static: true })
|
||||
accountingStep: SavingProductAccountingStepComponent;
|
||||
|
||||
currentProductsTemplate: any;
|
||||
accountingRuleData: string[] = [];
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentProductsTemplate: any }) => {
|
||||
this.currentProductsTemplate = data.currentProductsTemplate;
|
||||
});
|
||||
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
|
||||
}
|
||||
|
||||
get detailsForm() {
|
||||
return this.detailsStep.savingProductDetailsForm;
|
||||
}
|
||||
get currencyForm() {
|
||||
return this.currencyStep.savingProductCurrencyForm;
|
||||
}
|
||||
get termsForm() {
|
||||
return this.termsStep.savingProductTermsForm;
|
||||
}
|
||||
get settingsForm() {
|
||||
return this.settingsStep.savingProductSettingsForm;
|
||||
}
|
||||
get accountingForm() {
|
||||
return this.accountingStep.savingProductAccountingForm;
|
||||
}
|
||||
|
||||
get formValid() {
|
||||
return (
|
||||
this.detailsForm.valid &&
|
||||
this.currencyForm.valid &&
|
||||
this.termsForm.valid &&
|
||||
this.settingsForm.valid &&
|
||||
this.accountingForm.valid
|
||||
);
|
||||
}
|
||||
|
||||
get currentProduct() {
|
||||
return {
|
||||
...this.detailsStep.savingProductDetails,
|
||||
...this.currencyStep.savingProductCurrency,
|
||||
...this.termsStep.savingProductTerms,
|
||||
...this.settingsStep.savingProductSettings,
|
||||
...this.chargesStep.savingProductCharges,
|
||||
...this.accountingStep.savingProductAccounting
|
||||
};
|
||||
}
|
||||
|
||||
submit() {
|
||||
const product = {
|
||||
...this.currentProduct,
|
||||
charges: this.currentProduct.charges.map((charge: any) => ({ id: charge.id })),
|
||||
locale: this.settingsService.language.code
|
||||
};
|
||||
delete product.advancedAccountingRules;
|
||||
this.productsService.createCurrentProduct(product).subscribe((response: any) => {
|
||||
this.router.navigate(
|
||||
[
|
||||
'../',
|
||||
response.resourceId
|
||||
],
|
||||
{ relativeTo: this.route }
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProductsService } from '../products.service';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentProductResolver {
|
||||
private productsService = inject(ProductsService);
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||
const productId = route.parent.paramMap.get('productId');
|
||||
return this.productsService.getCurrentProduct(productId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProductsService } from '../products.service';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentProductsTemplateResolver {
|
||||
private productsService = inject(ProductsService);
|
||||
|
||||
resolve(): Observable<any> {
|
||||
return this.productsService.getCurrentProductsTemplate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="container m-b-20 layout-row align-end gap-20px">
|
||||
<div class="in-block">
|
||||
<button mat-raised-button color="primary" [routerLink]="['create']" *mifosxHasPermission="'CREATE_CURRENTPRODUCT'">
|
||||
<fa-icon icon="plus" class="m-r-10"></fa-icon>
|
||||
{{ 'labels.text.Create Current Product' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="layout-row">
|
||||
<mat-form-field class="flex-fill">
|
||||
<mat-label>{{ 'labels.inputs.Filter' | translate }}</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event.target.value)" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z8">
|
||||
<table mat-table [dataSource]="dataSource" matSort>
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Name' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let product">{{ product.name }}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="shortName">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Short Name' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let product">{{ product.shortName }}</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns" [routerLink]="[row.id]" class="select-row"></tr>
|
||||
</table>
|
||||
|
||||
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,7 @@
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
.select-row:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Component, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort, MatSortHeader } from '@angular/material/sort';
|
||||
import {
|
||||
MatTableDataSource,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow
|
||||
} from '@angular/material/table';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-current-products',
|
||||
templateUrl: './current-products.component.html',
|
||||
styleUrls: ['./current-products.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent,
|
||||
MatTable,
|
||||
MatSort,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatSortHeader,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow,
|
||||
MatPaginator
|
||||
]
|
||||
})
|
||||
export class CurrentProductsComponent implements OnInit {
|
||||
private route = inject(ActivatedRoute);
|
||||
|
||||
currentProductsData: any;
|
||||
displayedColumns: string[] = [
|
||||
'name',
|
||||
'shortName'
|
||||
];
|
||||
dataSource: MatTableDataSource<any>;
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentProducts: any }) => {
|
||||
this.currentProductsData = data.currentProducts;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource = new MatTableDataSource(this.currentProductsData);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
applyFilter(filterValue: string) {
|
||||
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProductsService } from '../products.service';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentProductsResolver {
|
||||
private productsService = inject(ProductsService);
|
||||
|
||||
resolve(): Observable<any> {
|
||||
return this.productsService.getCurrentProducts();
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProductsService } from '../../products.service';
|
||||
|
||||
@Injectable()
|
||||
export class CurrentProductAndTemplateResolver {
|
||||
private productsService = inject(ProductsService);
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||
const productId = route.paramMap.get('productId');
|
||||
return this.productsService.getCurrentProduct(productId, true);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
<div class="container">
|
||||
<mat-stepper orientation="vertical" [linear]="false" class="mat-elevation-z8" labelPosition="bottom">
|
||||
<ng-template matStepperIcon="number"><fa-icon icon="pencil-alt" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="edit"><fa-icon icon="pencil-alt" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="done"><fa-icon icon="check" size="sm"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="error"><fa-icon icon="exclamation-triangle" size="lg"></fa-icon></ng-template>
|
||||
<ng-template matStepperIcon="preview"><fa-icon icon="eye" size="sm"></fa-icon></ng-template>
|
||||
|
||||
<mat-step [stepControl]="detailsForm" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.DETAILS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-details-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
></mifosx-saving-product-details-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="currencyForm" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.CURRENCY' | translate }}</ng-template>
|
||||
<mifosx-saving-product-currency-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
></mifosx-saving-product-currency-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="termsForm" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.TERMS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-terms-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
></mifosx-saving-product-terms-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="settingsForm" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.SETTINGS' | translate }}</ng-template>
|
||||
<mifosx-saving-product-settings-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
></mifosx-saving-product-settings-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.CHARGES' | translate }}</ng-template>
|
||||
<mifosx-saving-product-charges-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
[currencyCode]="currencyForm.get('currencyCode')"
|
||||
></mifosx-saving-product-charges-step>
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="accountingForm" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.ACCOUNTING' | translate }}</ng-template>
|
||||
<mifosx-saving-product-accounting-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[isDormancyTrackingActive]="settingsForm.get('isDormancyTrackingActive')"
|
||||
[savingProductFormValid]="formValidAndNotPristine"
|
||||
[allowOverdraft]="settingsForm.get('allowOverdraft')"
|
||||
></mifosx-saving-product-accounting-step>
|
||||
</mat-step>
|
||||
|
||||
@if (formValidAndNotPristine) {
|
||||
<mat-step state="preview" completed>
|
||||
<ng-template matStepLabel>{{ 'labels.inputs.PREVIEW' | translate }}</ng-template>
|
||||
<mifosx-saving-product-preview-step
|
||||
[savingProductsTemplate]="currentProductAndTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[savingProduct]="currentProduct"
|
||||
[taskPermission]="'UPDATE_CURRENTPRODUCT'"
|
||||
(submitEvent)="submit()"
|
||||
></mifosx-saving-product-preview-step>
|
||||
</mat-step>
|
||||
}
|
||||
</mat-stepper>
|
||||
</div>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
fa-icon {
|
||||
position: relative;
|
||||
left: 5%;
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
import { Component, ViewChild, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SavingProductDetailsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-details-step/saving-product-details-step.component';
|
||||
import { SavingProductCurrencyStepComponent } from '../../saving-products/saving-product-stepper/saving-product-currency-step/saving-product-currency-step.component';
|
||||
import { SavingProductTermsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-terms-step/saving-product-terms-step.component';
|
||||
import { SavingProductSettingsStepComponent } from '../../saving-products/saving-product-stepper/saving-product-settings-step/saving-product-settings-step.component';
|
||||
import { SavingProductChargesStepComponent } from '../../saving-products/saving-product-stepper/saving-product-charges-step/saving-product-charges-step.component';
|
||||
import { SavingProductAccountingStepComponent } from '../../saving-products/saving-product-stepper/saving-product-accounting-step/saving-product-accounting-step.component';
|
||||
import { SavingProductPreviewStepComponent } from '../../saving-products/saving-product-stepper/saving-product-preview-step/saving-product-preview-step.component';
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Accounting } from 'app/core/utils/accounting';
|
||||
import { MatStepper, MatStepperIcon, MatStep, MatStepLabel } from '@angular/material/stepper';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-edit-current-product',
|
||||
templateUrl: './edit-current-product.component.html',
|
||||
styleUrls: ['./edit-current-product.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatStepper,
|
||||
MatStepperIcon,
|
||||
FaIconComponent,
|
||||
MatStep,
|
||||
MatStepLabel,
|
||||
SavingProductDetailsStepComponent,
|
||||
SavingProductCurrencyStepComponent,
|
||||
SavingProductTermsStepComponent,
|
||||
SavingProductSettingsStepComponent,
|
||||
SavingProductChargesStepComponent,
|
||||
SavingProductAccountingStepComponent,
|
||||
SavingProductPreviewStepComponent
|
||||
]
|
||||
})
|
||||
export class EditCurrentProductComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private productsService = inject(ProductsService);
|
||||
private router = inject(Router);
|
||||
private settingsService = inject(SettingsService);
|
||||
private accounting = inject(Accounting);
|
||||
|
||||
@ViewChild(SavingProductDetailsStepComponent, { static: true }) detailsStep: SavingProductDetailsStepComponent;
|
||||
@ViewChild(SavingProductCurrencyStepComponent, { static: true }) currencyStep: SavingProductCurrencyStepComponent;
|
||||
@ViewChild(SavingProductTermsStepComponent, { static: true }) termsStep: SavingProductTermsStepComponent;
|
||||
@ViewChild(SavingProductSettingsStepComponent, { static: true }) settingsStep: SavingProductSettingsStepComponent;
|
||||
@ViewChild(SavingProductChargesStepComponent, { static: true }) chargesStep: SavingProductChargesStepComponent;
|
||||
@ViewChild(SavingProductAccountingStepComponent, { static: true })
|
||||
accountingStep: SavingProductAccountingStepComponent;
|
||||
|
||||
currentProductAndTemplate: any;
|
||||
accountingRuleData: string[] = [];
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentProductAndTemplate: any }) => {
|
||||
this.currentProductAndTemplate = data.currentProductAndTemplate;
|
||||
});
|
||||
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
|
||||
}
|
||||
|
||||
get detailsForm() {
|
||||
return this.detailsStep.savingProductDetailsForm;
|
||||
}
|
||||
get currencyForm() {
|
||||
return this.currencyStep.savingProductCurrencyForm;
|
||||
}
|
||||
get termsForm() {
|
||||
return this.termsStep.savingProductTermsForm;
|
||||
}
|
||||
get settingsForm() {
|
||||
return this.settingsStep.savingProductSettingsForm;
|
||||
}
|
||||
get accountingForm() {
|
||||
return this.accountingStep.savingProductAccountingForm;
|
||||
}
|
||||
|
||||
get formValidAndNotPristine() {
|
||||
return (
|
||||
this.detailsForm.valid &&
|
||||
this.currencyForm.valid &&
|
||||
this.termsForm.valid &&
|
||||
this.settingsForm.valid &&
|
||||
this.accountingForm.valid &&
|
||||
(!this.detailsForm.pristine ||
|
||||
!this.currencyForm.pristine ||
|
||||
!this.termsForm.pristine ||
|
||||
!this.settingsForm.pristine ||
|
||||
!this.chargesStep.pristine ||
|
||||
!this.accountingForm.pristine)
|
||||
);
|
||||
}
|
||||
|
||||
get currentProduct() {
|
||||
return {
|
||||
...this.detailsStep.savingProductDetails,
|
||||
...this.currencyStep.savingProductCurrency,
|
||||
...this.termsStep.savingProductTerms,
|
||||
...this.settingsStep.savingProductSettings,
|
||||
...this.chargesStep.savingProductCharges,
|
||||
...this.accountingStep.savingProductAccounting
|
||||
};
|
||||
}
|
||||
|
||||
submit() {
|
||||
const product = {
|
||||
...this.currentProduct,
|
||||
charges: this.currentProduct.charges.map((charge: any) => ({ id: charge.id })),
|
||||
locale: this.settingsService.language.code
|
||||
};
|
||||
delete product.advancedAccountingRules;
|
||||
this.productsService.updateCurrentProduct(this.currentProductAndTemplate.id, product).subscribe((response: any) => {
|
||||
this.router.navigate(
|
||||
[
|
||||
'../../',
|
||||
response.resourceId
|
||||
],
|
||||
{ relativeTo: this.route }
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
<div class="layout-row align-end gap-2px responsive-column container m-b-20">
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
class="m-t-20"
|
||||
[routerLink]="['../edit']"
|
||||
*mifosxHasPermission="'UPDATE_CURRENTPRODUCT'"
|
||||
>
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon>{{ 'labels.buttons.Edit' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-container">
|
||||
<div class="responsive-column">
|
||||
<h2 class="mat-h2 flex-100">{{ currentProduct.name }}</h2>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Details' | translate }}</h3>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Short Name' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.shortName }}</span>
|
||||
</div>
|
||||
|
||||
@if (currentProduct.description) {
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Description' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.description }}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<h3 class="mat-h3 flex-fill">{{ 'labels.inputs.Currency' | translate }}</h3>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Currency' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.currency.name }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Decimal Places' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.currency.decimalPlaces }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Terms' | translate }}</h3>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Nominal Annual Interest' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.nominalAnnualInterestRate | formatNumber }} %</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Interest Compounding Period' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.interestCompoundingPeriodType?.value | translateKey: 'catalogs' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex-fill layout-row">
|
||||
<span class="flex-40">{{ 'labels.inputs.Interest Posting Period' | translate }}:</span>
|
||||
<span class="flex-60">{{ currentProduct.interestPostingPeriodType?.value | translateKey: 'catalogs' }}</span>
|
||||
</div>
|
||||
|
||||
@if (currentProduct.charges?.length) {
|
||||
<div class="layout-row-wrap responsive-column flex-fill">
|
||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
<table class="flex-fill mat-elevation-z1" mat-table [dataSource]="currentProduct.charges">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Name' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let charge">{{ charge.name + ', ' + charge.currency.displaySymbol }}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chargeCalculationType">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Type' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.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 charge">{{ charge.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 charge">{{ charge.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>
|
||||
}
|
||||
|
||||
<h3 class="mat-h3 flex-fill">{{ 'labels.heading.Accounting' | translate }}</h3>
|
||||
<mat-divider [inset]="true"></mat-divider>
|
||||
|
||||
<mifosx-view-savings-accounting-details
|
||||
class="flex-100"
|
||||
[accountingRule]="currentProduct.accountingRule"
|
||||
[accountingMappings]="currentProduct.accountingMappings"
|
||||
></mifosx-view-savings-accounting-details>
|
||||
</div>
|
||||
</div>
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
@use 'assets/styles/helper';
|
||||
@use 'assets/styles/colours' as *;
|
||||
|
||||
.tab-container {
|
||||
padding: 1%;
|
||||
margin: 1%;
|
||||
}
|
||||
|
||||
.mat-h3 {
|
||||
margin-top: 10px !important;
|
||||
font-weight: 300;
|
||||
color: $status-approved;
|
||||
}
|
||||
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-elevation-z1 {
|
||||
margin: 1em 0 1.5em;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 0 0 0.5em;
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { Accounting } from 'app/core/utils/accounting';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { MatDivider } from '@angular/material/divider';
|
||||
import {
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow
|
||||
} from '@angular/material/table';
|
||||
import { ViewSavingsAccountingDetailsComponent } from '../../../../shared/accounting/view-savings-accounting-details/view-savings-accounting-details.component';
|
||||
import { FormatNumberPipe } from '../../../../pipes/format-number.pipe';
|
||||
import { YesnoPipe } from '../../../../pipes/yesno.pipe';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-current-product-general-tab',
|
||||
templateUrl: './current-product-general-tab.component.html',
|
||||
styleUrls: ['./current-product-general-tab.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent,
|
||||
MatDivider,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatHeaderCellDef,
|
||||
MatHeaderCell,
|
||||
MatCellDef,
|
||||
MatCell,
|
||||
MatHeaderRowDef,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatRow,
|
||||
ViewSavingsAccountingDetailsComponent,
|
||||
FormatNumberPipe,
|
||||
YesnoPipe
|
||||
]
|
||||
})
|
||||
export class CurrentProductGeneralTabComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private accounting = inject(Accounting);
|
||||
|
||||
currentProduct: any;
|
||||
|
||||
chargesDisplayedColumns: string[] = [
|
||||
'name',
|
||||
'chargeCalculationType',
|
||||
'amount',
|
||||
'chargeTimeType'
|
||||
];
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentProduct: any }) => {
|
||||
this.currentProduct = data.currentProduct;
|
||||
});
|
||||
}
|
||||
|
||||
isCashOrAccrualAccounting(): boolean {
|
||||
return this.accounting.isCashOrAccrualAccounting(this.currentProduct.accountingRule);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<mat-card class="product-card">
|
||||
<mat-card-content>
|
||||
<nav mat-tab-nav-bar class="navigation-tabs" [tabPanel]="tabPanel">
|
||||
<a
|
||||
mat-tab-link
|
||||
[routerLink]="['./general']"
|
||||
routerLinkActive
|
||||
#general="routerLinkActive"
|
||||
[active]="general.isActive"
|
||||
>
|
||||
{{ 'labels.heading.General' | translate }}
|
||||
</a>
|
||||
</nav>
|
||||
<mat-tab-nav-panel #tabPanel>
|
||||
<router-outlet></router-outlet>
|
||||
</mat-tab-nav-panel>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
.product-card {
|
||||
margin: 0 auto;
|
||||
max-width: 80rem;
|
||||
width: 90%;
|
||||
padding: 0;
|
||||
|
||||
.navigation-tabs {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ActivatedRoute, RouterLinkActive, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { MatTabNav, MatTabLink, MatTabNavPanel } from '@angular/material/tabs';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-view-current-product',
|
||||
templateUrl: './view-current-product.component.html',
|
||||
styleUrls: ['./view-current-product.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatTabNav,
|
||||
MatTabLink,
|
||||
RouterLinkActive,
|
||||
MatTabNavPanel,
|
||||
RouterOutlet
|
||||
]
|
||||
})
|
||||
export class ViewCurrentProductComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
@@ -135,6 +135,17 @@ import { ShareProductDatatablesResolver } from './share-products/share-product-d
|
||||
import { ShareProductDatatableResolver } from './share-products/share-product-datatable.resolver';
|
||||
import { GlobalConfigurationsResolver } from 'app/system/configurations/global-configurations-tab/global-configurations.resolver';
|
||||
|
||||
/** Current Products */
|
||||
import { CurrentProductsComponent } from './current-products/current-products.component';
|
||||
import { CreateCurrentProductComponent } from './current-products/create-current-product/create-current-product.component';
|
||||
import { ViewCurrentProductComponent } from './current-products/view-current-product/view-current-product.component';
|
||||
import { EditCurrentProductComponent } from './current-products/edit-current-product/edit-current-product.component';
|
||||
import { CurrentProductGeneralTabComponent } from './current-products/view-current-product/current-product-general-tab/current-product-general-tab.component';
|
||||
import { CurrentProductsResolver } from './current-products/current-products.resolver';
|
||||
import { CurrentProductsTemplateResolver } from './current-products/current-products-template.resolver';
|
||||
import { CurrentProductResolver } from './current-products/current-product.resolver';
|
||||
import { CurrentProductAndTemplateResolver } from './current-products/edit-current-product/current-product-and-template.resolver';
|
||||
|
||||
/** Products Routes */
|
||||
const routes: Routes = [
|
||||
Route.withShell([
|
||||
@@ -283,6 +294,60 @@ const routes: Routes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'current-products',
|
||||
data: { title: 'Current Products', breadcrumb: 'Current Products' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: CurrentProductsComponent,
|
||||
resolve: {
|
||||
currentProducts: CurrentProductsResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: CreateCurrentProductComponent,
|
||||
data: { title: 'Create Current Product', breadcrumb: 'Create' },
|
||||
resolve: {
|
||||
currentProductsTemplate: CurrentProductsTemplateResolver
|
||||
}
|
||||
},
|
||||
{
|
||||
path: ':productId',
|
||||
data: { title: 'View Current Product', breadcrumb: 'productId', routeParamBreadcrumb: 'productId' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: ViewCurrentProductComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'general',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'general',
|
||||
data: { title: 'General', breadcrumb: 'General', routeParamBreadcrumb: false },
|
||||
component: CurrentProductGeneralTabComponent,
|
||||
resolve: {
|
||||
currentProduct: CurrentProductResolver
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'edit',
|
||||
component: EditCurrentProductComponent,
|
||||
data: { title: 'Edit Current Product', breadcrumb: 'Edit', routeParamBreadcrumb: false },
|
||||
resolve: {
|
||||
currentProductAndTemplate: CurrentProductAndTemplateResolver
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'share-products',
|
||||
data: { title: 'Share Products', breadcrumb: 'Share Products' },
|
||||
@@ -951,7 +1016,11 @@ const routes: Routes = [
|
||||
CollateralsResolver,
|
||||
CollateralTemplateResolver,
|
||||
DelinquencyRangeComponentsResolver,
|
||||
DelinquencyBucketComponentsResolver
|
||||
DelinquencyBucketComponentsResolver,
|
||||
CurrentProductsResolver,
|
||||
CurrentProductsTemplateResolver,
|
||||
CurrentProductResolver,
|
||||
CurrentProductAndTemplateResolver
|
||||
]
|
||||
})
|
||||
export class ProductsRoutingModule {}
|
||||
|
||||
@@ -83,6 +83,21 @@
|
||||
</mat-list-item>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-list-item [routerLink]="['current-products']" *mifosxHasPermission="'READ_CURRENTPRODUCT'">
|
||||
<div class="menu-list-item-content">
|
||||
<div class="menu-left-section" [routerLink]="['current-products']">
|
||||
<mat-icon matListIcon>
|
||||
<fa-icon icon="briefcase" size="sm"></fa-icon>
|
||||
</mat-icon>
|
||||
<div matLine>
|
||||
{{ 'labels.heading.Current Products' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</div>
|
||||
|
||||
<div #shareProducts>
|
||||
<mat-list-item [routerLink]="['share-products']" *mifosxHasPermission="'READ_SHAREPRODUCT'">
|
||||
<div class="menu-list-item-content">
|
||||
|
||||
@@ -74,6 +74,34 @@ export class ProductsService {
|
||||
return this.http.put(`/savingsproducts/${savingProductId}`, savingProduct);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Current products data
|
||||
*/
|
||||
getCurrentProducts(): Observable<any> {
|
||||
return this.http.get('/currentproducts');
|
||||
}
|
||||
|
||||
createCurrentProduct(currentProduct: any): Observable<any> {
|
||||
return this.http.post('/currentproducts', currentProduct);
|
||||
}
|
||||
|
||||
getCurrentProductsTemplate(): Observable<any> {
|
||||
return this.http.get('/currentproducts/template');
|
||||
}
|
||||
|
||||
getCurrentProduct(currentProductId: string, template: boolean = false): Observable<any> {
|
||||
const httpParams = new HttpParams().set('template', template.toString());
|
||||
return this.http.get(`/currentproducts/${currentProductId}`, { params: httpParams });
|
||||
}
|
||||
|
||||
updateCurrentProduct(currentProductId: string, currentProduct: any): Observable<any> {
|
||||
return this.http.put(`/currentproducts/${currentProductId}`, currentProduct);
|
||||
}
|
||||
|
||||
deleteCurrentProduct(currentProductId: string): Observable<any> {
|
||||
return this.http.delete(`/currentproducts/${currentProductId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Share products data
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user