From a6f937d37c4dd7aebfe239b3d78d57234814e903 Mon Sep 17 00:00:00 2001 From: Muskan Khedia <36980003+muskankhedia@users.noreply.github.com> Date: Thu, 30 Jul 2020 13:06:46 +0530 Subject: [PATCH] feat: add create recurring deposit product component (#934) Fixes: #193 --- src/app/products/products-routing.module.ts | 11 +- src/app/products/products.module.ts | 28 +- src/app/products/products.service.ts | 5 + ...e-recurring-deposit-product.component.html | 110 +++++ ...e-recurring-deposit-product.component.scss | 0 ...ecurring-deposit-product.component.spec.ts | 25 + ...ate-recurring-deposit-product.component.ts | 107 ++++ ...sit-product-accounting-step.component.html | 264 ++++++++++ ...sit-product-accounting-step.component.scss | 23 + ...-product-accounting-step.component.spec.ts | 25 + ...posit-product-accounting-step.component.ts | 218 ++++++++ ...eposit-product-charges-step.component.html | 76 +++ ...eposit-product-charges-step.component.scss | 11 + ...sit-product-charges-step.component.spec.ts | 25 + ...-deposit-product-charges-step.component.ts | 56 +++ ...posit-product-currency-step.component.html | 46 ++ ...posit-product-currency-step.component.scss | 3 + ...it-product-currency-step.component.spec.ts | 25 + ...deposit-product-currency-step.component.ts | 42 ++ ...eposit-product-details-step.component.html | 39 ++ ...eposit-product-details-step.component.scss | 3 + ...sit-product-details-step.component.spec.ts | 25 + ...-deposit-product-details-step.component.ts | 32 ++ ...ct-interest-rate-chart-step.component.html | 225 +++++++++ ...ct-interest-rate-chart-step.component.scss | 47 ++ ...interest-rate-chart-step.component.spec.ts | 25 + ...duct-interest-rate-chart-step.component.ts | 244 +++++++++ ...eposit-product-preview-step.component.html | 466 ++++++++++++++++++ ...eposit-product-preview-step.component.scss | 45 ++ ...sit-product-preview-step.component.spec.ts | 25 + ...-deposit-product-preview-step.component.ts | 37 ++ ...posit-product-settings-step.component.html | 142 ++++++ ...posit-product-settings-step.component.scss | 20 + ...it-product-settings-step.component.spec.ts | 25 + ...deposit-product-settings-step.component.ts | 73 +++ ...-deposit-product-terms-step.component.html | 88 ++++ ...-deposit-product-terms-step.component.scss | 12 + ...posit-product-terms-step.component.spec.ts | 25 + ...ng-deposit-product-terms-step.component.ts | 60 +++ ...ring-deposit-products-template.resolver.ts | 2 +- .../recurring-deposit-products.component.html | 2 +- 41 files changed, 2755 insertions(+), 7 deletions(-) create mode 100644 src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.html create mode 100644 src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.scss create mode 100644 src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.html create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.scss create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.spec.ts create mode 100644 src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.ts diff --git a/src/app/products/products-routing.module.ts b/src/app/products/products-routing.module.ts index 2d9c78aab..7ce3e1808 100644 --- a/src/app/products/products-routing.module.ts +++ b/src/app/products/products-routing.module.ts @@ -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 + } + } ] }, { diff --git a/src/app/products/products.module.ts b/src/app/products/products.module.ts index f13f31715..d52a1b682 100644 --- a/src/app/products/products.module.ts +++ b/src/app/products/products.module.ts @@ -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, diff --git a/src/app/products/products.service.ts b/src/app/products/products.service.ts index 102655c9a..0e783c773 100644 --- a/src/app/products/products.service.ts +++ b/src/app/products/products.service.ts @@ -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 { + return this.http.post('/recurringdepositproducts', recurringDepositProduct); + } + } diff --git a/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.html b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.html new file mode 100644 index 000000000..667aa4c72 --- /dev/null +++ b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.html @@ -0,0 +1,110 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + DETAILS + + + + + + + + CURRENCY + + + + + + + + + TERMS + + + + + + + + + SETTINGS + + + + + + + + + INTEREST RATE CHART + + + + + + + + + CHARGES + + + + + + + + + ACCOUNTING + + + + + + + + + PREVIEW + + + + + + + + +
diff --git a/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.scss b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.spec.ts b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.spec.ts new file mode 100644 index 000000000..e8cf10b69 --- /dev/null +++ b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CreateRecurringDepositProductComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateRecurringDepositProductComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.ts b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.ts new file mode 100644 index 000000000..daf8e0b37 --- /dev/null +++ b/src/app/products/recurring-deposit-products/create-recurring-deposit-product/create-recurring-deposit-product.component.ts @@ -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 }); + }); + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.html new file mode 100644 index 000000000..8a95c5223 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.html @@ -0,0 +1,264 @@ +
+ +
+ + + + {{ accountingRule }} + + + + + +
+ +

Assets

+ + + Saving reference + + + {{ assetAccount.name }} + + + + Saving reference is required + + + + + +

Liabilities

+ + + Saving control + + + {{ liabilityAccount.name }} + + + + Saving control is required + + + + + Savings transfers in suspense + + + {{ liabilityAccount.name }} + + + + Savings transfers in suspense is required + + + + + +

Expenses

+ + + Interest on savings + + + {{ expenseAccount.name }} + + + + Interest on savings is required + + + + + +

Income

+ + + Income from fees + + + {{ incomeAccount.name }} + + + + Income from fees Repayments is required + + + + + Income from penalties + + + {{ incomeAccount.name }} + + + + Income from penalties is required + + + + + +

Advanced Accounting Rules

+ + + +
+ +

Configure Fund Sources for Payment Channels

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Payment Type + {{ paymentFundSource.paymentTypeId | find:paymentTypeData:'id':'name' }} + Fund Source + {{ paymentFundSource.fundSourceAccountId | find:assetAccountData:'id':'name' }} + Actions + + +
+ +

Map Fees to Specific Income Accounts

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Fees + {{ feesIncome.chargeId | find:chargeData:'id':'name' }} + Income Account + {{ feesIncome.incomeAccountId | find:incomeAccountData:'id':'name' }} + Actions + + +
+ +

Map Penalties to Specific Income Accounts

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
Penalty + {{ penaltyIncome.chargeId | find:penaltyData:'id':'name' }} + Income Account + {{ penaltyIncome.incomeAccountId | find:incomeAccountData:'id':'name' }} + Actions + + +
+ +
+ +
+ +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.scss new file mode 100644 index 000000000..e9e5641d0 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.scss @@ -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; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.spec.ts new file mode 100644 index 000000000..0068e986d --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductAccountingStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductAccountingStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts new file mode 100644 index 000000000..e012b5e03 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-accounting-step/recurring-deposit-product-accounting-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.html new file mode 100644 index 000000000..81c67b32f --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.html @@ -0,0 +1,76 @@ +
+ + + Charge + + + {{ charge.name }} + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name + {{ charge.name + ', ' + charge.currency.displaySymbol }} + Type + {{ charge.chargeCalculationType.value }} + Amount + {{ charge.amount }} + Collected On + {{ charge.chargeTimeType.value }} + Actions + +
+ +
+ +
+ + +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.scss new file mode 100644 index 000000000..dd420676a --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.scss @@ -0,0 +1,11 @@ +table { + width: 100%; +} + +.mat-elevation-z1 { + margin: 1em 0 1.5em 0; +} + +.margin-t { + margin-top: 1em; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.spec.ts new file mode 100644 index 000000000..48785e47a --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductChargesStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductChargesStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.ts new file mode 100644 index 000000000..a5cbb2f9c --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-charges-step/recurring-deposit-product-charges-step.component.ts @@ -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 + }; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.html new file mode 100644 index 000000000..7f87aec8d --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.html @@ -0,0 +1,46 @@ +
+ +
+ + + Currency + + + {{ currency.name }} + + + + Currency is required + + + + + Decimal Places + + + Decimal Places is required + + + + + Currency in multiples of + + + Currency in multiples of is required + + + +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.scss new file mode 100644 index 000000000..481475e1b --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.scss @@ -0,0 +1,3 @@ +.margin-t { + margin-top: 1em; + } diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.spec.ts new file mode 100644 index 000000000..794f5f9c2 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductCurrencyStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductCurrencyStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.ts new file mode 100644 index 000000000..5b5467729 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-currency-step/recurring-deposit-product-currency-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.html new file mode 100644 index 000000000..e7579391f --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.html @@ -0,0 +1,39 @@ +
+ +
+ + + Product Name + + + Product Name is required + + + + + Short Name + + + Short Name is required + + + + + Description + + + +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.scss new file mode 100644 index 000000000..aa8d23226 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.scss @@ -0,0 +1,3 @@ +.margin-t { + margin-top: 1em; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.spec.ts new file mode 100644 index 000000000..9aa3b7d4d --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductDetailsStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductDetailsStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.ts new file mode 100644 index 000000000..3f097906b --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-details-step/recurring-deposit-product-details-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.html new file mode 100644 index 000000000..02e0d5ebd --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.html @@ -0,0 +1,225 @@ +
+ +
+ +

Interest Rate Charts

+ +
+ +
+ +
+ + + +
+ +
+ +
+ + + Name + + + + + Valid from Date + + + + + Valid from Date is required + + + + + End Date + + + + + + + Description + + + +
+ + Is primary grouping by amount? + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Period + {{ chartSlab.fromPeriod + ' - ' + chartSlab.toPeriod + ' ' + (chartSlab.periodType | find:periodTypeData:'id':'value') }} + Amount Range + {{ chartSlab.amountRangeFrom + ' - ' + chartSlab.amountRangeTo }} + Interest + {{ chartSlab.annualInterestRate }} + Description + {{ chartSlab.description }} + Actions + + + + + +
+ + + +

+ Incentives +

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entity Type + {{ incentive.entityType | find:entityTypeData:'id':'value' }} + Attribute Name + {{ incentive.attributeName | find:attributeNameData:'id':'value' }} + Condition Type + {{ incentive.conditionType | find:conditionTypeData:'id':'value' }} + Attribute Value + {{ incentive.attributeValue | find:genderData:'id':'name' }} + {{ incentive.attributeValue }} + {{ incentive.attributeValue | find:clientTypeData:'id':'name' }} + {{ incentive.attributeValue | find:clientClassificationData:'id':'name' }} + Incentive Type + {{ incentive.incentiveType | find:incentiveTypeData:'id':'value'}} + Interest + {{ incentive.amount }} + Actions + + +
+ +
+
+
+ +
+ +
+ +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.scss new file mode 100644 index 000000000..21b059693 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.scss @@ -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; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.spec.ts new file mode 100644 index 000000000..e8d817310 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductInterestRateChartStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductInterestRateChartStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.ts new file mode 100644 index 000000000..86a89d362 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-interest-rate-chart-step/recurring-deposit-product-interest-rate-chart-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.html new file mode 100644 index 000000000..15b89e6d1 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.html @@ -0,0 +1,466 @@ +
+ +

{{ recurringDepositProduct.name }}

+ + + +

Details

+ + + +
+ Short Name: + {{ recurringDepositProduct.shortName }} +
+ +
+ Description: + {{ recurringDepositProduct.description }} +
+ +

Currency

+ + + +
+ Currency: + {{ recurringDepositProduct.currencyCode | find:recurringDepositProductsTemplate.currencyOptions:'code':'name' }} +
+ +
+ Decimal Places: + {{ recurringDepositProduct.digitsAfterDecimal }} +
+ +
+ Currency in multiples of: + {{ recurringDepositProduct.inMultiplesOf }} +
+ +

Terms

+ + + +
+ Deposit Amount: + {{ recurringDepositProduct.depositAmount + ' (Min: ' + (recurringDepositProduct.minDepositAmount ? recurringDepositProduct.minDepositAmount : recurringDepositProduct.depositAmount) + ', Max: ' + (recurringDepositProduct.maxDepositAmount ? recurringDepositProduct.maxDepositAmount : recurringDepositProduct.depositAmount) + ')' }} +
+ +
+ Interest Compounding Period: + {{ recurringDepositProduct.interestCompoundingPeriodType | find:recurringDepositProductsTemplate.interestCompoundingPeriodTypeOptions:'id':'value' }} +
+ +
+ Interest Posting Period: + {{ recurringDepositProduct.interestPostingPeriodType | find:recurringDepositProductsTemplate.interestPostingPeriodTypeOptions:'id':'value' }} +
+ +
+ Interest Calculated using: + {{ recurringDepositProduct.interestCalculationType | find:recurringDepositProductsTemplate.interestCalculationTypeOptions:'id':'value' }} +
+ +
+ Days in Year: + {{ recurringDepositProduct.interestCalculationDaysInYearType | find:recurringDepositProductsTemplate.interestCalculationDaysInYearTypeOptions:'id':'value' }} +
+ +

Settings

+ + + +
+ Lock-in Period: + {{ recurringDepositProduct.lockinPeriodFrequency + ' ' + (recurringDepositProduct.lockinPeriodFrequencyType | find:recurringDepositProductsTemplate.lockinPeriodFrequencyTypeOptions:'id':'value') }} +
+ +
+ Minimum Deposit Term: + {{ recurringDepositProduct.minDepositTerm + ' ' + (recurringDepositProduct.minDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }} +
+ +
+ And thereafter, in Multiples of: + {{ recurringDepositProduct.inMultiplesOfDepositTerm + ' ' + (recurringDepositProduct.inMultiplesOfDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }} +
+ +
+ Minimum Deposit Term: + {{ recurringDepositProduct.maxDepositTerm + ' ' + (recurringDepositProduct.maxDepositTermTypeId | find:recurringDepositProductsTemplate.periodFrequencyTypeOptions:'id':'value') }} +
+ +
+ Apply Penal Interest (less): + {{ recurringDepositProduct.preClosurePenalApplicable ? 'Yes' : 'No' }} +
+ +
+ Penal Interest (%): + {{ recurringDepositProduct.preClosurePenalInterest + '% (' + (recurringDepositProduct.preClosurePenalInterestOnTypeId | find:recurringDepositProductsTemplate.preClosurePenalInterestOnTypeOptions:'id':'value') + ')' }} +
+ +
+ Recurring Deposit Type: + Mandatory + Voluntary +
+ +
+ Withhold Tax is Applicable: + {{ recurringDepositProduct.withHoldTax ? 'Yes' : 'No' }} +
+ +
+ Tax Group: + {{ recurringDepositProduct.taxGroupId | find:recurringDepositProductsTemplate.taxGroupOptions:'id':'name' }} +
+ +
+ +

Interest Rate Charts

+ + + +
+ +
+ Name: + {{ chart.name }} +
+ +
+ Valid from Date: + {{ chart.fromDate | date }} +
+ +
+ End Date: + {{ chart.endDate | date }} +
+ +
+ Description: + {{ chart.description }} +
+ +
+ Primary Grouping by Amount: + {{ recurringDepositProduct.isPrimaryGroupingByAmount ? 'Yes' : 'No' }} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Period + {{ chartSlab.fromPeriod + ' - ' + chartSlab.toPeriod + ' ' + (chartSlab.periodType | find:recurringDepositProductsTemplate.chartTemplate.periodTypes:'id':'value') }} + Amount Range + {{ chartSlab.amountRangeFrom + ' - ' + chartSlab.amountRangeTo }} + Interest + {{ chartSlab.annualInterestRate }} + Description + {{ chartSlab.description }} + Actions + + +
+ + +

+ Incentives +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Entity Type + {{ incentive.entityType | find:recurringDepositProductsTemplate.chartTemplate.entityTypeOptions:'id':'value' }} + Attribute Name + {{ incentive.attributeName | find:recurringDepositProductsTemplate.chartTemplate.attributeNameOptions:'id':'value' }} + Condition Type + {{ incentive.conditionType | find:recurringDepositProductsTemplate.chartTemplate.conditionTypeOptions:'id':'value' }} + Attribute Value + {{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.genderOptions:'id':'name' }} + {{ incentive.attributeValue }} + {{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.clientTypeOptions:'id':'name' }} + {{ incentive.attributeValue | find:recurringDepositProductsTemplate.chartTemplate.clientClassificationOptions:'id':'name' }} + Incentive Type + {{ incentive.incentiveType | find:recurringDepositProductsTemplate.chartTemplate.incentiveTypeOptions:'id':'value'}} + Amount + {{ incentive.amount }} +
+ +
+
+
+ + + +
+ +
+ +
+ +

Charges

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name + {{ charge.name + ', ' + charge.currency.displaySymbol }} + Type + {{ charge.chargeCalculationType.value }} + Amount + {{ charge.amount }} + Collected On + {{ charge.chargeTimeType.value }} +
+ +
+ +

Accounting

+ + + +
+ Type: + {{ accountingRuleData[recurringDepositProduct.accountingRule-1] }} +
+ +
+ +

Assets

+ +
+ Saving reference: + {{ recurringDepositProduct.savingsReferenceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }} +
+ +

Liabilities

+ +
+ Saving control: + {{ recurringDepositProduct.savingsControlAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }} + Savings transfers in suspense: + {{ recurringDepositProduct.transfersInSuspenseAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }} +
+ +

Expenses

+ +
+ Interest on savings: + {{ recurringDepositProduct.interestOnSavingsAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }} +
+ +

Income

+ +
+ Income from fees: + {{ recurringDepositProduct.incomeFromFeeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }} + Income from penalties: + {{ recurringDepositProduct.incomeFromPenaltyAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }} +
+ +
+ +

Advanced Accounting Rules

+ + + +
+ +

Fund Sources for Payment Channels

+ + + + + + + + + + + + + + + + +
Payment Type + {{ paymentFundSource.paymentTypeId | find:recurringDepositProductsTemplate.paymentTypeOptions:'id':'name' }} + Fund Source + {{ paymentFundSource.fundSourceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }} +
+ +
+ +
+ +

Fees to Specific Income Accounts

+ + + + + + + + + + + + + + + + +
Fees + {{ feesIncome.chargeId | find:recurringDepositProductsTemplate.chargeOptions:'id':'name' }} + Income Account + {{ feesIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }} +
+ +
+ +
+ +

Penalties to Specific Income Accounts

+ + + + + + + + + + + + + + + + +
Penalty + {{ penaltyIncome.chargeId | find:recurringDepositProductsTemplate.penaltyOptions:'id':'name' }} + Income Account + {{ penaltyIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }} +
+ +
+ +
+ +
+ +
+ +
+ + + +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.scss new file mode 100644 index 000000000..9949c63bb --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.scss @@ -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; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.spec.ts new file mode 100644 index 000000000..45b771067 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductPreviewStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductPreviewStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.ts new file mode 100644 index 000000000..292a05068 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-preview-step/recurring-deposit-product-preview-step.component.ts @@ -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() { + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.html new file mode 100644 index 000000000..25dddc548 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.html @@ -0,0 +1,142 @@ +
+ +
+ + + Is Mandatory Deposit? + + + + Adjust advance payments toward future installments? + + + + Allow Withdrawals? + + +

Lock-in Period

+ + + Frequency + + + + + Type + + + {{ lockinPeriodFrequencyType.value }} + + + + +

Minimum Deposit Term

+ + + Frequency + + + Minimum Deposit Term Frequency is required + + + + + Frequency Type + + + {{ periodFrequencyType.value }} + + + + Minimum Deposit Term Frequency Type is required + + + +

And thereafter, in Multiples of

+ + + Frequency + + + + + Type + + + {{ periodFrequencyType.value }} + + + + +

Maximum Deposit Term

+ + + Frequency + + + + + Type + + + {{ periodFrequencyType.value }} + + + + + + +

For Pre-mature closure

+ + + Apply Penal Interest (less) + + + + Penal Interest (%) + + + + + Period + + + {{ preClosurePenalInterestOnType.value }} + + + + + + + + Is Withhold Tax Applicable? + + + + Tax Group + + + {{ taxGroup.name }} + + + + Tax Group is required + + + +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.scss new file mode 100644 index 000000000..72790f3df --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.scss @@ -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; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.spec.ts new file mode 100644 index 000000000..b00a32706 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductSettingsStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductSettingsStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts new file mode 100644 index 000000000..acad1dfcd --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-settings-step/recurring-deposit-product-settings-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.html new file mode 100644 index 000000000..98804bf56 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.html @@ -0,0 +1,88 @@ +
+ +
+ +

Deposit Amount

+ + + Minimum + + + + + Default + + + Default Deposit Amount is required + + + + + Maximum + + + + + + + Interest Compounding Period + + + {{ interestCompoundingPeriodType.value }} + + + + Interest Compounding Period is required + + + + + Interest Posting Period + + + {{ interestPostingPeriodType.value }} + + + + Interest Posting Period is required + + + + + Interest Calculated using + + + {{ interestCalculationType.value }} + + + + Interest Calculated using is required + + + + + Days in Year + + + {{ interestCalculationDaysInYearType.value }} + + + + Days in Year is required + + + +
+ +
+ + +
+ +
diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.scss b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.scss new file mode 100644 index 000000000..dae670b43 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.scss @@ -0,0 +1,12 @@ +h4 { + font-weight: 500; + margin: 1em 0; +} + +mat-divider { + margin: 1em 0 2em 0; +} + +.margin-t { + margin-top: 1em; +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.spec.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.spec.ts new file mode 100644 index 000000000..53646e792 --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ RecurringDepositProductTermsStepComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(RecurringDepositProductTermsStepComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.ts b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.ts new file mode 100644 index 000000000..b1d4eb80f --- /dev/null +++ b/src/app/products/recurring-deposit-products/recurring-deposit-product-stepper/recurring-deposit-product-terms-step/recurring-deposit-product-terms-step.component.ts @@ -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; + } + +} diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-products-template.resolver.ts b/src/app/products/recurring-deposit-products/recurring-deposit-products-template.resolver.ts index a0287db68..f11f9b10a 100644 --- a/src/app/products/recurring-deposit-products/recurring-deposit-products-template.resolver.ts +++ b/src/app/products/recurring-deposit-products/recurring-deposit-products-template.resolver.ts @@ -11,7 +11,7 @@ import { ProductsService } from '../products.service'; @Injectable() export class RecurringDepositProductsTemplateResolver implements Resolve { - constructor(private productsService: ProductsService) {} + constructor(private productsService: ProductsService) { } /** * Returns the recurring deposit products template data. diff --git a/src/app/products/recurring-deposit-products/recurring-deposit-products.component.html b/src/app/products/recurring-deposit-products/recurring-deposit-products.component.html index ae1207dad..636ce243d 100644 --- a/src/app/products/recurring-deposit-products/recurring-deposit-products.component.html +++ b/src/app/products/recurring-deposit-products/recurring-deposit-products.component.html @@ -1,5 +1,5 @@
-