feat: add create recurring deposit product component (#934)
Fixes: #193
This commit is contained in:
@@ -42,6 +42,7 @@ import { CreateTaxComponentComponent } from './manage-tax-components/create-tax-
|
||||
import { EditTaxComponentComponent } from './manage-tax-components/edit-tax-component/edit-tax-component.component';
|
||||
import { ViewTaxGroupComponent } from './manage-tax-groups/view-tax-group/view-tax-group.component';
|
||||
import { ShareProductsDividendsComponent } from './share-products/dividends-share-product/dividends.components';
|
||||
import { CreateRecurringDepositProductComponent } from './recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component';
|
||||
|
||||
/** Custom Resolvers */
|
||||
import { LoanProductsResolver } from './loan-products/loan-products.resolver';
|
||||
@@ -301,7 +302,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'recurring-deposit-products',
|
||||
data: { title: extract('Recurring Deposit Products'), breadcrumb: 'Recurring Deposit Products' },
|
||||
data: { title: extract('Recurring Deposit Products'), breadcrumb: 'Recurring Deposit Products' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
@@ -324,6 +325,14 @@ const routes: Routes = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: CreateRecurringDepositProductComponent,
|
||||
data: { title: extract('Create Recurring Deposit Product'), breadcrumb: 'Create' },
|
||||
resolve: {
|
||||
recurringDepositProductsTemplate: RecurringDepositProductsTemplateResolver
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
/** Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DatePipe, CommonModule } from '@angular/common';
|
||||
import { MatFormFieldModule, MatSelectModule, MatOptionModule } from '@angular/material';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
/** Custom Modules */
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ProductsRoutingModule } from './products-routing.module';
|
||||
import { PipesModule } from 'app/pipes/pipes.module';
|
||||
import { DirectivesModule } from '../directives/directives.module';
|
||||
|
||||
/** Custom Components */
|
||||
import { ProductsComponent } from './products.component';
|
||||
@@ -71,11 +74,18 @@ import { FloatingRatePeriodDialogComponent } from './floating-rates/floating-rat
|
||||
import { CreateTaxComponentComponent } from './manage-tax-components/create-tax-component/create-tax-component.component';
|
||||
import { EditTaxComponentComponent } from './manage-tax-components/edit-tax-component/edit-tax-component.component';
|
||||
import { EditChargeComponent } from './charges/edit-charge/edit-charge.component';
|
||||
import { MatFormFieldModule, MatSelectModule, MatOptionModule } from '@angular/material';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ViewTaxGroupComponent } from './manage-tax-groups/view-tax-group/view-tax-group.component';
|
||||
import { ShareProductsDividendsComponent } from './share-products/dividends-share-product/dividends.components';
|
||||
import { ViewRecurringDepositProductComponent } from './recurring-deposit-products/view-recurring-deposit-product/view-recurring-deposit-product.component';
|
||||
import { CreateRecurringDepositProductComponent } from './recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component';
|
||||
import { RecurringDepositProductAccountingStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component';
|
||||
import { RecurringDepositProductChargesStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component';
|
||||
import { RecurringDepositProductCurrencyStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component';
|
||||
import { RecurringDepositProductDetailsStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component';
|
||||
import { RecurringDepositProductInterestRateChartStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component';
|
||||
import { RecurringDepositProductPreviewStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component';
|
||||
import { RecurringDepositProductSettingsStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component';
|
||||
import { RecurringDepositProductTermsStepComponent } from './recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component';
|
||||
|
||||
/**
|
||||
* Products Module
|
||||
@@ -86,7 +96,8 @@ import { ViewRecurringDepositProductComponent } from './recurring-deposit-produc
|
||||
imports: [
|
||||
SharedModule,
|
||||
ProductsRoutingModule,
|
||||
PipesModule
|
||||
PipesModule,
|
||||
DirectivesModule
|
||||
],
|
||||
declarations: [
|
||||
ProductsComponent,
|
||||
@@ -155,7 +166,16 @@ import { ViewRecurringDepositProductComponent } from './recurring-deposit-produc
|
||||
ViewTaxGroupComponent,
|
||||
ShareProductsDividendsComponent,
|
||||
DepositProductIncentiveFormDialogComponent,
|
||||
ViewRecurringDepositProductComponent
|
||||
ViewRecurringDepositProductComponent,
|
||||
CreateRecurringDepositProductComponent,
|
||||
RecurringDepositProductAccountingStepComponent,
|
||||
RecurringDepositProductChargesStepComponent,
|
||||
RecurringDepositProductCurrencyStepComponent,
|
||||
RecurringDepositProductDetailsStepComponent,
|
||||
RecurringDepositProductInterestRateChartStepComponent,
|
||||
RecurringDepositProductPreviewStepComponent,
|
||||
RecurringDepositProductSettingsStepComponent,
|
||||
RecurringDepositProductTermsStepComponent
|
||||
],
|
||||
entryComponents: [
|
||||
DepositProductIncentiveFormDialogComponent,
|
||||
|
||||
@@ -276,4 +276,9 @@ export class ProductsService {
|
||||
const httpParams = new HttpParams().set('productId', productId);
|
||||
return this.http.get(`/interestratecharts`, {params: httpParams});
|
||||
}
|
||||
|
||||
createRecurringDepositProduct(recurringDepositProduct: string): Observable<any> {
|
||||
return this.http.post('/recurringdepositproducts', recurringDepositProduct);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-horizontal-stepper class="mat-elevation-z8" labelPosition="bottom" #recurringDepositProductStepper>
|
||||
|
||||
<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]="recurringDepositProductDetailsForm">
|
||||
|
||||
<ng-template matStepLabel>DETAILS</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-details-step></mifosx-recurring-deposit-product-details-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="recurringDepositProductCurrencyForm">
|
||||
|
||||
<ng-template matStepLabel>CURRENCY</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-currency-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate">
|
||||
</mifosx-recurring-deposit-product-currency-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="recurringDepositProductTermsForm">
|
||||
|
||||
<ng-template matStepLabel>TERMS</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-terms-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate">
|
||||
</mifosx-recurring-deposit-product-terms-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="recurringDepositProductSettingsForm">
|
||||
|
||||
<ng-template matStepLabel>SETTINGS</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-settings-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate">
|
||||
</mifosx-recurring-deposit-product-settings-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="recurringDepositProductInterestRateChartForm">
|
||||
|
||||
<ng-template matStepLabel>INTEREST RATE CHART</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-interest-rate-chart-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate">
|
||||
</mifosx-recurring-deposit-product-interest-rate-chart-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
|
||||
<ng-template matStepLabel>CHARGES</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-charges-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate"
|
||||
[currencyCode]="recurringDepositProductCurrencyForm.get('currencyCode')">
|
||||
</mifosx-recurring-deposit-product-charges-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="recurringDepositProductAccountingForm">
|
||||
|
||||
<ng-template matStepLabel>ACCOUNTING</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-accounting-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate" [accountingRuleData]="accountingRuleData"
|
||||
[recurringDepositProductFormValid]="recurringDepositProductFormValid">
|
||||
</mifosx-recurring-deposit-product-accounting-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step state="preview" *ngIf="recurringDepositProductFormValid" completed>
|
||||
|
||||
<ng-template matStepLabel>PREVIEW</ng-template>
|
||||
|
||||
<mifosx-recurring-deposit-product-preview-step
|
||||
[recurringDepositProductsTemplate]="recurringDepositProductsTemplate"
|
||||
[chartSlabsDisplayedColumns]="recurringDepositProductInterestRateChartStep.chartSlabsDisplayedColumns"
|
||||
[accountingRuleData]="accountingRuleData" [recurringDepositProduct]="recurringDepositProduct"
|
||||
(submit)="submit()">
|
||||
</mifosx-recurring-deposit-product-preview-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
</div>
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateRecurringDepositProductComponent } from './create-recurring-deposit-product.component';
|
||||
|
||||
describe('CreateRecurringDepositProductComponent', () => {
|
||||
let component: CreateRecurringDepositProductComponent;
|
||||
let fixture: ComponentFixture<CreateRecurringDepositProductComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CreateRecurringDepositProductComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateRecurringDepositProductComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { RecurringDepositProductDetailsStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component';
|
||||
import { RecurringDepositProductCurrencyStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component';
|
||||
import { RecurringDepositProductTermsStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component';
|
||||
import { RecurringDepositProductSettingsStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component';
|
||||
import { RecurringDepositProductInterestRateChartStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component';
|
||||
import { RecurringDepositProductChargesStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component';
|
||||
import { RecurringDepositProductAccountingStepComponent } from '../recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component';
|
||||
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-create-recurring-deposit-product',
|
||||
templateUrl: './create-recurring-deposit-product.component.html',
|
||||
styleUrls: ['./create-recurring-deposit-product.component.scss']
|
||||
})
|
||||
export class CreateRecurringDepositProductComponent implements OnInit {
|
||||
|
||||
@ViewChild(RecurringDepositProductDetailsStepComponent) recurringDepositProductDetailsStep: RecurringDepositProductDetailsStepComponent;
|
||||
@ViewChild(RecurringDepositProductCurrencyStepComponent) recurringDepositProductCurrencyStep: RecurringDepositProductCurrencyStepComponent;
|
||||
@ViewChild(RecurringDepositProductTermsStepComponent) recurringDepositProductTermsStep: RecurringDepositProductTermsStepComponent;
|
||||
@ViewChild(RecurringDepositProductSettingsStepComponent) recurringDepositProductSettingsStep: RecurringDepositProductSettingsStepComponent;
|
||||
@ViewChild(RecurringDepositProductInterestRateChartStepComponent) recurringDepositProductInterestRateChartStep: RecurringDepositProductInterestRateChartStepComponent;
|
||||
@ViewChild(RecurringDepositProductChargesStepComponent) recurringDepositProductChargesStep: RecurringDepositProductChargesStepComponent;
|
||||
@ViewChild(RecurringDepositProductAccountingStepComponent) recurringDepositProductAccountingStep: RecurringDepositProductAccountingStepComponent;
|
||||
|
||||
recurringDepositProductsTemplate: any;
|
||||
accountingRuleData = ['None', 'Cash'];
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private productsService: ProductsService,
|
||||
private router: Router) {
|
||||
this.route.data.subscribe((data: { recurringDepositProductsTemplate: any }) => {
|
||||
this.recurringDepositProductsTemplate = data.recurringDepositProductsTemplate;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
get recurringDepositProductDetailsForm() {
|
||||
return this.recurringDepositProductDetailsStep.recurringDepositProductDetailsForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductCurrencyForm() {
|
||||
return this.recurringDepositProductCurrencyStep.recurringDepositProductCurrencyForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductTermsForm() {
|
||||
return this.recurringDepositProductTermsStep.recurringDepositProductTermsForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductSettingsForm() {
|
||||
return this.recurringDepositProductSettingsStep.recurringDepositProductSettingsForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductInterestRateChartForm() {
|
||||
return this.recurringDepositProductInterestRateChartStep.recurringDepositProductInterestRateChartForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductAccountingForm() {
|
||||
return this.recurringDepositProductAccountingStep.recurringDepositProductAccountingForm;
|
||||
}
|
||||
|
||||
get recurringDepositProductFormValid() {
|
||||
return (
|
||||
this.recurringDepositProductDetailsForm.valid &&
|
||||
this.recurringDepositProductCurrencyForm.valid &&
|
||||
this.recurringDepositProductTermsForm.valid &&
|
||||
this.recurringDepositProductSettingsForm.valid &&
|
||||
this.recurringDepositProductInterestRateChartForm.valid &&
|
||||
this.recurringDepositProductAccountingForm.valid
|
||||
);
|
||||
}
|
||||
|
||||
get recurringDepositProduct() {
|
||||
return {
|
||||
...this.recurringDepositProductDetailsStep.recurringDepositProductDetails,
|
||||
...this.recurringDepositProductCurrencyStep.recurringDepositProductCurrency,
|
||||
...this.recurringDepositProductTermsStep.recurringDepositProductTerms,
|
||||
...this.recurringDepositProductSettingsStep.recurringDepositProductSettings,
|
||||
...this.recurringDepositProductInterestRateChartStep.recurringDepositProductInterestRateChart,
|
||||
...this.recurringDepositProductChargesStep.recurringDepositProductCharges,
|
||||
...this.recurringDepositProductAccountingStep.recurringDepositProductAccounting
|
||||
};
|
||||
}
|
||||
|
||||
submit() {
|
||||
// TODO: Update once language and date settings are setup
|
||||
let recurringDepositProduct = {
|
||||
...this.recurringDepositProduct,
|
||||
charges: this.recurringDepositProduct.charges.map((charge: any) => ({ id: charge.id })),
|
||||
locale: 'en' // locale required for depositAmount
|
||||
};
|
||||
if (!recurringDepositProduct.description) {
|
||||
recurringDepositProduct.description = '';
|
||||
}
|
||||
delete recurringDepositProduct.advancedAccountingRules;
|
||||
this.productsService.createRecurringDepositProduct(recurringDepositProduct)
|
||||
.subscribe((response: any) => {
|
||||
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
<form [formGroup]="recurringDepositProductAccountingForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-radio-group fxFlex="98%" fxLayout="row" fxLayoutGap="5%" fxLayout.lt-md="column"
|
||||
formControlName="accountingRule">
|
||||
<mat-radio-button *ngFor="let accountingRule of accountingRuleData; let i = index" [value]="i+1">
|
||||
{{ accountingRule }}
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<div *ngIf="recurringDepositProductAccountingForm.value.accountingRule === 2" fxFlexFill fxLayout="row wrap"
|
||||
fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Assets</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Saving reference</mat-label>
|
||||
<mat-select formControlName="savingsReferenceAccountId" required>
|
||||
<mat-option *ngFor="let assetAccount of assetAccountData" [value]="assetAccount.id">
|
||||
{{ assetAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Saving reference is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Liabilities</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Saving control</mat-label>
|
||||
<mat-select formControlName="savingsControlAccountId" required>
|
||||
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
|
||||
{{ liabilityAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Saving control is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Savings transfers in suspense</mat-label>
|
||||
<mat-select formControlName="transfersInSuspenseAccountId" required>
|
||||
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
|
||||
{{ liabilityAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Savings transfers in suspense is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Expenses</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Interest on savings</mat-label>
|
||||
<mat-select formControlName="interestOnSavingsAccountId" required>
|
||||
<mat-option *ngFor="let expenseAccount of expenseAccountData" [value]="expenseAccount.id">
|
||||
{{ expenseAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Interest on savings is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Income</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Income from fees</mat-label>
|
||||
<mat-select formControlName="incomeFromFeeAccountId" required>
|
||||
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
|
||||
{{ incomeAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Income from fees Repayments is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Income from penalties</mat-label>
|
||||
<mat-select formControlName="incomeFromPenaltyAccountId" required>
|
||||
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
|
||||
{{ incomeAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Income from penalties is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h3 fxFlex="23%" class="mat-h3">Advanced Accounting Rules</h3>
|
||||
|
||||
<mat-checkbox fxFlex="73%" formControlName="advancedAccountingRules"></mat-checkbox>
|
||||
|
||||
<div *ngIf="recurringDepositProductAccountingForm.value.advancedAccountingRules" fxFlexFill fxLayout="row wrap"
|
||||
fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<h4 fxFlex="33%" class="mat-h4">Configure Fund Sources for Payment Channels</h4>
|
||||
|
||||
<div fxFlex="63%">
|
||||
<button type="button" mat-raised-button color="primary"
|
||||
(click)="add('PaymentFundSource', paymentChannelToFundSourceMappings)">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="paymentChannelToFundSourceMappings.value"
|
||||
*ngIf="paymentChannelToFundSourceMappings.value.length !== 0">
|
||||
|
||||
<ng-container matColumnDef="paymentTypeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource">
|
||||
{{ paymentFundSource.paymentTypeId | find:paymentTypeData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="fundSourceAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource">
|
||||
{{ paymentFundSource.fundSourceAccountId | find:assetAccountData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource; let i = index">
|
||||
<button mat-icon-button color="primary"
|
||||
(click)="edit('PaymentFundSource', paymentChannelToFundSourceMappings, i)">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="delete(paymentChannelToFundSourceMappings, i)">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<h4 fxFlex="33%" class="mat-h4">Map Fees to Specific Income Accounts</h4>
|
||||
|
||||
<div fxFlex="63%">
|
||||
<button type="button" mat-raised-button color="primary"
|
||||
(click)="add('FeesIncome', feeToIncomeAccountMappings)">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="feeToIncomeAccountMappings.value"
|
||||
*ngIf="feeToIncomeAccountMappings.value.length !== 0">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Fees </th>
|
||||
<td mat-cell *matCellDef="let feesIncome">
|
||||
{{ feesIncome.chargeId | find:chargeData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incomeAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Income Account </th>
|
||||
<td mat-cell *matCellDef="let feesIncome">
|
||||
{{ feesIncome.incomeAccountId | find:incomeAccountData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let feesIncome; let i = index">
|
||||
<button mat-icon-button color="primary" (click)="edit('FeesIncome', feeToIncomeAccountMappings, i)">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="delete(feeToIncomeAccountMappings, i)">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<h4 fxFlex="33%" class="mat-h4">Map Penalties to Specific Income Accounts</h4>
|
||||
|
||||
<div fxFlex="63%">
|
||||
<button type="button" mat-raised-button color="primary"
|
||||
(click)="add('PenaltyIncome', penaltyToIncomeAccountMappings)">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="penaltyToIncomeAccountMappings.value"
|
||||
*ngIf="penaltyToIncomeAccountMappings.value.length !== 0">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Penalty </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome">
|
||||
{{ penaltyIncome.chargeId | find:penaltyData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incomeAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Income Account </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome">
|
||||
{{ penaltyIncome.incomeAccountId | find:incomeAccountData:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome; let i = index">
|
||||
<button mat-icon-button color="primary"
|
||||
(click)="edit('PenaltyIncome', penaltyToIncomeAccountMappings, i)">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="delete(penaltyToIncomeAccountMappings, i)">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext [disabled]="!recurringDepositProductFormValid">
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-elevation-z1 {
|
||||
margin: 1em 0 1.5em 0;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
mat-radio-group, h4 {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 1em 0 2em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductAccountingStepComponent } from './recurring-deposit-product-accounting-step.component';
|
||||
|
||||
describe('RecurringDepositProductAccountingStepComponent', () => {
|
||||
let component: RecurringDepositProductAccountingStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductAccountingStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductAccountingStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductAccountingStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, FormArray, Validators, FormControl } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material';
|
||||
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-accounting-step',
|
||||
templateUrl: './recurring-deposit-product-accounting-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-accounting-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductAccountingStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
@Input() accountingRuleData: any;
|
||||
@Input() recurringDepositProductFormValid: boolean;
|
||||
|
||||
recurringDepositProductAccountingForm: FormGroup;
|
||||
|
||||
chargeData: any;
|
||||
penaltyData: any;
|
||||
paymentTypeData: any;
|
||||
assetAccountData: any;
|
||||
incomeAccountData: any;
|
||||
expenseAccountData: any;
|
||||
liabilityAccountData: any;
|
||||
|
||||
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId', 'actions'];
|
||||
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId', 'actions'];
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
public dialog: MatDialog) {
|
||||
this.createrecurringDepositProductAccountingForm();
|
||||
this.setConditionalControls();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.chargeData = this.recurringDepositProductsTemplate.chargeOptions || [];
|
||||
this.penaltyData = this.recurringDepositProductsTemplate.penaltyOptions || [];
|
||||
this.paymentTypeData = this.recurringDepositProductsTemplate.paymentTypeOptions || [];
|
||||
this.assetAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
|
||||
this.incomeAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
|
||||
this.expenseAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
|
||||
this.liabilityAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
|
||||
}
|
||||
|
||||
createrecurringDepositProductAccountingForm() {
|
||||
this.recurringDepositProductAccountingForm = this.formBuilder.group({
|
||||
'accountingRule': [1]
|
||||
});
|
||||
}
|
||||
|
||||
setConditionalControls() {
|
||||
this.recurringDepositProductAccountingForm.get('accountingRule').valueChanges
|
||||
.subscribe((accountingRule: any) => {
|
||||
if (accountingRule === 2) {
|
||||
this.recurringDepositProductAccountingForm.addControl('savingsReferenceAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('savingsControlAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('transfersInSuspenseAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('interestOnSavingsAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('incomeFromFeeAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('incomeFromPenaltyAccountId', new FormControl('', Validators.required));
|
||||
this.recurringDepositProductAccountingForm.addControl('advancedAccountingRules', new FormControl(false));
|
||||
|
||||
this.recurringDepositProductAccountingForm.get('advancedAccountingRules').valueChanges
|
||||
.subscribe((advancedAccountingRules: boolean) => {
|
||||
if (advancedAccountingRules) {
|
||||
this.recurringDepositProductAccountingForm.addControl('paymentChannelToFundSourceMappings', this.formBuilder.array([]));
|
||||
this.recurringDepositProductAccountingForm.addControl('feeToIncomeAccountMappings', this.formBuilder.array([]));
|
||||
this.recurringDepositProductAccountingForm.addControl('penaltyToIncomeAccountMappings', this.formBuilder.array([]));
|
||||
} else {
|
||||
this.recurringDepositProductAccountingForm.removeControl('paymentChannelToFundSourceMappings');
|
||||
this.recurringDepositProductAccountingForm.removeControl('feeToIncomeAccountMappings');
|
||||
this.recurringDepositProductAccountingForm.removeControl('penaltyToIncomeAccountMappings');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.recurringDepositProductAccountingForm.removeControl('savingsReferenceAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('overdraftPortfolioControlId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('savingsControlAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('transfersInSuspenseAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('interestOnSavingsAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('writeOffAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('incomeFromFeeAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('incomeFromPenaltyAccountId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('incomeFromInterestId');
|
||||
this.recurringDepositProductAccountingForm.removeControl('advancedAccountingRules');
|
||||
this.recurringDepositProductAccountingForm.removeControl('escheatLiabilityId');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get paymentChannelToFundSourceMappings(): FormArray {
|
||||
return this.recurringDepositProductAccountingForm.get('paymentChannelToFundSourceMappings') as FormArray;
|
||||
}
|
||||
|
||||
get feeToIncomeAccountMappings(): FormArray {
|
||||
return this.recurringDepositProductAccountingForm.get('feeToIncomeAccountMappings') as FormArray;
|
||||
}
|
||||
|
||||
get penaltyToIncomeAccountMappings(): FormArray {
|
||||
return this.recurringDepositProductAccountingForm.get('penaltyToIncomeAccountMappings') as FormArray;
|
||||
}
|
||||
|
||||
add(formType: string, formArray: FormArray) {
|
||||
const data = { ...this.getData(formType), pristine: false };
|
||||
const dialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
formArray.push(response.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
edit(formType: string, formArray: FormArray, index: number) {
|
||||
const data = { ...this.getData(formType, formArray.at(index).value), layout: { addButtonText: 'Edit' } };
|
||||
const dialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
formArray.at(index).patchValue(response.data.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
delete(formArray: FormArray, index: number) {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `this` }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
formArray.removeAt(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getData(formType: string, values?: any) {
|
||||
switch (formType) {
|
||||
case 'PaymentFundSource': return { title: 'Configure Fund Sources for Payment Channels', formfields: this.getPaymentFundSourceFormfields(values) };
|
||||
case 'FeesIncome': return { title: 'Map Fees to Income Accounts', formfields: this.getFeesIncomeFormfields(values) };
|
||||
case 'PenaltyIncome': return { title: 'Map Penalties to Specific Income Accounts', formfields: this.getPenaltyIncomeFormfields(values) };
|
||||
}
|
||||
}
|
||||
|
||||
getPaymentFundSourceFormfields(values?: any) {
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'paymentTypeId',
|
||||
label: 'Payment Type',
|
||||
value: values ? values.paymentTypeId : this.paymentTypeData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.paymentTypeData },
|
||||
required: true,
|
||||
order: 1
|
||||
}),
|
||||
new SelectBase({
|
||||
controlName: 'fundSourceAccountId',
|
||||
label: 'Fund Source',
|
||||
value: values ? values.fundSourceAccountId : this.assetAccountData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.assetAccountData },
|
||||
required: true,
|
||||
order: 2
|
||||
})
|
||||
];
|
||||
return formfields;
|
||||
}
|
||||
|
||||
getFeesIncomeFormfields(values?: any) {
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'chargeId',
|
||||
label: 'Fees',
|
||||
value: values ? values.chargeId : this.chargeData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.chargeData },
|
||||
required: true,
|
||||
order: 1
|
||||
}),
|
||||
new SelectBase({
|
||||
controlName: 'incomeAccountId',
|
||||
label: 'Income Account',
|
||||
value: values ? values.incomeAccountId : this.incomeAccountData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.incomeAccountData },
|
||||
required: true,
|
||||
order: 2
|
||||
})
|
||||
];
|
||||
return formfields;
|
||||
}
|
||||
|
||||
getPenaltyIncomeFormfields(values?: any) {
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'chargeId',
|
||||
label: 'Penalty',
|
||||
value: values ? values.chargeId : this.penaltyData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.penaltyData },
|
||||
required: true,
|
||||
order: 1
|
||||
}),
|
||||
new SelectBase({
|
||||
controlName: 'incomeAccountId',
|
||||
label: 'Income Account',
|
||||
value: values ? values.incomeAccountId : this.incomeAccountData[0].id,
|
||||
options: { label: 'name', value: 'id', data: this.incomeAccountData },
|
||||
required: true,
|
||||
order: 2
|
||||
})
|
||||
];
|
||||
return formfields;
|
||||
}
|
||||
|
||||
get recurringDepositProductAccounting() {
|
||||
return this.recurringDepositProductAccountingForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Charge</mat-label>
|
||||
<mat-select #charge>
|
||||
<mat-option *ngFor="let charge of chargeData | chargesFilter:chargesDataSource:currencyCode.value"
|
||||
[value]="charge">
|
||||
{{ charge.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<div fxFlex="48%" fxFlexAlign="center">
|
||||
<button type="button" mat-raised-button color="primary" (click)="addCharge(charge)" [disabled]="!charge.value">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="chargesDataSource"
|
||||
[hidden]="chargesDataSource.length === 0">
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.name + ', ' + charge.currency.displaySymbol }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="chargeCalculationType">
|
||||
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.chargeCalculationType.value }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.amount }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="chargeTimeType">
|
||||
<th mat-header-cell *matHeaderCellDef> Collected On </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.chargeTimeType.value }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="action">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
<button mat-icon-button color="warn" (click)="deleteCharge(charge)">
|
||||
<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 fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mat-elevation-z1 {
|
||||
margin: 1em 0 1.5em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductChargesStepComponent } from './recurring-deposit-product-charges-step.component';
|
||||
|
||||
describe('RecurringDepositProductChargesStepComponent', () => {
|
||||
let component: RecurringDepositProductChargesStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductChargesStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductChargesStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductChargesStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-charges-step',
|
||||
templateUrl: './recurring-deposit-product-charges-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-charges-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductChargesStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
@Input() currencyCode: FormControl;
|
||||
|
||||
chargeData: any;
|
||||
|
||||
chargesDataSource: {}[];
|
||||
displayedColumns: string[] = ['name', 'chargeCalculationType', 'amount', 'chargeTimeType', 'action'];
|
||||
|
||||
constructor(public dialog: MatDialog) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.chargeData = this.recurringDepositProductsTemplate.chargeOptions;
|
||||
|
||||
this.chargesDataSource = [];
|
||||
|
||||
this.currencyCode.valueChanges.subscribe(() => this.chargesDataSource = []);
|
||||
}
|
||||
|
||||
addCharge(charge: any) {
|
||||
this.chargesDataSource = this.chargesDataSource.concat([charge.value]);
|
||||
charge.value = '';
|
||||
}
|
||||
|
||||
deleteCharge(charge: any) {
|
||||
const deleteChargeDialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `charge ${charge.name}` }
|
||||
});
|
||||
deleteChargeDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
this.chargesDataSource.splice(this.chargesDataSource.indexOf(charge), 1);
|
||||
this.chargesDataSource = this.chargesDataSource.concat([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get recurringDepositProductCharges() {
|
||||
return {
|
||||
charges: this.chargesDataSource
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<form [formGroup]="recurringDepositProductCurrencyForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Currency</mat-label>
|
||||
<mat-select formControlName="currencyCode" required>
|
||||
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
||||
{{ currency.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Currency is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Decimal Places</mat-label>
|
||||
<input type="number" matInput formControlName="digitsAfterDecimal" required>
|
||||
<mat-error>
|
||||
Decimal Places is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Currency in multiples of</mat-label>
|
||||
<input type="number" matInput formControlName="inMultiplesOf" required>
|
||||
<mat-error>
|
||||
Currency in multiples of is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductCurrencyStepComponent } from './recurring-deposit-product-currency-step.component';
|
||||
|
||||
describe('RecurringDepositProductCurrencyStepComponent', () => {
|
||||
let component: RecurringDepositProductCurrencyStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductCurrencyStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductCurrencyStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductCurrencyStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-currency-step',
|
||||
templateUrl: './recurring-deposit-product-currency-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-currency-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductCurrencyStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
|
||||
recurringDepositProductCurrencyForm: FormGroup;
|
||||
|
||||
currencyData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createrecurringDepositProductCurrencyForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.currencyData = this.recurringDepositProductsTemplate.currencyOptions;
|
||||
|
||||
this.recurringDepositProductCurrencyForm.patchValue({
|
||||
'currencyCode': this.currencyData[0].code,
|
||||
'digitsAfterDecimal': 2
|
||||
});
|
||||
}
|
||||
|
||||
createrecurringDepositProductCurrencyForm() {
|
||||
this.recurringDepositProductCurrencyForm = this.formBuilder.group({
|
||||
'currencyCode': ['', Validators.required],
|
||||
'digitsAfterDecimal': ['', Validators.required],
|
||||
'inMultiplesOf': ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
get recurringDepositProductCurrency() {
|
||||
return this.recurringDepositProductCurrencyForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<form [formGroup]="recurringDepositProductDetailsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Product Name</mat-label>
|
||||
<input matInput formControlName="name" required>
|
||||
<mat-error>
|
||||
Product Name is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Short Name</mat-label>
|
||||
<input matInput formControlName="shortName" maxlength="4" required>
|
||||
<mat-error>
|
||||
Short Name is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="98%">
|
||||
<mat-label>Description</mat-label>
|
||||
<textarea matInput formControlName="description"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious disabled>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductDetailsStepComponent } from './recurring-deposit-product-details-step.component';
|
||||
|
||||
describe('RecurringDepositProductDetailsStepComponent', () => {
|
||||
let component: RecurringDepositProductDetailsStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductDetailsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductDetailsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductDetailsStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-details-step',
|
||||
templateUrl: './recurring-deposit-product-details-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-details-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductDetailsStepComponent implements OnInit {
|
||||
|
||||
recurringDepositProductDetailsForm: FormGroup;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createrecurringDepositProductDetailsForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
createrecurringDepositProductDetailsForm() {
|
||||
this.recurringDepositProductDetailsForm = this.formBuilder.group({
|
||||
'name': ['', Validators.required],
|
||||
'shortName': ['', Validators.required],
|
||||
'description': ['']
|
||||
});
|
||||
}
|
||||
|
||||
get recurringDepositProductDetails() {
|
||||
return this.recurringDepositProductDetailsForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
<form [formGroup]="recurringDepositProductInterestRateChartForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<h3 fxFlex="13%" class="mat-h3">Interest Rate Charts</h3>
|
||||
|
||||
<div fxFlex="83%" fxLayout="row" fxLayoutAlign="start center">
|
||||
<button type="button" mat-raised-button color="primary" (click)="addChart()">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" formArrayName="charts" *ngFor="let chart of charts.controls; let chartIndex = index">
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="chartIndex">
|
||||
|
||||
<div fxFlex="98%" fxLayout="row" fxLayoutAlign="end center">
|
||||
<button type="button" mat-icon-button color="warn" (click)="delete(charts, chartIndex)" matTooltip="Delete Interest Rate Chart" matTooltipPosition="left">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-form-field fxFlex="32%">
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput formControlName="name">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Valid from Date</mat-label>
|
||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="validFromDatePicker" formControlName="fromDate" required>
|
||||
<mat-datepicker-toggle matSuffix [for]="validFromDatePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #validFromDatePicker></mat-datepicker>
|
||||
<mat-error>
|
||||
Valid from Date is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>End Date</mat-label>
|
||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="endDatePicker" formControlName="endDate">
|
||||
<mat-datepicker-toggle matSuffix [for]="endDatePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #endDatePicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="65%">
|
||||
<mat-label>Description</mat-label>
|
||||
<textarea matInput formControlName="description"></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<div fxFlex="31%" fxLayout="row" fxLayoutAlign="space-between center">
|
||||
<mat-checkbox labelPosition="before" formControlName="isPrimaryGroupingByAmount">
|
||||
Is primary grouping by amount?
|
||||
</mat-checkbox>
|
||||
<button type="button" mat-raised-button color="primary" (click)="addChartSlab(chart.controls.chartSlabs)">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add Slab
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table fxFlex="98%" class="mat-elevation-z1" mat-table [dataSource]="chart.value.chartSlabs" *ngIf="chart.value.chartSlabs.length !== 0" multiTemplateDataRows>
|
||||
|
||||
<ng-container matColumnDef="period">
|
||||
<th mat-header-cell *matHeaderCellDef> Period </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.fromPeriod + ' - ' + chartSlab.toPeriod + ' ' + (chartSlab.periodType | find:periodTypeData:'id':'value') }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amountRange">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount Range </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.amountRangeFrom + ' - ' + chartSlab.amountRangeTo }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="annualInterestRate">
|
||||
<th mat-header-cell *matHeaderCellDef> Interest </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.annualInterestRate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef> Description </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.description }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let chartSlab; let chartSlabIndex = dataIndex">
|
||||
<button mat-icon-button color="primary" (click)="editChartSlab(chart.controls.chartSlabs, chartSlabIndex)">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="delete(chart.controls.chartSlabs, chartSlabIndex)">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
<button mat-button color="primary" (click)="expandChartSlabIndex[chartIndex] = expandChartSlabIndex[chartIndex] === chartSlabIndex ? null : chartSlabIndex">
|
||||
<span *ngIf="expandChartSlabIndex[chartIndex] !== chartSlabIndex">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
View Incentives
|
||||
</span>
|
||||
<span *ngIf="expandChartSlabIndex[chartIndex] === chartSlabIndex">
|
||||
<fa-icon icon="eye-slash"></fa-icon>
|
||||
Hide Incentives
|
||||
</span>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incentives">
|
||||
<td mat-cell *matCellDef="let chartSlab; let chartSlabIndex = dataIndex" [attr.colspan]="chartSlabsDisplayedColumns[chartIndex].length">
|
||||
|
||||
<div fxLayout="row wrap" fxFlexFill class="incentives" [@expandChartSlab]="chartSlabIndex === expandChartSlabIndex[chartIndex] ? 'expanded' : 'collapsed'">
|
||||
|
||||
<mat-card fxLayout="row wrap" fxFlexFill>
|
||||
|
||||
<h4 class="mat-h4" fxFlex="13%">
|
||||
Incentives
|
||||
</h4>
|
||||
|
||||
<div fxFlex="83%">
|
||||
<button mat-raised-button color="primary" (click)="addIncentive(getIncentives(chart.controls.chartSlabs, chartSlabIndex))">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="chartSlab.incentives" *ngIf="chartSlab.incentives.length">
|
||||
|
||||
<ng-container matColumnDef="entityType">
|
||||
<th mat-header-cell *matHeaderCellDef> Entity Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.entityType | find:entityTypeData:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="attributeName">
|
||||
<th mat-header-cell *matHeaderCellDef> Attribute Name </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.attributeName | find:attributeNameData:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="conditionType">
|
||||
<th mat-header-cell *matHeaderCellDef> Condition Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.conditionType | find:conditionTypeData:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="attributeValue">
|
||||
<th mat-header-cell *matHeaderCellDef> Attribute Value </th>
|
||||
<td mat-cell *matCellDef="let incentive" [ngSwitch]="incentive.attributeName">
|
||||
<span *ngSwitchCase="2">{{ incentive.attributeValue | find:genderData:'id':'name' }}</span>
|
||||
<span *ngSwitchCase="3">{{ incentive.attributeValue }}</span>
|
||||
<span *ngSwitchCase="4">{{ incentive.attributeValue | find:clientTypeData:'id':'name' }}</span>
|
||||
<span *ngSwitchCase="5">{{ incentive.attributeValue | find:clientClassificationData:'id':'name' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incentiveType">
|
||||
<th mat-header-cell *matHeaderCellDef> Incentive Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.incentiveType | find:incentiveTypeData:'id':'value'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Interest </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.amount }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let incentive; let incentiveIndex = index">
|
||||
<button mat-icon-button color="primary" (click)="editIncentive(getIncentives(chart.controls.chartSlabs, chartSlabIndex), incentiveIndex)">
|
||||
<fa-icon icon="edit"></fa-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="delete(getIncentives(chart.controls.chartSlabs, chartSlabIndex), incentiveIndex)">
|
||||
<fa-icon icon="trash"></fa-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="incentivesDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: incentivesDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</mat-card>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="chartSlabsDisplayedColumns[chartIndex]"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: chartSlabsDisplayedColumns[chartIndex];"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: chartSlabsIncentivesDisplayedColumns;" class="incentives-row"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious disabled>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
tr.incentives-row {
|
||||
height: 0;
|
||||
|
||||
> td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.incentives {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mat-card {
|
||||
border-radius: 0;
|
||||
|
||||
> h4 {
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 1em 0 1em 0;
|
||||
}
|
||||
|
||||
.mat-elevation-z1 {
|
||||
margin: 1em 0 1.5em 0;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.margin-v {
|
||||
margin: 1em 0;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductInterestRateChartStepComponent } from './recurring-deposit-product-interest-rate-chart-step.component';
|
||||
|
||||
describe('RecurringDepositProductInterestRateChartStepComponent', () => {
|
||||
let component: RecurringDepositProductInterestRateChartStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductInterestRateChartStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductInterestRateChartStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductInterestRateChartStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component';
|
||||
import { DepositProductIncentiveFormDialogComponent } from 'app/products/deposit-product-incentive-form-dialog/deposit-product-incentive-form-dialog.component';
|
||||
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
|
||||
|
||||
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
|
||||
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
|
||||
import { InputBase } from 'app/shared/form-dialog/formfield/model/input-base';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-interest-rate-chart-step',
|
||||
templateUrl: './recurring-deposit-product-interest-rate-chart-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-interest-rate-chart-step.component.scss'],
|
||||
animations: [
|
||||
trigger('expandChartSlab', [
|
||||
state('collapsed', style({ height: '0px', minHeight: '0' })),
|
||||
state('expanded', style({ height: '*' })),
|
||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
|
||||
])
|
||||
]
|
||||
})
|
||||
export class RecurringDepositProductInterestRateChartStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
|
||||
recurringDepositProductInterestRateChartForm: FormGroup;
|
||||
|
||||
periodTypeData: any;
|
||||
entityTypeData: any;
|
||||
attributeNameData: any;
|
||||
conditionTypeData: any;
|
||||
genderData: any;
|
||||
clientTypeData: any;
|
||||
clientClassificationData: any;
|
||||
incentiveTypeData: any;
|
||||
|
||||
chartSlabsDisplayedColumns: any[] = [];
|
||||
chartSlabsIncentivesDisplayedColumns: string[] = ['incentives'];
|
||||
incentivesDisplayedColumns: string[] = ['entityType', 'attributeName', 'conditionType', 'attributeValue', 'incentiveType', 'amount', 'actions'];
|
||||
|
||||
minDate = new Date(2000, 0, 1);
|
||||
maxDate = new Date(new Date().setFullYear(new Date().getFullYear() + 10));
|
||||
|
||||
expandChartSlabIndex: number[] = [];
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
public dialog: MatDialog,
|
||||
private datePipe: DatePipe) {
|
||||
this.createrecurringDepositProductInterestRateChartForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.periodTypeData = this.recurringDepositProductsTemplate.chartTemplate.periodTypes;
|
||||
this.entityTypeData = this.recurringDepositProductsTemplate.chartTemplate.entityTypeOptions;
|
||||
this.attributeNameData = this.recurringDepositProductsTemplate.chartTemplate.attributeNameOptions;
|
||||
this.conditionTypeData = this.recurringDepositProductsTemplate.chartTemplate.conditionTypeOptions;
|
||||
this.genderData = this.recurringDepositProductsTemplate.chartTemplate.genderOptions;
|
||||
this.clientTypeData = this.recurringDepositProductsTemplate.chartTemplate.clientTypeOptions;
|
||||
this.clientClassificationData = this.recurringDepositProductsTemplate.chartTemplate.clientClassificationOptions;
|
||||
this.incentiveTypeData = this.recurringDepositProductsTemplate.chartTemplate.incentiveTypeOptions;
|
||||
}
|
||||
|
||||
createrecurringDepositProductInterestRateChartForm() {
|
||||
this.recurringDepositProductInterestRateChartForm = this.formBuilder.group({
|
||||
'charts': this.formBuilder.array([])
|
||||
});
|
||||
}
|
||||
|
||||
get charts(): FormArray {
|
||||
return this.recurringDepositProductInterestRateChartForm.get('charts') as FormArray;
|
||||
}
|
||||
|
||||
createChartForm(): FormGroup {
|
||||
return this.formBuilder.group({
|
||||
'name': [''],
|
||||
'description': [''],
|
||||
'fromDate': ['', Validators.required],
|
||||
'endDate': [''],
|
||||
'isPrimaryGroupingByAmount': [false],
|
||||
'chartSlabs': this.formBuilder.array([])
|
||||
});
|
||||
}
|
||||
|
||||
addChart() {
|
||||
this.charts.push(this.createChartForm());
|
||||
this.setConditionalControls(this.charts.length - 1);
|
||||
}
|
||||
|
||||
setConditionalControls(chartIndex: number) {
|
||||
this.chartSlabsDisplayedColumns[chartIndex] = ['period', 'amountRange', 'annualInterestRate', 'description', 'actions'];
|
||||
this.charts.at(chartIndex).get('isPrimaryGroupingByAmount').valueChanges
|
||||
.subscribe((isPrimaryGroupingByAmount: boolean) => {
|
||||
this.chartSlabsDisplayedColumns[chartIndex] = isPrimaryGroupingByAmount ? ['amountRange', 'period'] : ['period', 'amountRange'];
|
||||
this.chartSlabsDisplayedColumns[chartIndex].push('annualInterestRate', 'description', 'actions');
|
||||
});
|
||||
}
|
||||
|
||||
getIncentives(chartSlabs: FormArray, chartSlabIndex: number): FormArray {
|
||||
return chartSlabs.at(chartSlabIndex).get('incentives') as FormArray;
|
||||
}
|
||||
|
||||
addChartSlab(chartSlabs: FormArray) {
|
||||
const data = { ...this.getData('Slab') };
|
||||
const dialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
response.data.addControl('incentives', this.formBuilder.array([]));
|
||||
chartSlabs.push(response.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addIncentive(incentives: FormArray) {
|
||||
const data = { ...this.getData('Incentive'), entityType: this.entityTypeData[0].id };
|
||||
const dialogRef = this.dialog.open(DepositProductIncentiveFormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
incentives.push(response.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editChartSlab(chartSlabs: FormArray, chartSlabIndex: number) {
|
||||
const data = { ...this.getData('Slab', chartSlabs.at(chartSlabIndex).value), layout: { addButtonText: 'Edit' } };
|
||||
const dialogRef = this.dialog.open(FormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
chartSlabs.at(chartSlabIndex).patchValue(response.data.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editIncentive(incentives: FormArray, incentiveIndex: number) {
|
||||
const data = { ...this.getData('Incentive', incentives.at(incentiveIndex).value), layout: { addButtonText: 'Edit' } };
|
||||
const dialogRef = this.dialog.open(DepositProductIncentiveFormDialogComponent, { data });
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.data) {
|
||||
incentives.at(incentiveIndex).patchValue(response.data.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
delete(formArray: FormArray, index: number) {
|
||||
const dialogRef = this.dialog.open(DeleteDialogComponent, {
|
||||
data: { deleteContext: `this` }
|
||||
});
|
||||
dialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.delete) {
|
||||
formArray.removeAt(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getData(formType: string, values?: any) {
|
||||
switch (formType) {
|
||||
case 'Slab': return { title: 'Slab', formfields: this.getSlabFormfields(values) };
|
||||
case 'Incentive': return { values, chartTemplate: this.recurringDepositProductsTemplate.chartTemplate };
|
||||
}
|
||||
}
|
||||
|
||||
getSlabFormfields(values?: any) {
|
||||
const formfields: FormfieldBase[] = [
|
||||
new SelectBase({
|
||||
controlName: 'periodType',
|
||||
label: 'Period Type',
|
||||
value: values ? values.periodType : this.periodTypeData[0].id,
|
||||
options: { label: 'value', value: 'id', data: this.periodTypeData },
|
||||
required: true,
|
||||
order: 1
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'fromPeriod',
|
||||
label: 'Period From',
|
||||
value: values ? values.fromPeriod : undefined,
|
||||
type: 'number',
|
||||
required: true,
|
||||
order: 2
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'toPeriod',
|
||||
label: 'Period To',
|
||||
value: values ? values.toPeriod : undefined,
|
||||
type: 'number',
|
||||
order: 3
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'amountRangeFrom',
|
||||
label: 'Amount Range From',
|
||||
value: values ? values.amountRangeFrom : undefined,
|
||||
type: 'number',
|
||||
order: 4
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'amountRangeTo',
|
||||
label: 'Amount Range To',
|
||||
value: values ? values.amountRangeTo : undefined,
|
||||
type: 'number',
|
||||
order: 5
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'annualInterestRate',
|
||||
label: 'Interest',
|
||||
value: values ? values.annualInterestRate : undefined,
|
||||
type: 'number',
|
||||
required: true,
|
||||
order: 6
|
||||
}),
|
||||
new InputBase({
|
||||
controlName: 'description',
|
||||
label: 'Description',
|
||||
value: values ? values.description : undefined,
|
||||
required: true,
|
||||
order: 7
|
||||
})
|
||||
];
|
||||
return formfields;
|
||||
}
|
||||
|
||||
get recurringDepositProductInterestRateChart() {
|
||||
// TODO: Update once language and date settings are setup
|
||||
const dateFormat = 'yyyy-MM-dd';
|
||||
const locale = 'en';
|
||||
const recurringDepositProductInterestRateChart = this.recurringDepositProductInterestRateChartForm.value;
|
||||
for (const chart of recurringDepositProductInterestRateChart.charts) {
|
||||
chart.dateFormat = dateFormat;
|
||||
chart.locale = locale;
|
||||
chart.fromDate = this.datePipe.transform(chart.fromDate, dateFormat) || '';
|
||||
chart.endDate = this.datePipe.transform(chart.endDate, dateFormat) || '';
|
||||
if (chart.endDate === '') {
|
||||
delete chart.endDate;
|
||||
}
|
||||
if (chart.description === '') {
|
||||
delete chart.description;
|
||||
}
|
||||
}
|
||||
return recurringDepositProductInterestRateChart;
|
||||
}
|
||||
|
||||
}
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
<div fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h2 class="mat-h2" fxFlexFill>{{ recurringDepositProduct.name }}</h2>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Details</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Short Name:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.shortName }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.description">
|
||||
<span fxFlex="40%">Description:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.description }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Currency</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Currency:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.currencyCode | find:recurringDepositProductsTemplate.currencyOptions:'code':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Decimal Places:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.digitsAfterDecimal }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Currency in multiples of:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.inMultiplesOf }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Terms</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Deposit Amount:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.depositAmount + ' (Min: ' + (recurringDepositProduct.minDepositAmount ? recurringDepositProduct.minDepositAmount : recurringDepositProduct.depositAmount) + ', Max: ' + (recurringDepositProduct.maxDepositAmount ? recurringDepositProduct.maxDepositAmount : recurringDepositProduct.depositAmount) + ')' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Compounding Period:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.interestCompoundingPeriodType | find:recurringDepositProductsTemplate.interestCompoundingPeriodTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Posting Period:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.interestPostingPeriodType | find:recurringDepositProductsTemplate.interestPostingPeriodTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Calculated using:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.interestCalculationType | find:recurringDepositProductsTemplate.interestCalculationTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Days in Year:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.interestCalculationDaysInYearType | find:recurringDepositProductsTemplate.interestCalculationDaysInYearTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Settings</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.lockinPeriodFrequency">
|
||||
<span fxFlex="40%">Lock-in Period:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.lockinPeriodFrequency + ' ' + (recurringDepositProduct.lockinPeriodFrequencyType | find:recurringDepositProductsTemplate.lockinPeriodFrequencyTypeOptions:'id':'value') }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Minimum Deposit Term:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.minDepositTerm + ' ' + (recurringDepositProduct.minDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.inMultiplesOfDepositTerm">
|
||||
<span fxFlex="40%">And thereafter, in Multiples of:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.inMultiplesOfDepositTerm + ' ' + (recurringDepositProduct.inMultiplesOfDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.maxDepositTerm">
|
||||
<span fxFlex="40%">Minimum Deposit Term:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.maxDepositTerm + ' ' + (recurringDepositProduct.maxDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }}</span>
|
||||
</div>
|
||||
<!-- For Pre-mature closure -->
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Apply Penal Interest (less):</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.preClosurePenalApplicable ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.preClosurePenalApplicable">
|
||||
<span fxFlex="40%">Penal Interest (%):</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.preClosurePenalInterest + '% (' + (recurringDepositProduct.preClosurePenalInterestOnTypeId | find:recurringDepositProductsTemplate.preClosurePenalInterestOnTypeOptions:'id':'value') + ')' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.isMandatoryDeposit !== undefined">
|
||||
<span fxFlex="40%">Recurring Deposit Type:</span>
|
||||
<span fxFlex="60%" *ngIf="recurringDepositProduct.isMandatoryDeposit"> Mandatory </span>
|
||||
<span fxFlex="60%" *ngIf="!recurringDepositProduct.isMandatoryDeposit"> Voluntary </span>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Withhold Tax is Applicable:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.withHoldTax ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.withHoldTax">
|
||||
<span fxFlex="40%">Tax Group:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.taxGroupId | find:recurringDepositProductsTemplate.taxGroupOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" *ngIf="recurringDepositProduct.charts.length !== 0">
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Interest Rate Charts</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill *ngFor="let chart of recurringDepositProduct.charts; let chartIndex = index" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<div fxFlexFill *ngIf="chart.name">
|
||||
<span fxFlex="40%">Name:</span>
|
||||
<span fxFlex="60%">{{ chart.name }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Valid from Date:</span>
|
||||
<span fxFlex="60%">{{ chart.fromDate | date }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="chart.endDate">
|
||||
<span fxFlex="40%">End Date:</span>
|
||||
<span fxFlex="60%">{{ chart.endDate | date }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="chart.description">
|
||||
<span fxFlex="40%">Description:</span>
|
||||
<span fxFlex="60%">{{ chart.description }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Primary Grouping by Amount:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.isPrimaryGroupingByAmount ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="chart.chartSlabs" *ngIf="chart.chartSlabs.length !== 0" multiTemplateDataRows>
|
||||
|
||||
<ng-container matColumnDef="period">
|
||||
<th mat-header-cell *matHeaderCellDef> Period </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.fromPeriod + ' - ' + chartSlab.toPeriod + ' ' + (chartSlab.periodType | find:recurringDepositProductsTemplate.chartTemplate.periodTypes:'id':'value') }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amountRange">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount Range </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.amountRangeFrom + ' - ' + chartSlab.amountRangeTo }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="annualInterestRate">
|
||||
<th mat-header-cell *matHeaderCellDef> Interest </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.annualInterestRate }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef> Description </th>
|
||||
<td mat-cell *matCellDef="let chartSlab">
|
||||
{{ chartSlab.description }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> Actions </th>
|
||||
<td mat-cell *matCellDef="let chartSlab; let chartSlabIndex = dataIndex">
|
||||
<button mat-button color="primary" (click)="expandChartSlabIndex[chartIndex] = expandChartSlabIndex[chartIndex] === chartSlabIndex ? null : chartSlabIndex" [disabled]="chartSlab.incentives.length === 0">
|
||||
<span *ngIf="expandChartSlabIndex[chartIndex] !== chartSlabIndex">
|
||||
<fa-icon icon="eye"></fa-icon>
|
||||
View Incentives
|
||||
</span>
|
||||
<span *ngIf="expandChartSlabIndex[chartIndex] === chartSlabIndex">
|
||||
<fa-icon icon="eye-slash"></fa-icon>
|
||||
Hide Incentives
|
||||
</span>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incentives">
|
||||
<td mat-cell *matCellDef="let chartSlab; let chartSlabIndex = dataIndex" [attr.colspan]="chartSlabsDisplayedColumns[chartIndex].length">
|
||||
<div fxLayout="row wrap" fxFlexFill class="incentives" [@expandChartSlab]="chartSlabIndex === expandChartSlabIndex[chartIndex] ? 'expanded' : 'collapsed'">
|
||||
<mat-card fxLayout="row wrap" fxFlexFill>
|
||||
|
||||
<h4 class="mat-h4" fxFlex="23%">
|
||||
Incentives
|
||||
</h4>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="chartSlab.incentives">
|
||||
|
||||
<ng-container matColumnDef="entityType">
|
||||
<th mat-header-cell *matHeaderCellDef> Entity Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.entityType | find:recurringDepositProductsTemplate.chartTemplate.entityTypeOptions:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="attributeName">
|
||||
<th mat-header-cell *matHeaderCellDef> Attribute Name </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.attributeName | find:recurringDepositProductsTemplate.chartTemplate.attributeNameOptions:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="conditionType">
|
||||
<th mat-header-cell *matHeaderCellDef> Condition Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.conditionType | find:recurringDepositProductsTemplate.chartTemplate.conditionTypeOptions:'id':'value' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="attributeValue">
|
||||
<th mat-header-cell *matHeaderCellDef> Attribute Value </th>
|
||||
<td mat-cell *matCellDef="let incentive" [ngSwitch]="incentive.attributeName">
|
||||
<span *ngSwitchCase="2">{{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.genderOptions:'id':'name' }}</span>
|
||||
<span *ngSwitchCase="3">{{ incentive.attributeValue }}</span>
|
||||
<span *ngSwitchCase="4">{{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.clientTypeOptions:'id':'name' }}</span>
|
||||
<span *ngSwitchCase="5">{{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.clientClassificationOptions:'id':'name' }}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incentiveType">
|
||||
<th mat-header-cell *matHeaderCellDef> Incentive Type </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.incentiveType | find:recurringDepositProductsTemplate.chartTemplate.incentiveTypeOptions:'id':'value'}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount </th>
|
||||
<td mat-cell *matCellDef="let incentive">
|
||||
{{ incentive.amount }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="incentivesDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: incentivesDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</mat-card>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="chartSlabsDisplayedColumns[chartIndex]"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: chartSlabsDisplayedColumns[chartIndex];"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: chartSlabsIncentivesDisplayedColumns;" class="incentives-row"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.charges.length" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Charges</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.charges">
|
||||
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef> Name </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.name + ', ' + charge.currency.displaySymbol }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="chargeCalculationType">
|
||||
<th mat-header-cell *matHeaderCellDef> Type </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.chargeCalculationType.value }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.amount }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="chargeTimeType">
|
||||
<th mat-header-cell *matHeaderCellDef> Collected On </th>
|
||||
<td mat-cell *matCellDef="let charge">
|
||||
{{ charge.chargeTimeType.value }}
|
||||
</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" fxFlexFill>Accounting</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Type:</span>
|
||||
<span fxFlex="60%">{{ accountingRuleData[recurringDepositProduct.accountingRule-1] }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="recurringDepositProduct.accountingRule === 2" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Assets</h4>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Saving reference:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.savingsReferenceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
<span fxFlex="40%">Saving control:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.savingsControlAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Savings transfers in suspense:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.transfersInSuspenseAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Expenses</h4>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest on savings:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.interestOnSavingsAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Income</h4>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
<span fxFlex="40%">Income from fees:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.incomeFromFeeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Income from penalties:</span>
|
||||
<span fxFlex="60%">{{ recurringDepositProduct.incomeFromPenaltyAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="recurringDepositProduct.advancedAccountingRules && (recurringDepositProduct.paymentChannelToFundSourceMappings?.length || recurringDepositProduct.feeToIncomeAccountMappings?.length || recurringDepositProduct.penaltyToIncomeAccountMappings?.length)" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.paymentChannelToFundSourceMappings">
|
||||
|
||||
<ng-container matColumnDef="paymentTypeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource">
|
||||
{{ paymentFundSource.paymentTypeId | find:recurringDepositProductsTemplate.paymentTypeOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="fundSourceAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource">
|
||||
{{ paymentFundSource.fundSourceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="recurringDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.feeToIncomeAccountMappings">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Fees </th>
|
||||
<td mat-cell *matCellDef="let feesIncome">
|
||||
{{ feesIncome.chargeId | find:recurringDepositProductsTemplate.chargeOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incomeAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Income Account </th>
|
||||
<td mat-cell *matCellDef="let feesIncome">
|
||||
{{ feesIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="recurringDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
|
||||
|
||||
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.penaltyToIncomeAccountMappings">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Penalty </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome">
|
||||
{{ penaltyIncome.chargeId | find:recurringDepositProductsTemplate.penaltyOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="incomeAccountId">
|
||||
<th mat-header-cell *matHeaderCellDef> Income Account </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome">
|
||||
{{ penaltyIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button [routerLink]="['../']">
|
||||
Cancel
|
||||
</button>
|
||||
<button mat-raised-button color="primary" (click)="submit.emit()">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
tr.incentives-row {
|
||||
height: 0;
|
||||
|
||||
> td {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.incentives {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mat-card {
|
||||
border-radius: 0;
|
||||
|
||||
> h4 {
|
||||
font-weight: 500;
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-elevation-z1 {
|
||||
margin: 1em 0 1.5em 0;
|
||||
}
|
||||
|
||||
h2, h3, h4 {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductPreviewStepComponent } from './recurring-deposit-product-preview-step.component';
|
||||
|
||||
describe('RecurringDepositProductPreviewStepComponent', () => {
|
||||
let component: RecurringDepositProductPreviewStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductPreviewStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductPreviewStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductPreviewStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { trigger, state, transition, animate, style } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-preview-step',
|
||||
templateUrl: './recurring-deposit-product-preview-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-preview-step.component.scss'],
|
||||
animations: [
|
||||
trigger('expandChartSlab', [
|
||||
state('collapsed', style({ height: '0px', minHeight: '0' })),
|
||||
state('expanded', style({ height: '*' })),
|
||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
|
||||
])
|
||||
]
|
||||
})
|
||||
export class RecurringDepositProductPreviewStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
@Input() chartSlabsDisplayedColumns: any[];
|
||||
@Input() accountingRuleData: any;
|
||||
@Input() recurringDepositProduct: any;
|
||||
@Output() submit = new EventEmitter();
|
||||
|
||||
chartSlabsIncentivesDisplayedColumns: string[] = ['incentives'];
|
||||
incentivesDisplayedColumns: string[] = ['entityType', 'attributeName', 'conditionType', 'attributeValue', 'incentiveType', 'amount'];
|
||||
chargesDisplayedColumns: string[] = ['name', 'chargeCalculationType', 'amount', 'chargeTimeType'];
|
||||
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId'];
|
||||
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId'];
|
||||
|
||||
expandChartSlabIndex: number[] = [];
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
<form [formGroup]="recurringDepositProductSettingsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="isMandatoryDeposit" class="margin-v">
|
||||
Is Mandatory Deposit?
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="adjustAdvanceTowardsFuturePayments" class="margin-v">
|
||||
Adjust advance payments toward future installments?
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="allowWithdrawal" class="margin-v">
|
||||
Allow Withdrawals?
|
||||
</mat-checkbox>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Lock-in Period</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Frequency</mat-label>
|
||||
<input type="number" matInput formControlName="lockinPeriodFrequency">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select formControlName="lockinPeriodFrequencyType">
|
||||
<mat-option *ngFor="let lockinPeriodFrequencyType of lockinPeriodFrequencyTypeData"
|
||||
[value]="lockinPeriodFrequencyType.id">
|
||||
{{ lockinPeriodFrequencyType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Minimum Deposit Term</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Frequency</mat-label>
|
||||
<input type="number" matInput formControlName="minDepositTerm" required>
|
||||
<mat-error>
|
||||
Minimum Deposit Term Frequency is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Frequency Type</mat-label>
|
||||
<mat-select formControlName="minDepositTermTypeId" required>
|
||||
<mat-option *ngFor="let periodFrequencyType of periodFrequencyTypeData" [value]="periodFrequencyType.id">
|
||||
{{ periodFrequencyType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Minimum Deposit Term Frequency Type is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">And thereafter, in Multiples of</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Frequency</mat-label>
|
||||
<input type="number" matInput formControlName="inMultiplesOfDepositTerm">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select formControlName="inMultiplesOfDepositTermTypeId">
|
||||
<mat-option *ngFor="let periodFrequencyType of periodFrequencyTypeData" [value]="periodFrequencyType.id">
|
||||
{{ periodFrequencyType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Maximum Deposit Term</h4>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Frequency</mat-label>
|
||||
<input type="number" matInput formControlName="maxDepositTerm">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Type</mat-label>
|
||||
<mat-select formControlName="maxDepositTermTypeId">
|
||||
<mat-option *ngFor="let periodFrequencyType of periodFrequencyTypeData" [value]="periodFrequencyType.id">
|
||||
{{ periodFrequencyType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h4 fxFlex="23%" class="mat-h4">For Pre-mature closure</h4>
|
||||
|
||||
<mat-checkbox fxFlex="73%" labelPosition="before" formControlName="preClosurePenalApplicable" class="margin-v">
|
||||
Apply Penal Interest (less)
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Penal Interest (%)</mat-label>
|
||||
<input type="number" matInput formControlName="preClosurePenalInterest">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Period</mat-label>
|
||||
<mat-select formControlName="preClosurePenalInterestOnTypeId">
|
||||
<mat-option *ngFor="let preClosurePenalInterestOnType of preClosurePenalInterestOnTypeData"
|
||||
[value]="preClosurePenalInterestOnType.id">
|
||||
{{ preClosurePenalInterestOnType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="withHoldTax" class="margin-v">
|
||||
Is Withhold Tax Applicable?
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-form-field fxFlex="48%" *ngIf="recurringDepositProductSettingsForm.value.withHoldTax">
|
||||
<mat-label>Tax Group</mat-label>
|
||||
<mat-select formControlName="taxGroupId" required>
|
||||
<mat-option *ngFor="let taxGroup of taxGroupData" [value]="taxGroup.id">
|
||||
{{ taxGroup.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Tax Group is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
h4 {
|
||||
font-weight: 500;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 1em 0 2em 0;
|
||||
}
|
||||
|
||||
.margin-v {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.margin-b {
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductSettingsStepComponent } from './recurring-deposit-product-settings-step.component';
|
||||
|
||||
describe('RecurringDepositProductSettingsStepComponent', () => {
|
||||
let component: RecurringDepositProductSettingsStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductSettingsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductSettingsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductSettingsStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-settings-step',
|
||||
templateUrl: './recurring-deposit-product-settings-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-settings-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductSettingsStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
|
||||
recurringDepositProductSettingsForm: FormGroup;
|
||||
|
||||
lockinPeriodFrequencyTypeData: any;
|
||||
periodFrequencyTypeData: any;
|
||||
preClosurePenalInterestOnTypeData: any;
|
||||
taxGroupData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createrecurringDepositProductSettingsForm();
|
||||
this.setConditionalControls();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.lockinPeriodFrequencyTypeData = this.recurringDepositProductsTemplate.lockinPeriodFrequencyTypeOptions;
|
||||
this.periodFrequencyTypeData = this.recurringDepositProductsTemplate.periodFrequencyTypeOptions.slice(0, -1);
|
||||
this.preClosurePenalInterestOnTypeData = this.recurringDepositProductsTemplate.preClosurePenalInterestOnTypeOptions;
|
||||
this.taxGroupData = this.recurringDepositProductsTemplate.taxGroupOptions;
|
||||
}
|
||||
|
||||
createrecurringDepositProductSettingsForm() {
|
||||
this.recurringDepositProductSettingsForm = this.formBuilder.group({
|
||||
'isMandatoryDeposit': [false],
|
||||
'adjustAdvanceTowardsFuturePayments': [false],
|
||||
'allowWithdrawal': [false],
|
||||
'lockinPeriodFrequency': [''],
|
||||
'lockinPeriodFrequencyType': [''],
|
||||
'minDepositTerm': ['', Validators.required],
|
||||
'minDepositTermTypeId': ['', Validators.required],
|
||||
'inMultiplesOfDepositTerm': [''],
|
||||
'inMultiplesOfDepositTermTypeId': [''],
|
||||
'maxDepositTerm': [''],
|
||||
'maxDepositTermTypeId': [''],
|
||||
'preClosurePenalApplicable': [false],
|
||||
'preClosurePenalInterest': [''],
|
||||
'preClosurePenalInterestOnTypeId': [''],
|
||||
'withHoldTax': [false]
|
||||
});
|
||||
}
|
||||
|
||||
setConditionalControls() {
|
||||
this.recurringDepositProductSettingsForm.get('withHoldTax').valueChanges
|
||||
.subscribe((withHoldTax: any) => {
|
||||
if (withHoldTax) {
|
||||
this.recurringDepositProductSettingsForm.addControl('taxGroupId', new FormControl('', Validators.required));
|
||||
} else {
|
||||
this.recurringDepositProductSettingsForm.removeControl('taxGroupId');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get recurringDepositProductSettings() {
|
||||
const recurringDepositProductSettings = this.recurringDepositProductSettingsForm.value;
|
||||
for (const key in recurringDepositProductSettings) {
|
||||
if (recurringDepositProductSettings[key] === '') {
|
||||
delete recurringDepositProductSettings[key];
|
||||
}
|
||||
}
|
||||
return recurringDepositProductSettings;
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<form [formGroup]="recurringDepositProductTermsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<h4 fxFlex="98%" class="mat-h4">Deposit Amount</h4>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Minimum</mat-label>
|
||||
<input type="number" matInput formControlName="minDepositAmount">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Default</mat-label>
|
||||
<input type="number" matInput formControlName="depositAmount" required>
|
||||
<mat-error>
|
||||
Default Deposit Amount is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Maximum</mat-label>
|
||||
<input type="number" matInput formControlName="maxDepositAmount">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Interest Compounding Period</mat-label>
|
||||
<mat-select formControlName="interestCompoundingPeriodType" required>
|
||||
<mat-option *ngFor="let interestCompoundingPeriodType of interestCompoundingPeriodTypeData" [value]="interestCompoundingPeriodType.id">
|
||||
{{ interestCompoundingPeriodType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Interest Compounding Period is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Interest Posting Period</mat-label>
|
||||
<mat-select formControlName="interestPostingPeriodType" required>
|
||||
<mat-option *ngFor="let interestPostingPeriodType of interestPostingPeriodTypeData" [value]="interestPostingPeriodType.id">
|
||||
{{ interestPostingPeriodType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Interest Posting Period is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Interest Calculated using</mat-label>
|
||||
<mat-select formControlName="interestCalculationType" required>
|
||||
<mat-option *ngFor="let interestCalculationType of interestCalculationTypeData" [value]="interestCalculationType.id">
|
||||
{{ interestCalculationType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Interest Calculated using is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Days in Year</mat-label>
|
||||
<mat-select formControlName="interestCalculationDaysInYearType" required>
|
||||
<mat-option *ngFor="let interestCalculationDaysInYearType of interestCalculationDaysInYearTypeData" [value]="interestCalculationDaysInYearType.id">
|
||||
{{ interestCalculationDaysInYearType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Days in Year is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="margin-t" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="2%">
|
||||
<button mat-raised-button matStepperPrevious>
|
||||
<fa-icon icon="arrow-left"></fa-icon>
|
||||
Previous
|
||||
</button>
|
||||
<button mat-raised-button matStepperNext>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
h4 {
|
||||
font-weight: 500;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 1em 0 2em 0;
|
||||
}
|
||||
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RecurringDepositProductTermsStepComponent } from './recurring-deposit-product-terms-step.component';
|
||||
|
||||
describe('RecurringDepositProductTermsStepComponent', () => {
|
||||
let component: RecurringDepositProductTermsStepComponent;
|
||||
let fixture: ComponentFixture<RecurringDepositProductTermsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ RecurringDepositProductTermsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RecurringDepositProductTermsStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-recurring-deposit-product-terms-step',
|
||||
templateUrl: './recurring-deposit-product-terms-step.component.html',
|
||||
styleUrls: ['./recurring-deposit-product-terms-step.component.scss']
|
||||
})
|
||||
export class RecurringDepositProductTermsStepComponent implements OnInit {
|
||||
|
||||
@Input() recurringDepositProductsTemplate: any;
|
||||
|
||||
recurringDepositProductTermsForm: FormGroup;
|
||||
|
||||
interestCompoundingPeriodTypeData: any;
|
||||
interestPostingPeriodTypeData: any;
|
||||
interestCalculationTypeData: any;
|
||||
interestCalculationDaysInYearTypeData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createrecurringDepositProductTermsForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.interestCompoundingPeriodTypeData = this.recurringDepositProductsTemplate.interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeData = this.recurringDepositProductsTemplate.interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeData = this.recurringDepositProductsTemplate.interestCalculationTypeOptions;
|
||||
this.interestCalculationDaysInYearTypeData = this.recurringDepositProductsTemplate.interestCalculationDaysInYearTypeOptions;
|
||||
|
||||
this.recurringDepositProductTermsForm.patchValue({
|
||||
'interestCompoundingPeriodType': this.recurringDepositProductsTemplate.interestCompoundingPeriodType.id,
|
||||
'interestPostingPeriodType': this.recurringDepositProductsTemplate.interestPostingPeriodType.id,
|
||||
'interestCalculationType': this.recurringDepositProductsTemplate.interestCalculationType.id,
|
||||
'interestCalculationDaysInYearType': this.recurringDepositProductsTemplate.interestCalculationDaysInYearType.id
|
||||
});
|
||||
}
|
||||
|
||||
createrecurringDepositProductTermsForm() {
|
||||
this.recurringDepositProductTermsForm = this.formBuilder.group({
|
||||
'minDepositAmount': [''],
|
||||
'depositAmount': ['', Validators.required],
|
||||
'maxDepositAmount': [''],
|
||||
'interestCompoundingPeriodType': ['', Validators.required],
|
||||
'interestPostingPeriodType': ['', Validators.required],
|
||||
'interestCalculationType': ['', Validators.required],
|
||||
'interestCalculationDaysInYearType': ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
get recurringDepositProductTerms() {
|
||||
const recurringDepositProductTerms = this.recurringDepositProductTermsForm.value;
|
||||
for (const key in recurringDepositProductTerms) {
|
||||
if (recurringDepositProductTerms[key] === '') {
|
||||
delete recurringDepositProductTerms[key];
|
||||
}
|
||||
}
|
||||
return recurringDepositProductTerms;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@ import { ProductsService } from '../products.service';
|
||||
@Injectable()
|
||||
export class RecurringDepositProductsTemplateResolver implements Resolve<Object> {
|
||||
|
||||
constructor(private productsService: ProductsService) {}
|
||||
constructor(private productsService: ProductsService) { }
|
||||
|
||||
/**
|
||||
* Returns the recurring deposit products template data.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
|
||||
<button mat-raised-button color="primary">
|
||||
<button mat-raised-button color="primary" [routerLink]="['create']" mifosxHasPermission='"CREATE_RECURRINGDEPOSITPRODUCT"'>
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Create Recurring Deposit Product
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user