feat: add create saving product component (#455)
- Add saving product stepper components - Add create saving product component Fixes: #189
This commit is contained in:
@@ -15,6 +15,7 @@ import { CreateLoanProductComponent } from './loan-products/create-loan-product/
|
||||
import { ViewLoanProductComponent } from './loan-products/view-loan-product/view-loan-product.component';
|
||||
import { EditLoanProductComponent } from './loan-products/edit-loan-product/edit-loan-product.component';
|
||||
import { SavingProductsComponent } from './saving-products/saving-products.component';
|
||||
import { CreateSavingProductComponent } from './saving-products/create-saving-product/create-saving-product.component';
|
||||
import { ManageTaxConfigurationsComponent } from './manage-tax-configurations/manage-tax-configurations.component';
|
||||
import { RecurringDepositProductsComponent } from './recurring-deposit-products/recurring-deposit-products.component';
|
||||
import { ChargesComponent } from './charges/charges.component';
|
||||
@@ -28,6 +29,7 @@ import { LoanProductsTemplateResolver } from './loan-products/loan-products-temp
|
||||
import { LoanProductResolver } from './loan-products/loan-product.resolver';
|
||||
import { LoanProductAndTemplateResolver } from './loan-products/edit-loan-product/loan-product-and-template.resolver';
|
||||
import { SavingProductsResolver } from './saving-products/saving-products.resolver';
|
||||
import { SavingProductsTemplateResolver } from './saving-products/saving-products-template.resolver';
|
||||
import { RecurringDepositProductsResolver } from './recurring-deposit-products/recurring-deposit-products.resolver';
|
||||
import { ChargesResolver } from './charges/charges.resolver';
|
||||
import { FixedDepositProductsResolver } from './fixed-deposit-products/fixed-deposit-products.resolver';
|
||||
@@ -97,7 +99,15 @@ const routes: Routes = [
|
||||
resolve: {
|
||||
savingProducts: SavingProductsResolver
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
component: CreateSavingProductComponent,
|
||||
data: { title: extract('Create Saving Product'), breadcrumb: 'Create' },
|
||||
resolve: {
|
||||
savingProductsTemplate: SavingProductsTemplateResolver
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -169,6 +179,7 @@ const routes: Routes = [
|
||||
LoanProductResolver,
|
||||
LoanProductAndTemplateResolver,
|
||||
SavingProductsResolver,
|
||||
SavingProductsTemplateResolver,
|
||||
RecurringDepositProductsResolver,
|
||||
ChargesResolver,
|
||||
FixedDepositProductsResolver,
|
||||
|
||||
@@ -27,6 +27,14 @@ import { ManageTaxComponentsComponent } from './manage-tax-components/manage-tax
|
||||
import { ViewLoanProductComponent } from './loan-products/view-loan-product/view-loan-product.component';
|
||||
import { EditLoanProductComponent } from './loan-products/edit-loan-product/edit-loan-product.component';
|
||||
import { SavingProductsComponent } from './saving-products/saving-products.component';
|
||||
import { SavingProductDetailsStepComponent } from './saving-products/saving-product-stepper/saving-product-details-step/saving-product-details-step.component';
|
||||
import { SavingProductCurrencyStepComponent } from './saving-products/saving-product-stepper/saving-product-currency-step/saving-product-currency-step.component';
|
||||
import { SavingProductTermsStepComponent } from './saving-products/saving-product-stepper/saving-product-terms-step/saving-product-terms-step.component';
|
||||
import { SavingProductSettingsStepComponent } from './saving-products/saving-product-stepper/saving-product-settings-step/saving-product-settings-step.component';
|
||||
import { SavingProductChargesStepComponent } from './saving-products/saving-product-stepper/saving-product-charges-step/saving-product-charges-step.component';
|
||||
import { SavingProductAccountingStepComponent } from './saving-products/saving-product-stepper/saving-product-accounting-step/saving-product-accounting-step.component';
|
||||
import { SavingProductPreviewStepComponent } from './saving-products/saving-product-stepper/saving-product-preview-step/saving-product-preview-step.component';
|
||||
import { CreateSavingProductComponent } from './saving-products/create-saving-product/create-saving-product.component';
|
||||
|
||||
/**
|
||||
* Products Module
|
||||
@@ -58,7 +66,15 @@ import { SavingProductsComponent } from './saving-products/saving-products.compo
|
||||
ManageTaxComponentsComponent,
|
||||
ViewLoanProductComponent,
|
||||
EditLoanProductComponent,
|
||||
SavingProductsComponent
|
||||
SavingProductsComponent,
|
||||
SavingProductDetailsStepComponent,
|
||||
SavingProductCurrencyStepComponent,
|
||||
SavingProductTermsStepComponent,
|
||||
SavingProductSettingsStepComponent,
|
||||
SavingProductChargesStepComponent,
|
||||
SavingProductAccountingStepComponent,
|
||||
SavingProductPreviewStepComponent,
|
||||
CreateSavingProductComponent
|
||||
],
|
||||
entryComponents: [
|
||||
],
|
||||
|
||||
@@ -49,6 +49,14 @@ export class ProductsService {
|
||||
return this.http.get('/savingsproducts');
|
||||
}
|
||||
|
||||
createSavingProduct(savingProduct: string): Observable<any> {
|
||||
return this.http.post('/savingsproducts', savingProduct);
|
||||
}
|
||||
|
||||
getSavingProductsTemplate(): Observable<any> {
|
||||
return this.http.get('/savingsproducts/template');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Observable<any>} Recurring deposit products data
|
||||
*/
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<div class="container">
|
||||
|
||||
<mat-horizontal-stepper class="mat-elevation-z8" labelPosition="bottom" #savingProductStepper>
|
||||
|
||||
<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]="savingProductDetailsForm">
|
||||
|
||||
<ng-template matStepLabel>DETAILS</ng-template>
|
||||
|
||||
<mifosx-saving-product-details-step></mifosx-saving-product-details-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="savingProductCurrencyForm">
|
||||
|
||||
<ng-template matStepLabel>CURRENCY</ng-template>
|
||||
|
||||
<mifosx-saving-product-currency-step [savingProductsTemplate]="savingProductsTemplate"></mifosx-saving-product-currency-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="savingProductTermsForm">
|
||||
|
||||
<ng-template matStepLabel>TERMS</ng-template>
|
||||
|
||||
<mifosx-saving-product-terms-step [savingProductsTemplate]="savingProductsTemplate"></mifosx-saving-product-terms-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="savingProductSettingsForm">
|
||||
|
||||
<ng-template matStepLabel>SETTINGS</ng-template>
|
||||
|
||||
<mifosx-saving-product-settings-step [savingProductsTemplate]="savingProductsTemplate"></mifosx-saving-product-settings-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step>
|
||||
|
||||
<ng-template matStepLabel>CHARGES</ng-template>
|
||||
|
||||
<mifosx-saving-product-charges-step
|
||||
[savingProductsTemplate]="savingProductsTemplate"
|
||||
[currencyCode]="savingProductCurrencyForm.get('currencyCode')"
|
||||
>
|
||||
</mifosx-saving-product-charges-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step [stepControl]="savingProductAccountingForm">
|
||||
|
||||
<ng-template matStepLabel>ACCOUNTING</ng-template>
|
||||
|
||||
<mifosx-saving-product-accounting-step
|
||||
[savingProductsTemplate]="savingProductsTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[isDormancyTrackingActive]="savingProductSettingsForm.get('isDormancyTrackingActive')"
|
||||
[savingProductFormValid]="savingProductFormValid"
|
||||
>
|
||||
</mifosx-saving-product-accounting-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
<mat-step state="preview" *ngIf="savingProductFormValid" completed>
|
||||
|
||||
<ng-template matStepLabel>PREVIEW</ng-template>
|
||||
|
||||
<mifosx-saving-product-preview-step
|
||||
[savingProductsTemplate]="savingProductsTemplate"
|
||||
[accountingRuleData]="accountingRuleData"
|
||||
[savingProduct]="savingProduct"
|
||||
(submit)="submit()"
|
||||
>
|
||||
</mifosx-saving-product-preview-step>
|
||||
|
||||
</mat-step>
|
||||
|
||||
</mat-horizontal-stepper>
|
||||
|
||||
</div>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
fa-icon {
|
||||
position: relative;
|
||||
left: 5%;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CreateSavingProductComponent } from './create-saving-product.component';
|
||||
|
||||
describe('CreateSavingProductComponent', () => {
|
||||
let component: CreateSavingProductComponent;
|
||||
let fixture: ComponentFixture<CreateSavingProductComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CreateSavingProductComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CreateSavingProductComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { SavingProductDetailsStepComponent } from '../saving-product-stepper/saving-product-details-step/saving-product-details-step.component';
|
||||
import { SavingProductCurrencyStepComponent } from '../saving-product-stepper/saving-product-currency-step/saving-product-currency-step.component';
|
||||
import { SavingProductTermsStepComponent } from '../saving-product-stepper/saving-product-terms-step/saving-product-terms-step.component';
|
||||
import { SavingProductSettingsStepComponent } from '../saving-product-stepper/saving-product-settings-step/saving-product-settings-step.component';
|
||||
import { SavingProductChargesStepComponent } from '../saving-product-stepper/saving-product-charges-step/saving-product-charges-step.component';
|
||||
import { SavingProductAccountingStepComponent } from '../saving-product-stepper/saving-product-accounting-step/saving-product-accounting-step.component';
|
||||
|
||||
import { ProductsService } from 'app/products/products.service';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-create-saving-product',
|
||||
templateUrl: './create-saving-product.component.html',
|
||||
styleUrls: ['./create-saving-product.component.scss']
|
||||
})
|
||||
export class CreateSavingProductComponent implements OnInit {
|
||||
|
||||
@ViewChild(SavingProductDetailsStepComponent) savingProductDetailsStep: SavingProductDetailsStepComponent;
|
||||
@ViewChild(SavingProductCurrencyStepComponent) savingProductCurrencyStep: SavingProductCurrencyStepComponent;
|
||||
@ViewChild(SavingProductTermsStepComponent) savingProductTermsStep: SavingProductTermsStepComponent;
|
||||
@ViewChild(SavingProductSettingsStepComponent) savingProductSettingsStep: SavingProductSettingsStepComponent;
|
||||
@ViewChild(SavingProductChargesStepComponent) savingProductChargesStep: SavingProductChargesStepComponent;
|
||||
@ViewChild(SavingProductAccountingStepComponent) savingProductAccountingStep: SavingProductAccountingStepComponent;
|
||||
|
||||
savingProductsTemplate: any;
|
||||
accountingRuleData = ['None', 'Cash'];
|
||||
|
||||
constructor(private route: ActivatedRoute,
|
||||
private productsService: ProductsService,
|
||||
private router: Router) {
|
||||
this.route.data.subscribe((data: { savingProductsTemplate: any }) => {
|
||||
this.savingProductsTemplate = data.savingProductsTemplate;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
get savingProductDetailsForm() {
|
||||
return this.savingProductDetailsStep.savingProductDetailsForm;
|
||||
}
|
||||
|
||||
get savingProductCurrencyForm() {
|
||||
return this.savingProductCurrencyStep.savingProductCurrencyForm;
|
||||
}
|
||||
|
||||
get savingProductTermsForm() {
|
||||
return this.savingProductTermsStep.savingProductTermsForm;
|
||||
}
|
||||
|
||||
get savingProductSettingsForm() {
|
||||
return this.savingProductSettingsStep.savingProductSettingsForm;
|
||||
}
|
||||
|
||||
get savingProductAccountingForm() {
|
||||
return this.savingProductAccountingStep.savingProductAccountingForm;
|
||||
}
|
||||
|
||||
get savingProductFormValid() {
|
||||
return (
|
||||
this.savingProductDetailsForm.valid &&
|
||||
this.savingProductCurrencyForm.valid &&
|
||||
this.savingProductTermsForm.valid &&
|
||||
this.savingProductSettingsForm.valid &&
|
||||
this.savingProductAccountingForm.valid
|
||||
);
|
||||
}
|
||||
|
||||
get savingProduct() {
|
||||
return {
|
||||
...this.savingProductDetailsStep.savingProductDetails,
|
||||
...this.savingProductCurrencyStep.savingProductCurrency,
|
||||
...this.savingProductTermsStep.savingProductTerms,
|
||||
...this.savingProductSettingsStep.savingProductSettings,
|
||||
...this.savingProductChargesStep.savingProductCharges,
|
||||
...this.savingProductAccountingStep.savingProductAccounting
|
||||
};
|
||||
}
|
||||
|
||||
submit() {
|
||||
// TODO: Update once language and date settings are setup
|
||||
const savingProduct = {
|
||||
...this.savingProduct,
|
||||
charges: this.savingProduct.charges.map((charge: any) => ({ id: charge.id })),
|
||||
locale: 'en' // locale required for nominalAnnualInterestRate
|
||||
};
|
||||
delete savingProduct.advancedAccountingRules;
|
||||
this.productsService.createSavingProduct(savingProduct)
|
||||
.subscribe((response: any) => {
|
||||
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
<form [formGroup]="savingProductAccountingForm">
|
||||
|
||||
<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="savingProductAccountingForm.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-form-field fxFlex="48%">
|
||||
<mat-label>Overdraft portfolio</mat-label>
|
||||
<mat-select formControlName="overdraftPortfolioControlId" required>
|
||||
<mat-option *ngFor="let assetAccount of assetAccountData" [value]="assetAccount.id">
|
||||
{{ assetAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Overdraft portfolio 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-form-field fxFlex="48%" *ngIf="isDormancyTrackingActive.value">
|
||||
<mat-label>Escheat liability</mat-label>
|
||||
<mat-select formControlName="escheatLiabilityId" required>
|
||||
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
|
||||
{{ liabilityAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Escheat liability 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-form-field fxFlex="48%">
|
||||
<mat-label>Write-off</mat-label>
|
||||
<mat-select formControlName="writeOffAccountId" required>
|
||||
<mat-option *ngFor="let expenseAccount of expenseAccountData" [value]="expenseAccount.id">
|
||||
{{ expenseAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Write-off 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-form-field fxFlex="48%">
|
||||
<mat-label>Overdraft Interest Income</mat-label>
|
||||
<mat-select formControlName="incomeFromInterestId" required>
|
||||
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
|
||||
{{ incomeAccount.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
Overdraft Interest Income 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="savingProductAccountingForm.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]="!savingProductFormValid">
|
||||
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 { SavingProductAccountingStepComponent } from './saving-product-accounting-step.component';
|
||||
|
||||
describe('SavingProductAccountingStepComponent', () => {
|
||||
let component: SavingProductAccountingStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductAccountingStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductAccountingStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductAccountingStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
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-saving-product-accounting-step',
|
||||
templateUrl: './saving-product-accounting-step.component.html',
|
||||
styleUrls: ['./saving-product-accounting-step.component.scss']
|
||||
})
|
||||
export class SavingProductAccountingStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
@Input() accountingRuleData: any;
|
||||
@Input() isDormancyTrackingActive: FormControl;
|
||||
@Input() savingProductFormValid: boolean;
|
||||
|
||||
savingProductAccountingForm: FormGroup;
|
||||
|
||||
chargeData: any;
|
||||
penaltyData: any;
|
||||
paymentTypeData: any;
|
||||
assetAccountData: any;
|
||||
incomeAccountData: any;
|
||||
expenseAccountData: any;
|
||||
liabilityAccountData: any;
|
||||
incomeAndLiabilityAccountData: any;
|
||||
|
||||
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId', 'actions'];
|
||||
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId', 'actions'];
|
||||
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
public dialog: MatDialog) {
|
||||
this.createsavingProductAccountingForm();
|
||||
this.setConditionalControls();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.chargeData = this.savingProductsTemplate.chargeOptions || [];
|
||||
this.penaltyData = this.savingProductsTemplate.penaltyOptions || [];
|
||||
this.paymentTypeData = this.savingProductsTemplate.paymentTypeOptions || [];
|
||||
this.assetAccountData = this.savingProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
|
||||
this.incomeAccountData = this.savingProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
|
||||
this.expenseAccountData = this.savingProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
|
||||
this.liabilityAccountData = this.savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
|
||||
}
|
||||
|
||||
createsavingProductAccountingForm() {
|
||||
this.savingProductAccountingForm = this.formBuilder.group({
|
||||
'accountingRule': [1]
|
||||
});
|
||||
}
|
||||
|
||||
setConditionalControls() {
|
||||
this.savingProductAccountingForm.get('accountingRule').valueChanges
|
||||
.subscribe((accountingRule: any) => {
|
||||
if (accountingRule === 2) {
|
||||
this.savingProductAccountingForm.addControl('savingsReferenceAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('overdraftPortfolioControlId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('savingsControlAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('transfersInSuspenseAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('interestOnSavingsAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('writeOffAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('incomeFromFeeAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('incomeFromPenaltyAccountId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('incomeFromInterestId', new FormControl('', Validators.required));
|
||||
this.savingProductAccountingForm.addControl('advancedAccountingRules', new FormControl(false));
|
||||
|
||||
if (this.isDormancyTrackingActive.value) {
|
||||
this.savingProductAccountingForm.addControl('escheatLiabilityId', new FormControl('', Validators.required));
|
||||
}
|
||||
|
||||
this.isDormancyTrackingActive.valueChanges
|
||||
.subscribe((isDormancyTrackingActive: boolean) => {
|
||||
if (isDormancyTrackingActive) {
|
||||
this.savingProductAccountingForm.addControl('escheatLiabilityId', new FormControl('', Validators.required));
|
||||
} else {
|
||||
this.savingProductAccountingForm.removeControl('escheatLiabilityId');
|
||||
}
|
||||
});
|
||||
|
||||
this.savingProductAccountingForm.get('advancedAccountingRules').valueChanges
|
||||
.subscribe((advancedAccountingRules: boolean) => {
|
||||
if (advancedAccountingRules) {
|
||||
this.savingProductAccountingForm.addControl('paymentChannelToFundSourceMappings', this.formBuilder.array([]));
|
||||
this.savingProductAccountingForm.addControl('feeToIncomeAccountMappings', this.formBuilder.array([]));
|
||||
this.savingProductAccountingForm.addControl('penaltyToIncomeAccountMappings', this.formBuilder.array([]));
|
||||
} else {
|
||||
this.savingProductAccountingForm.removeControl('paymentChannelToFundSourceMappings');
|
||||
this.savingProductAccountingForm.removeControl('feeToIncomeAccountMappings');
|
||||
this.savingProductAccountingForm.removeControl('penaltyToIncomeAccountMappings');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.savingProductAccountingForm.removeControl('savingsReferenceAccountId');
|
||||
this.savingProductAccountingForm.removeControl('overdraftPortfolioControlId');
|
||||
this.savingProductAccountingForm.removeControl('savingsControlAccountId');
|
||||
this.savingProductAccountingForm.removeControl('transfersInSuspenseAccountId');
|
||||
this.savingProductAccountingForm.removeControl('interestOnSavingsAccountId');
|
||||
this.savingProductAccountingForm.removeControl('writeOffAccountId');
|
||||
this.savingProductAccountingForm.removeControl('incomeFromFeeAccountId');
|
||||
this.savingProductAccountingForm.removeControl('incomeFromPenaltyAccountId');
|
||||
this.savingProductAccountingForm.removeControl('incomeFromInterestId');
|
||||
this.savingProductAccountingForm.removeControl('advancedAccountingRules');
|
||||
this.savingProductAccountingForm.removeControl('escheatLiabilityId');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get paymentChannelToFundSourceMappings(): FormArray {
|
||||
return this.savingProductAccountingForm.get('paymentChannelToFundSourceMappings') as FormArray;
|
||||
}
|
||||
|
||||
get feeToIncomeAccountMappings(): FormArray {
|
||||
return this.savingProductAccountingForm.get('feeToIncomeAccountMappings') as FormArray;
|
||||
}
|
||||
|
||||
get penaltyToIncomeAccountMappings(): FormArray {
|
||||
return this.savingProductAccountingForm.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 savingProductAccounting() {
|
||||
return this.savingProductAccountingForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<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 { SavingProductChargesStepComponent } from './saving-product-charges-step.component';
|
||||
|
||||
describe('SavingProductChargesStepComponent', () => {
|
||||
let component: SavingProductChargesStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductChargesStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductChargesStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductChargesStepComponent);
|
||||
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-saving-product-charges-step',
|
||||
templateUrl: './saving-product-charges-step.component.html',
|
||||
styleUrls: ['./saving-product-charges-step.component.scss']
|
||||
})
|
||||
export class SavingProductChargesStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
@Input() currencyCode: FormControl;
|
||||
|
||||
chargeData: any;
|
||||
|
||||
chargesDataSource: {}[];
|
||||
displayedColumns: string[] = ['name', 'chargeCalculationType', 'amount', 'chargeTimeType', 'action'];
|
||||
|
||||
constructor(public dialog: MatDialog) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.chargeData = this.savingProductsTemplate.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 savingProductCharges() {
|
||||
return {
|
||||
charges: this.chargesDataSource
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<form [formGroup]="savingProductCurrencyForm">
|
||||
|
||||
<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 { SavingProductCurrencyStepComponent } from './saving-product-currency-step.component';
|
||||
|
||||
describe('SavingProductCurrencyStepComponent', () => {
|
||||
let component: SavingProductCurrencyStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductCurrencyStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductCurrencyStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductCurrencyStepComponent);
|
||||
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-saving-product-currency-step',
|
||||
templateUrl: './saving-product-currency-step.component.html',
|
||||
styleUrls: ['./saving-product-currency-step.component.scss']
|
||||
})
|
||||
export class SavingProductCurrencyStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
|
||||
savingProductCurrencyForm: FormGroup;
|
||||
|
||||
currencyData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createSavingProductCurrencyForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.currencyData = this.savingProductsTemplate.currencyOptions;
|
||||
|
||||
this.savingProductCurrencyForm.patchValue({
|
||||
'currencyCode': this.currencyData[0].code,
|
||||
'digitsAfterDecimal': 2
|
||||
});
|
||||
}
|
||||
|
||||
createSavingProductCurrencyForm() {
|
||||
this.savingProductCurrencyForm = this.formBuilder.group({
|
||||
'currencyCode': ['', Validators.required],
|
||||
'digitsAfterDecimal': ['', Validators.required],
|
||||
'inMultiplesOf': ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
get savingProductCurrency() {
|
||||
return this.savingProductCurrencyForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<form [formGroup]="savingProductDetailsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" fxLayoutAlign.gt-sm="start center">
|
||||
|
||||
<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 { SavingProductDetailsStepComponent } from './saving-product-details-step.component';
|
||||
|
||||
describe('SavingProductDetailsStepComponent', () => {
|
||||
let component: SavingProductDetailsStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductDetailsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductDetailsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductDetailsStepComponent);
|
||||
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-saving-product-details-step',
|
||||
templateUrl: './saving-product-details-step.component.html',
|
||||
styleUrls: ['./saving-product-details-step.component.scss']
|
||||
})
|
||||
export class SavingProductDetailsStepComponent implements OnInit {
|
||||
|
||||
savingProductDetailsForm: FormGroup;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createSavingProductDetailsForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
createSavingProductDetailsForm() {
|
||||
this.savingProductDetailsForm = this.formBuilder.group({
|
||||
'name': ['', Validators.required],
|
||||
'shortName': ['', Validators.required],
|
||||
'description': ['']
|
||||
});
|
||||
}
|
||||
|
||||
get savingProductDetails() {
|
||||
return this.savingProductDetailsForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
<div fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h2 class="mat-h2" fxFlexFill>{{ savingProduct.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%">{{ savingProduct.shortName }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.description">
|
||||
<span fxFlex="40%">Description:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.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%">{{ savingProduct.currencyCode | find:savingProductsTemplate.currencyOptions:'code':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Decimal Places:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.digitsAfterDecimal }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Currency in multiples of:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.inMultiplesOf }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Terms</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Nominal Annual Interest Rate:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.nominalAnnualInterestRate }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Compounding Period:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.interestCompoundingPeriodType | find:savingProductsTemplate.interestCompoundingPeriodTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Posting Period:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.interestPostingPeriodType | find:savingProductsTemplate.interestPostingPeriodTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Interest Calculated using:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.interestCalculationType | find:savingProductsTemplate.interestCalculationTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Days in Year:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.interestCalculationDaysInYearType | find:savingProductsTemplate.interestCalculationDaysInYearTypeOptions:'id':'value' }}</span>
|
||||
</div>
|
||||
|
||||
<h3 class="mat-h3" fxFlexFill>Settings</h3>
|
||||
|
||||
<mat-divider fxFlexFill></mat-divider>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.minRequiredOpeningBalance">
|
||||
<span fxFlex="40%">Minimum Opening Balance:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.minRequiredOpeningBalance }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.lockinPeriodFrequency">
|
||||
<span fxFlex="40%">Lock-in Period:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.lockinPeriodFrequency + ' ' + (savingProduct.lockinPeriodFrequencyType | find:savingProductsTemplate.lockinPeriodFrequencyTypeOptions:'id':'value') }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Apply Withdrawal Fee for Transfers:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.withdrawalFeeForTransfers ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.minBalanceForInterestCalculation">
|
||||
<span fxFlex="40%">Balance Required for Interest Calculation:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.minBalanceForInterestCalculation }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Enforce Minimum Balance:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.enforceMinRequiredBalance ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.minRequiredBalance">
|
||||
<span fxFlex="40%">Minimum Balance:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.minRequiredBalance }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Withhold Tax is Applicable:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.withHoldTax ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.withHoldTax">
|
||||
<span fxFlex="40%">Tax Group:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.taxGroupId | find:savingProductsTemplate.taxGroupOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Is Overdraft Allowed:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.allowOverdraft ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.minOverdraftForInterestCalculation">
|
||||
<span fxFlex="40%">Minimum Overdraft Required for Interest Calculation:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.minOverdraftForInterestCalculation }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.nominalAnnualInterestRateOverdraft">
|
||||
<span fxFlex="40%">Nominal Annual Interest for Overdraft:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.nominalAnnualInterestRateOverdraft }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.overdraftLimit">
|
||||
<span fxFlex="40%">Maximum Overdraft Amount Limit:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.overdraftLimit }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill>
|
||||
<span fxFlex="40%">Enable Dormancy Tracking:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.isDormancyTrackingActive ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.isDormancyTrackingActive" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
<span fxFlex="40%">Number of Days to Inactive sub-status:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.daysToInactive }}</span>
|
||||
<span fxFlex="40%">Number of Days to Dormant sub-status:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.daysToDormancy }}</span>
|
||||
<span fxFlex="40%">Number of Days to Escheat:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.daysToEscheat }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.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]="savingProduct.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[savingProduct.accountingRule-1] }}</span>
|
||||
</div>
|
||||
|
||||
<div fxFlexFill *ngIf="savingProduct.accountingRule === 2" fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Assets</h4>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
<span fxFlex="40%">Saving reference:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.savingsReferenceAccountId | find:savingProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Overdraft portfolio:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.overdraftPortfolioControlId | find:savingProductsTemplate.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%">{{ savingProduct.savingsControlAccountId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Savings transfers in suspense:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.transfersInSuspenseAccountId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
|
||||
<div fxFlexFill *ngIf="savingProduct.isDormancyTrackingActive">
|
||||
<span fxFlex="40%">Escheat liability:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.escheatLiabilityId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 fxFlexFill class="mat-h4">Expenses</h4>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
|
||||
<span fxFlex="40%">Interest on savings:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.interestOnSavingsAccountId | find:savingProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Write-off:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.writeOffAccountId | find:savingProductsTemplate.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%">{{ savingProduct.incomeFromFeeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Income from penalties:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.incomeFromPenaltyAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
|
||||
<span fxFlex="40%">Overdraft Interest Income:</span>
|
||||
<span fxFlex="60%">{{ savingProduct.incomeFromInterestId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
|
||||
</div>
|
||||
|
||||
<div *ngIf="savingProduct.advancedAccountingRules && (savingProduct.paymentChannelToFundSourceMappings?.length || savingProduct.feeToIncomeAccountMappings?.length || savingProduct.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="savingProduct.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]="savingProduct.paymentChannelToFundSourceMappings">
|
||||
|
||||
<ng-container matColumnDef="paymentTypeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
|
||||
<td mat-cell *matCellDef="let paymentFundSource">
|
||||
{{ paymentFundSource.paymentTypeId | find:savingProductsTemplate.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:savingProductsTemplate.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="savingProduct.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]="savingProduct.feeToIncomeAccountMappings">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Fees </th>
|
||||
<td mat-cell *matCellDef="let feesIncome">
|
||||
{{ feesIncome.chargeId | find:savingProductsTemplate.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:savingProductsTemplate.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="savingProduct.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]="savingProduct.penaltyToIncomeAccountMappings">
|
||||
|
||||
<ng-container matColumnDef="chargeId">
|
||||
<th mat-header-cell *matHeaderCellDef> Penalty </th>
|
||||
<td mat-cell *matCellDef="let penaltyIncome">
|
||||
{{ penaltyIncome.chargeId | find:savingProductsTemplate.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:savingProductsTemplate.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>
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.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 { SavingProductPreviewStepComponent } from './saving-product-preview-step.component';
|
||||
|
||||
describe('SavingProductPreviewStepComponent', () => {
|
||||
let component: SavingProductPreviewStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductPreviewStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductPreviewStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductPreviewStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-saving-product-preview-step',
|
||||
templateUrl: './saving-product-preview-step.component.html',
|
||||
styleUrls: ['./saving-product-preview-step.component.scss']
|
||||
})
|
||||
export class SavingProductPreviewStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
@Input() accountingRuleData: any;
|
||||
@Input() savingProduct: any;
|
||||
@Output() submit = new EventEmitter();
|
||||
|
||||
chargesDisplayedColumns: string[] = ['name', 'chargeCalculationType', 'amount', 'chargeTimeType'];
|
||||
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId'];
|
||||
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId'];
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
<form [formGroup]="savingProductSettingsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" fxLayoutAlign.gt-sm="start center">
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Minimum Opening Balance</mat-label>
|
||||
<input type="number" matInput formControlName="minRequiredOpeningBalance">
|
||||
</mat-form-field>
|
||||
|
||||
<span fxFlex="48%" fxHide.lt-md></span>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Lock-in Period</mat-label>
|
||||
<input type="number" matInput formControlName="lockinPeriodFrequency">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-select formControlName="lockinPeriodFrequencyType">
|
||||
<mat-option *ngFor="let lockinPeriodFrequencyType of lockinPeriodFrequencyTypeData" [value]="lockinPeriodFrequencyType.id">
|
||||
{{ lockinPeriodFrequencyType.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="withdrawalFeeForTransfers" class="margin-v">
|
||||
Apply Withdrawal Fee for Transfers
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Balance Required for Interest Calculation</mat-label>
|
||||
<input type="number" matInput formControlName="minBalanceForInterestCalculation">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="enforceMinRequiredBalance" class="margin-v">
|
||||
Enforce Minimum Balance
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Minimum Balance</mat-label>
|
||||
<input type="number" matInput formControlName="minRequiredBalance">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-checkbox fxFlex="48%" labelPosition="before" formControlName="withHoldTax" class="margin-v">
|
||||
Is Withhold Tax Applicable?
|
||||
</mat-checkbox>
|
||||
|
||||
<mat-form-field fxFlex="48%" *ngIf="savingProductSettingsForm.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>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h3 fxFlex="23%" class="mat-h3">Overdraft</h3>
|
||||
|
||||
<mat-checkbox fxFlex="73%" labelPosition="before" formControlName="allowOverdraft" class="margin-b">
|
||||
Is Overdraft Allowed?
|
||||
</mat-checkbox>
|
||||
|
||||
<div *ngIf="savingProductSettingsForm.value.allowOverdraft" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Minimum Overdraft Required for Interest Calculation</mat-label>
|
||||
<input type="number" matInput formControlName="minOverdraftForInterestCalculation">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Nominal Annual Interest for Overdraft</mat-label>
|
||||
<input type="number" matInput formControlName="nominalAnnualInterestRateOverdraft">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Maximum Overdraft Amount Limit</mat-label>
|
||||
<input type="number" matInput formControlName="overdraftLimit">
|
||||
</mat-form-field>
|
||||
|
||||
</div>
|
||||
|
||||
<mat-divider fxFlex="98%"></mat-divider>
|
||||
|
||||
<h3 fxFlex="23%" class="mat-h3">Dormancy Tracking</h3>
|
||||
|
||||
<mat-checkbox fxFlex="73%" labelPosition="before" formControlName="isDormancyTrackingActive" class="margin-b">
|
||||
Enable Dormancy Tracking
|
||||
</mat-checkbox>
|
||||
|
||||
<div *ngIf="savingProductSettingsForm.value.isDormancyTrackingActive" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Number of Days to Inactive sub-status</mat-label>
|
||||
<input type="number" matInput formControlName="daysToInactive" required>
|
||||
<mat-error>
|
||||
Number of Days to Inactive sub-status is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Number of Days to Dormant sub-status</mat-label>
|
||||
<input type="number" matInput formControlName="daysToDormancy" required>
|
||||
<mat-error>
|
||||
Number of Days to Dormant sub-status is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="31%">
|
||||
<mat-label>Number of Days to Escheat</mat-label>
|
||||
<input type="number" matInput formControlName="daysToEscheat" required>
|
||||
<mat-error>
|
||||
Number of Days to Escheat is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
</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>
|
||||
Next
|
||||
<fa-icon icon="arrow-right"></fa-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
h3 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
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 { SavingProductSettingsStepComponent } from './saving-product-settings-step.component';
|
||||
|
||||
describe('SavingProductSettingsStepComponent', () => {
|
||||
let component: SavingProductSettingsStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductSettingsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductSettingsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductSettingsStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-saving-product-settings-step',
|
||||
templateUrl: './saving-product-settings-step.component.html',
|
||||
styleUrls: ['./saving-product-settings-step.component.scss']
|
||||
})
|
||||
export class SavingProductSettingsStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
|
||||
savingProductSettingsForm: FormGroup;
|
||||
|
||||
lockinPeriodFrequencyTypeData: any;
|
||||
taxGroupData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createSavingProductSettingsForm();
|
||||
this.setConditionalControls();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.lockinPeriodFrequencyTypeData = this.savingProductsTemplate.lockinPeriodFrequencyTypeOptions;
|
||||
this.taxGroupData = this.savingProductsTemplate.taxGroupOptions;
|
||||
}
|
||||
|
||||
createSavingProductSettingsForm() {
|
||||
this.savingProductSettingsForm = this.formBuilder.group({
|
||||
'minRequiredOpeningBalance': [''],
|
||||
'lockinPeriodFrequency': [''],
|
||||
'lockinPeriodFrequencyType': [''],
|
||||
'withdrawalFeeForTransfers': [false],
|
||||
'minBalanceForInterestCalculation': [''],
|
||||
'enforceMinRequiredBalance': [false],
|
||||
'minRequiredBalance': [''],
|
||||
'allowOverdraft': [false],
|
||||
'withHoldTax': [false],
|
||||
'isDormancyTrackingActive': [false]
|
||||
});
|
||||
}
|
||||
|
||||
setConditionalControls() {
|
||||
this.savingProductSettingsForm.get('allowOverdraft').valueChanges
|
||||
.subscribe((allowOverdraft: any) => {
|
||||
if (allowOverdraft) {
|
||||
this.savingProductSettingsForm.addControl('minOverdraftForInterestCalculation', new FormControl(''));
|
||||
this.savingProductSettingsForm.addControl('nominalAnnualInterestRateOverdraft', new FormControl(''));
|
||||
this.savingProductSettingsForm.addControl('overdraftLimit', new FormControl(''));
|
||||
} else {
|
||||
this.savingProductSettingsForm.removeControl('minOverdraftForInterestCalculation');
|
||||
this.savingProductSettingsForm.removeControl('nominalAnnualInterestRateOverdraft');
|
||||
this.savingProductSettingsForm.removeControl('overdraftLimit');
|
||||
}
|
||||
});
|
||||
|
||||
this.savingProductSettingsForm.get('withHoldTax').valueChanges
|
||||
.subscribe((withHoldTax: any) => {
|
||||
if (withHoldTax) {
|
||||
this.savingProductSettingsForm.addControl('taxGroupId', new FormControl('', Validators.required));
|
||||
} else {
|
||||
this.savingProductSettingsForm.removeControl('taxGroupId');
|
||||
}
|
||||
});
|
||||
|
||||
this.savingProductSettingsForm.get('isDormancyTrackingActive').valueChanges
|
||||
.subscribe((isDormancyTrackingActive: any) => {
|
||||
if (isDormancyTrackingActive) {
|
||||
this.savingProductSettingsForm.addControl('daysToInactive', new FormControl('', Validators.required));
|
||||
this.savingProductSettingsForm.addControl('daysToDormancy', new FormControl('', Validators.required));
|
||||
this.savingProductSettingsForm.addControl('daysToEscheat', new FormControl('', Validators.required));
|
||||
} else {
|
||||
this.savingProductSettingsForm.removeControl('daysToInactive');
|
||||
this.savingProductSettingsForm.removeControl('daysToDormancy');
|
||||
this.savingProductSettingsForm.removeControl('daysToEscheat');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get savingProductSettings() {
|
||||
return this.savingProductSettingsForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<form [formGroup]="savingProductTermsForm">
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-label>Nominal Annual Interest Rate</mat-label>
|
||||
<input type="number" matInput formControlName="nominalAnnualInterestRate" required>
|
||||
<mat-error>
|
||||
Nominal Annual Interest is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<span fxFlex="48%" fxHide.lt-md></span>
|
||||
|
||||
<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>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
.margin-t {
|
||||
margin-top: 1em;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SavingProductTermsStepComponent } from './saving-product-terms-step.component';
|
||||
|
||||
describe('SavingProductTermsStepComponent', () => {
|
||||
let component: SavingProductTermsStepComponent;
|
||||
let fixture: ComponentFixture<SavingProductTermsStepComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SavingProductTermsStepComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SavingProductTermsStepComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-saving-product-terms-step',
|
||||
templateUrl: './saving-product-terms-step.component.html',
|
||||
styleUrls: ['./saving-product-terms-step.component.scss']
|
||||
})
|
||||
export class SavingProductTermsStepComponent implements OnInit {
|
||||
|
||||
@Input() savingProductsTemplate: any;
|
||||
|
||||
savingProductTermsForm: FormGroup;
|
||||
|
||||
interestCompoundingPeriodTypeData: any;
|
||||
interestPostingPeriodTypeData: any;
|
||||
interestCalculationTypeData: any;
|
||||
interestCalculationDaysInYearTypeData: any;
|
||||
|
||||
constructor(private formBuilder: FormBuilder) {
|
||||
this.createSavingProductTermsForm();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.interestCompoundingPeriodTypeData = this.savingProductsTemplate.interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeData = this.savingProductsTemplate.interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeData = this.savingProductsTemplate.interestCalculationTypeOptions;
|
||||
this.interestCalculationDaysInYearTypeData = this.savingProductsTemplate.interestCalculationDaysInYearTypeOptions;
|
||||
|
||||
this.savingProductTermsForm.patchValue({
|
||||
'interestCompoundingPeriodType': this.interestCompoundingPeriodTypeData[0].id,
|
||||
'interestPostingPeriodType': this.interestPostingPeriodTypeData[0].id,
|
||||
'interestCalculationType': this.interestCalculationTypeData[0].id,
|
||||
'interestCalculationDaysInYearType': this.interestCalculationDaysInYearTypeData[0].id
|
||||
});
|
||||
}
|
||||
|
||||
createSavingProductTermsForm() {
|
||||
this.savingProductTermsForm = this.formBuilder.group({
|
||||
'nominalAnnualInterestRate': ['', Validators.required],
|
||||
'interestCompoundingPeriodType': ['', Validators.required],
|
||||
'interestPostingPeriodType': ['', Validators.required],
|
||||
'interestCalculationType': ['', Validators.required],
|
||||
'interestCalculationDaysInYearType': ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
get savingProductTerms() {
|
||||
return this.savingProductTermsForm.value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/** Angular Imports */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Resolve } from '@angular/router';
|
||||
|
||||
/** rxjs Imports */
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/** Custom Services */
|
||||
import { ProductsService } from '../products.service';
|
||||
|
||||
@Injectable()
|
||||
export class SavingProductsTemplateResolver implements Resolve<Object> {
|
||||
|
||||
constructor(private productsService: ProductsService) {}
|
||||
|
||||
/**
|
||||
* Returns the saving products template data.
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
resolve(): Observable<any> {
|
||||
return this.productsService.getSavingProductsTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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']">
|
||||
<fa-icon icon="plus"></fa-icon>
|
||||
Create Saving Product
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user