diff --git a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss index 627fbb0d8..27fa4bbe7 100644 --- a/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss +++ b/src/app/loans/loans-view/repayment-schedule-tab/repayment-schedule-tab.component.scss @@ -1,5 +1,4 @@ @import "assets/styles/helper"; -@import "assets/styles/helper"; table { width: 100%; diff --git a/src/app/organization/investors/investors.component.html b/src/app/organization/investors/investors.component.html index 3a93bf7e9..96ba9912a 100644 --- a/src/app/organization/investors/investors.component.html +++ b/src/app/organization/investors/investors.component.html @@ -72,8 +72,8 @@ Effective From {{ record.effectiveFrom | dateFormat }} - - + + diff --git a/src/app/products/loan-products/create-loan-product/create-loan-product.component.html b/src/app/products/loan-products/create-loan-product/create-loan-product.component.html index 27ba07d38..8caaa82f5 100644 --- a/src/app/products/loan-products/create-loan-product/create-loan-product.component.html +++ b/src/app/products/loan-products/create-loan-product/create-loan-product.component.html @@ -63,13 +63,16 @@ PAYMENT ALLOCATION - + + diff --git a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts index b07474f88..2b034f7e0 100644 --- a/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts +++ b/src/app/products/loan-products/create-loan-product/create-loan-product.component.ts @@ -13,7 +13,7 @@ import { LoanProductAccountingStepComponent } from '../loan-product-stepper/loan /** Custom Services */ import { ProductsService } from 'app/products/products.service'; import { LoanProducts } from '../loan-products'; -import { PaymentAllocation, PaymentAllocationTransactionType, PaymentAllocationTransactionTypes, PaymentAllocationTypes } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; +import { AdvancedPaymentAllocation, AdvancedPaymentStrategy, PaymentAllocation } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; @Component({ selector: 'mifosx-create-loan-product', @@ -35,9 +35,7 @@ export class CreateLoanProductComponent implements OnInit { isAdvancedPaymentStrategy = false; paymentAllocation: PaymentAllocation[] = []; - transactionTypes: PaymentAllocationTransactionType[] = [ - PaymentAllocationTransactionTypes.DEFAULT_TRANSACTION - ]; + advancedPaymentAllocations: AdvancedPaymentAllocation[] = []; /** * @param {ActivatedRoute} route Activated Route. @@ -45,11 +43,11 @@ export class CreateLoanProductComponent implements OnInit { * @param {LoanProducts} loanProducts LoanProducts * @param {Router} router Router for navigation. */ - constructor(private route: ActivatedRoute, private productsService: ProductsService, private loanProducts: LoanProducts, - private router: Router) { + private router: Router, + private advancedPaymentStrategy: AdvancedPaymentStrategy) { this.route.data.subscribe((data: { loanProductsTemplate: any, configurations: any }) => { this.loanProductsTemplate = data.loanProductsTemplate; const assetAccountData = this.loanProductsTemplate.accountingMappingOptions.assetAccountOptions || []; @@ -82,7 +80,12 @@ export class CreateLoanProductComponent implements OnInit { this.isAdvancedPaymentStrategy = (value === 'advanced-payment-allocation-strategy'); } - setPaymentAllocation(paymentAllocation: PaymentAllocation[]) { + buildAdvancedPaymentAllocation(): void { + this.advancedPaymentAllocations = this.advancedPaymentStrategy.buildAdvancedPaymentAllocationList(this.loanProductsTemplate); + } + + setPaymentAllocation(paymentAllocation: PaymentAllocation[]): void { + console.log(paymentAllocation); this.paymentAllocation = paymentAllocation; } diff --git a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html index d3f51e0c9..2c9bcad4e 100644 --- a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html +++ b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.html @@ -63,11 +63,11 @@ PAYMENT ALLOCATION - diff --git a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts index b489e0a60..b0b776403 100644 --- a/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts +++ b/src/app/products/loan-products/edit-loan-product/edit-loan-product.component.ts @@ -14,7 +14,7 @@ import { LoanProductAccountingStepComponent } from '../loan-product-stepper/loan import { ProductsService } from 'app/products/products.service'; import { GlobalConfiguration } from 'app/system/configurations/global-configurations-tab/configuration.model'; import { LoanProducts } from '../loan-products'; -import { PaymentAllocation, PaymentAllocationTransactionType, PaymentAllocationTransactionTypes } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; +import { AdvancedPaymentAllocation, AdvancedPaymentStrategy, PaymentAllocation, PaymentAllocationOrder, PaymentAllocationTransactionTypes } from '../loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; @Component({ selector: 'mifosx-edit-loan-product', @@ -37,9 +37,7 @@ export class EditLoanProductComponent implements OnInit { isAdvancedPaymentStrategy = false; wasPaymentAllocationChanged = false; paymentAllocation: PaymentAllocation[] = []; - transactionTypes: PaymentAllocationTransactionType[] = [ - PaymentAllocationTransactionTypes.DEFAULT_TRANSACTION - ]; + advancedPaymentAllocations: AdvancedPaymentAllocation[] = []; /** * @param {ActivatedRoute} route Activated Route. @@ -51,7 +49,8 @@ export class EditLoanProductComponent implements OnInit { constructor(private route: ActivatedRoute, private productsService: ProductsService, private loanProducts: LoanProducts, - private router: Router) { + private router: Router, + private advancedPaymentStrategy: AdvancedPaymentStrategy) { this.route.data.subscribe((data: { loanProductAndTemplate: any, configurations: any }) => { this.loanProductAndTemplate = data.loanProductAndTemplate; const assetAccountData = this.loanProductAndTemplate.accountingMappingOptions.assetAccountOptions || []; @@ -65,6 +64,7 @@ export class EditLoanProductComponent implements OnInit { } ngOnInit() { + this.buildAdvancedPaymentAllocation(); } get loanProductDetailsForm() { @@ -87,8 +87,13 @@ export class EditLoanProductComponent implements OnInit { this.isAdvancedPaymentStrategy = (value === 'advanced-payment-allocation-strategy'); } + buildAdvancedPaymentAllocation(): void { + this.advancedPaymentAllocations = this.advancedPaymentStrategy.buildAdvancedPaymentAllocationList(this.loanProductAndTemplate); + } + setPaymentAllocation(paymentAllocation: PaymentAllocation[]): void { this.paymentAllocation = paymentAllocation; + this.wasPaymentAllocationChanged = true; } paymentAllocationChanged(value: boolean): void { diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.html new file mode 100644 index 000000000..27492f63c --- /dev/null +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.html @@ -0,0 +1,39 @@ +
+ +

You can drag and drop the rows to set a Payment Allocations order

+ +
+ +
+ +
+ + + + + + + + + + + + + + +
Payment Allocation {{ paymentAllocation.value }} Order {{ (rowIndex + 1) }}
+
+ + + Future Installment Allocation Rule + + + {{ futureInstallmentAllocationRule.value | translate }} + + + +
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.spec.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.spec.ts new file mode 100644 index 000000000..151afe131 --- /dev/null +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AdvancePaymentAllocationTabComponent } from './advance-payment-allocation-tab.component'; + +describe('AdvancePaymentAllocationTabComponent', () => { + let component: AdvancePaymentAllocationTabComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AdvancePaymentAllocationTabComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AdvancePaymentAllocationTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.ts new file mode 100644 index 000000000..98075f693 --- /dev/null +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component.ts @@ -0,0 +1,70 @@ +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { AdvancedPaymentAllocation, AdvancedPaymentStrategy, FutureInstallmentAllocationRule, PaymentAllocationOrder, PaymentAllocationTransactionType } from '../payment-allocation-model'; +import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; +import { MatTable } from '@angular/material/table'; +import { MatDialog } from '@angular/material/dialog'; +import { UntypedFormControl, Validators } from '@angular/forms'; +import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component'; + +@Component({ + selector: 'mifosx-advance-payment-allocation-tab', + templateUrl: './advance-payment-allocation-tab.component.html', + styleUrls: ['./advance-payment-allocation-tab.component.scss'] +}) +export class AdvancePaymentAllocationTabComponent implements OnInit { + + @Input() advancedPaymentAllocation: AdvancedPaymentAllocation; + + @Output() paymentAllocationChange = new EventEmitter(); + @Output() transactionTypeRemoved = new EventEmitter(); + + paymentAllocationsData: PaymentAllocationOrder[] = []; + + /** Columns to be displayed in the table. */ + displayedColumns: string[] = ['paymentAllocation', 'order']; + + futureInstallmentAllocationRule = new UntypedFormControl('', Validators.required); + + @ViewChild('table') table: MatTable; + + constructor(private dialog: MatDialog, + private advancedPaymentStrategy: AdvancedPaymentStrategy) { } + + ngOnInit(): void { + this.paymentAllocationsData = this.advancedPaymentAllocation.paymentAllocationOrder; + this.futureInstallmentAllocationRule.patchValue(this.advancedPaymentAllocation.futureInstallmentAllocationRule.code); + this.futureInstallmentAllocationRule.valueChanges.subscribe((value: any) => { + this.advancedPaymentAllocation.futureInstallmentAllocationRules.forEach((item: FutureInstallmentAllocationRule) => { + if (value === item.code) { + this.advancedPaymentAllocation.futureInstallmentAllocationRule = item; + this.paymentAllocationChange.emit(true); + } + }); + }); + } + + dropTable(event: CdkDragDrop) { + const prevIndex = this.paymentAllocationsData.findIndex((d: any) => d === event.item.data); + moveItemInArray(this.paymentAllocationsData, prevIndex, event.currentIndex); + this.paymentAllocationsData = [...this.paymentAllocationsData]; + this.advancedPaymentAllocation.paymentAllocationOrder = this.paymentAllocationsData; + this.table.renderRows(); + this.paymentAllocationChange.emit(true); + } + + isDefault(): boolean { + return this.advancedPaymentStrategy.isDefault(this.advancedPaymentAllocation.transaction); + } + + removeTransaction(): void { + const dialogRef = this.dialog.open(DeleteDialogComponent, { + data: { deleteContext: ` the Transaction Type ${this.advancedPaymentAllocation.transaction.value}` } + }); + dialogRef.afterClosed().subscribe((response: any) => { + if (response.delete) { + this.transactionTypeRemoved.emit(this.advancedPaymentAllocation.transaction); + } + }); + } + +} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.html index 898da7b86..ae8386903 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.html @@ -1,55 +1,25 @@ -
-
+ - - Transaction Type - - - {{ transactionTypeOption.name | translate }} - - - + + + {{advancedPaymentAllocation.transaction.code}} + + + + -

You can drag and drop the rows to set a Payment Allocations order

+ + + + + +
-
- - - - - - - - - - - - - - -
Payment Allocation {{ paymentAllocation.name }} Order {{ (rowIndex + 1) }}
-
- - - Future Installment Allocation Rule - - - {{ installmentAllocation.name | translate }} - - - -
- -
- - -
+
+
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.scss index e69de29bb..466f234bb 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.scss @@ -0,0 +1,13 @@ +@import "assets/styles/colours"; + +::ng-deep .mat-tab-body-wrapper { + width: 96%; + margin: auto; +} + +::ng-deep .mat-tab-label.mat-tab-disabled { + padding: 0px; + margin: 0; + justify-content: left; + color: $status-approved; +} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.ts index bbccfa3b0..fe9358bc6 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component.ts @@ -1,9 +1,10 @@ -import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; -import { UntypedFormControl, Validators } from '@angular/forms'; +import { AdvancedPaymentAllocation, AdvancedPaymentStrategy, PaymentAllocation, PaymentAllocationOrder, PaymentAllocationTransactionType } from './payment-allocation-model'; import { MatDialog } from '@angular/material/dialog'; -import { MatTable } from '@angular/material/table'; -import { FutureInstallmentAllocationRules, PaymentAllocation, PaymentAllocationOrder, PaymentAllocationTransactionType, PaymentAllocationTransactionTypes, PaymentAllocationTypes, PaymentCode } from './payment-allocation-model'; +import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base'; +import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base'; +import { FormDialogComponent } from 'app/shared/form-dialog/form-dialog.component'; +import { MatTabGroup } from '@angular/material/tabs'; @Component({ selector: 'mifosx-loan-product-payment-strategy-step', @@ -12,69 +13,85 @@ import { FutureInstallmentAllocationRules, PaymentAllocation, PaymentAllocationO }) export class LoanProductPaymentStrategyStepComponent implements OnInit { - @Input() loanProductsTemplate: any; - @Input() transactionType: PaymentAllocationTransactionType; - @Output() paymentAllocation = new EventEmitter(); + @Input() advancedPaymentAllocations: AdvancedPaymentAllocation[] = []; + @Input() advancedPaymentAllocationTransactionTypes: PaymentAllocationTransactionType[] = []; + @Input() paymentAllocationOrderDefault: PaymentAllocationOrder[]; + @Output() paymentAllocationChange = new EventEmitter(); + @Output() setPaymentAllocation = new EventEmitter(); - paymentAllocationsData: PaymentCode[] = []; - installmentAllocationOptions: PaymentCode[] = []; - transactionTypeOptions: PaymentCode[] = []; + @ViewChild(MatTabGroup) tabGroup: MatTabGroup; - transactionTypeCtrl = new UntypedFormControl(''); - futureInstallmentAllocationRule = new UntypedFormControl('', Validators.required); + constructor(private dialog: MatDialog, + private advancedPaymentStrategy: AdvancedPaymentStrategy) { } - @ViewChild('table') table: MatTable; - - /** Columns to be displayed in the table. */ - displayedColumns: string[] = ['paymentAllocation', 'order']; - - constructor() { } - - ngOnInit(): void { - this.paymentAllocationsData = []; - this.setOptions(); - this.sendPaymentAllocation(); - } - - setOptions(): void { - this.paymentAllocationsData = PaymentAllocationTypes.options; - this.transactionTypeOptions = PaymentAllocationTransactionTypes.options; - this.transactionTypeCtrl.patchValue(this.transactionTypeOptions[0].code); - if (this.transactionType) { - this.transactionTypeCtrl.patchValue(this.transactionType.code); - } - this.installmentAllocationOptions = FutureInstallmentAllocationRules.options; - this.futureInstallmentAllocationRule.patchValue(this.installmentAllocationOptions[0].code); - } - - dropTable(event: CdkDragDrop) { - const prevIndex = this.paymentAllocationsData.findIndex((d: any) => d === event.item.data); - moveItemInArray(this.paymentAllocationsData, prevIndex, event.currentIndex); - this.paymentAllocationsData = [...this.paymentAllocationsData]; - this.table.renderRows(); - this.sendPaymentAllocation(); - this.paymentAllocationChange.emit(true); - } + ngOnInit(): void { } sendPaymentAllocation(): void { - let transactionTypeVal = PaymentAllocationTransactionTypes.DEFAULT_TRANSACTION.code; - if (this.transactionType) { - transactionTypeVal = this.transactionType.code; - } - const paymentAllocationOrder: PaymentAllocationOrder[] = []; - this.paymentAllocationsData.forEach((txType: PaymentCode, index: number) => { - paymentAllocationOrder.push({ 'paymentAllocationRule': txType.code, order: (index + 1) }); + const data = this.advancedPaymentStrategy.buildPaymentAllocations(this.advancedPaymentAllocations); + this.setPaymentAllocation.emit(data); + } + + paymentAllocationChanged(changed: boolean): void { + this.paymentAllocationChange.emit(changed); + this.sendPaymentAllocation(); + } + + addTransaction(): void { + const transactionTypesCurrent: String[] = []; + this.advancedPaymentAllocations.forEach((item: AdvancedPaymentAllocation) => { + transactionTypesCurrent.push(item.transaction.code); }); - const paymentAllocation: PaymentAllocation[] = []; - paymentAllocation.push({ - 'futureInstallmentAllocationRule': this.futureInstallmentAllocationRule.value, - 'transactionType': transactionTypeVal, - 'paymentAllocationOrder': paymentAllocationOrder + const transactionTypesOptions: PaymentAllocationTransactionType[] = []; + this.advancedPaymentAllocationTransactionTypes.forEach((option: PaymentAllocationTransactionType) => { + if (!this.advancedPaymentStrategy.isDefault(option) && transactionTypesCurrent.indexOf(option.code) < 0) { + transactionTypesOptions.push(option); + } }); - this.paymentAllocation.emit(paymentAllocation); + const formfields: FormfieldBase[] = [ + new SelectBase({ + controlName: 'code', + label: 'Transaction Type', + options: { label: 'code', value: 'code', data: transactionTypesOptions }, + order: 1 + }) + ]; + const data = { + title: 'Advanced Payment Allocation Transaction Type', + layout: { addButtonText: 'Add' }, + formfields: formfields + }; + const transactionTypeDialogRef = this.dialog.open(FormDialogComponent, { data }); + transactionTypeDialogRef.afterClosed().subscribe((response: any) => { + if (response.data) { + const defaultPaymentAllocation: AdvancedPaymentAllocation = this.advancedPaymentAllocations[0]; + transactionTypesOptions.forEach((transactionType: PaymentAllocationTransactionType) => { + if (transactionType.code === response.data.value.code) { + this.advancedPaymentAllocations.push( + this.advancedPaymentStrategy.buildAdvancedPaymentAllocation(true, transactionType, + this.paymentAllocationOrderDefault, + defaultPaymentAllocation.futureInstallmentAllocationRules) + ); + this.paymentAllocationChange.emit(true); + this.tabGroup.selectedIndex = (this.advancedPaymentAllocations.length - 1); + this.sendPaymentAllocation(); + } + }); + } + }); + } + + transactionTypeRemoved(transaction: PaymentAllocationTransactionType): void { + this.advancedPaymentAllocations.forEach((item: AdvancedPaymentAllocation, index: number) => { + if (item.transaction.code === transaction.code) { + this.advancedPaymentAllocations.splice(index, 1); + this.paymentAllocationChange.emit(true); + this.tabGroup.selectedIndex = (index - 1); + this.sendPaymentAllocation(); + } + }); } } diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model.ts index adbcdc650..2be28e6b5 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model.ts @@ -1,9 +1,25 @@ -export interface PaymentCode { - name: string; +import { Injectable } from '@angular/core'; + +export interface PaymentAllocationTransactionType { + id: number; + value: string; + code: string; +} + +export interface PaymentAllocationType { + id: number; + value: string; + code: string; +} + +export interface FutureInstallmentAllocationRule { + id: number; + value: string; code: string; } export interface PaymentAllocationOrder { + id?: number; paymentAllocationRule: string; order: number; } @@ -14,40 +30,125 @@ export interface PaymentAllocation { futureInstallmentAllocationRule: string; } -export interface PaymentAllocationTransactionType { - name: string; - code: string; -} - export class PaymentAllocationTransactionTypes { - public static DEFAULT_TRANSACTION: PaymentAllocationTransactionType = { name: 'Default', code: 'DEFAULT' }; - - public static options: PaymentCode[] = [ - this.DEFAULT_TRANSACTION - ]; + public static DEFAULT_TRANSACTION: PaymentAllocationTransactionType = { id: 1, value: 'Default', code: 'DEFAULT' }; } -export class PaymentAllocationTypes { - public static options: PaymentCode[] = [ - { name: 'Past due penalty', code: 'PAST_DUE_PENALTY' }, - { name: 'Past due fee', code: 'PAST_DUE_FEE' }, - { name: 'Past due principal', code: 'PAST_DUE_PRINCIPAL' }, - { name: 'Past due interest', code: 'PAST_DUE_INTEREST' }, - { name: 'Due penalty', code: 'DUE_PENALTY' }, - { name: 'Due fee', code: 'DUE_FEE' }, - { name: 'Due principal', code: 'DUE_PRINCIPAL' }, - { name: 'Due interest', code: 'DUE_INTEREST' }, - { name: 'In advance penalty', code: 'IN_ADVANCE_PENALTY' }, - { name: 'In advance fee', code: 'IN_ADVANCE_FEE' }, - { name: 'In advance principal', code: 'IN_ADVANCE_PRINCIPAL' }, - { name: 'In advance interest', code: 'IN_ADVANCE_INTEREST' } - ]; +export class AdvancedPaymentAllocation { + transaction: PaymentAllocationTransactionType; + paymentAllocationOrder: PaymentAllocationOrder[]; + futureInstallmentAllocationRule: FutureInstallmentAllocationRule; + futureInstallmentAllocationRules: FutureInstallmentAllocationRule[]; } -export class FutureInstallmentAllocationRules { - public static options: PaymentCode[] = [ - { name: 'Next Installment', code: 'NEXT_INSTALLMENT' }, - { name: 'Last Installment', code: 'LAST_INSTALLMENT' }, - { name: 'Reamortization', code: 'REAMORTIZATION' } - ]; +@Injectable({ + providedIn: 'root' +}) +export class AdvancedPaymentStrategy { + + public buildAdvancedPaymentAllocationList(loanProduct: any): AdvancedPaymentAllocation[] { + const advancedPaymentAllocation: AdvancedPaymentAllocation[] = []; + const advancedPaymentAllocationTransactionTypes: PaymentAllocationTransactionType[] = + loanProduct.advancedPaymentAllocationTransactionTypes; + const advancedPaymentAllocationTypes: PaymentAllocationOrder[] = loanProduct.advancedPaymentAllocationTypes; + const advancedPaymentAllocationFutureInstallmentAllocationRules: FutureInstallmentAllocationRule[] = + loanProduct.advancedPaymentAllocationFutureInstallmentAllocationRules; + loanProduct.paymentAllocation.forEach((item: PaymentAllocation) => { + advancedPaymentAllocation.push({ + transaction: this.getItemByCode(item.transactionType, advancedPaymentAllocationTransactionTypes), + paymentAllocationOrder: this.buildCurrentPaymentAllocationOrder(item.paymentAllocationOrder, + advancedPaymentAllocationTypes), + futureInstallmentAllocationRule: this.getItemByCode(item.futureInstallmentAllocationRule, + advancedPaymentAllocationFutureInstallmentAllocationRules), + futureInstallmentAllocationRules: advancedPaymentAllocationFutureInstallmentAllocationRules, + }); + }); + // If this is Empty, add the Default + if (advancedPaymentAllocation.length === 0) { + advancedPaymentAllocation.push({ + transaction: PaymentAllocationTransactionTypes.DEFAULT_TRANSACTION, + paymentAllocationOrder: this.buildPaymentAllocationTransactionOrder(true, [], loanProduct.advancedPaymentAllocationTypes), + futureInstallmentAllocationRule: loanProduct.advancedPaymentAllocationFutureInstallmentAllocationRules[0], + futureInstallmentAllocationRules: loanProduct.advancedPaymentAllocationFutureInstallmentAllocationRules, + }); + } + return advancedPaymentAllocation; + } + + public buildAdvancedPaymentAllocation(forDefault: boolean, transaction: PaymentAllocationTransactionType, + currentItems: PaymentAllocationOrder[], + futureInstallmentAllocationRules: FutureInstallmentAllocationRule[]): AdvancedPaymentAllocation { + return { + transaction: transaction, + paymentAllocationOrder: this.buildPaymentAllocationTransactionOrder(forDefault, currentItems, currentItems), + futureInstallmentAllocationRule: futureInstallmentAllocationRules[0], + futureInstallmentAllocationRules: futureInstallmentAllocationRules, + }; + } + + public buildPaymentAllocationTransactionOrder(forDefault: boolean, currentItems: PaymentAllocationOrder[], defaultItems: PaymentAllocationOrder[]): PaymentAllocationOrder[] { + const paymentAllocationOrder: PaymentAllocationOrder[] = []; + if (forDefault) { + return defaultItems; + } else { + currentItems.forEach((currentItem: PaymentAllocationOrder) => { + defaultItems.forEach((item: PaymentAllocationOrder) => { + if (currentItem.id === item.id) { + paymentAllocationOrder.push(item); + } + }); + }); + } + return paymentAllocationOrder; + } + + public buildPaymentAllocations(advancedPaymentAllocations: AdvancedPaymentAllocation[]): PaymentAllocation[] { + const paymentAllocations: PaymentAllocation[] = []; + advancedPaymentAllocations.forEach((paymentAllocation: AdvancedPaymentAllocation) => { + paymentAllocations.push({ + transactionType: paymentAllocation.transaction.code, + paymentAllocationOrder: this.buildPaymentAllocationOrder(paymentAllocation.paymentAllocationOrder), + futureInstallmentAllocationRule: paymentAllocation.futureInstallmentAllocationRule.code + }); + }); + + return paymentAllocations; + } + + public buildPaymentAllocationOrder(paymentAllocationOrder: PaymentAllocationOrder[]): PaymentAllocationOrder[] { + const paymentAllocations: any[] = []; + paymentAllocationOrder.forEach((item: any, index: number) => { + paymentAllocations.push({ + order: (index + 1), + paymentAllocationRule: item.code + }); + }); + + return paymentAllocations; + } + + public buildCurrentPaymentAllocationOrder(currentItems: any[], defaultItems: PaymentAllocationOrder[]): + PaymentAllocationOrder[] { + const paymentAllocationOrder: PaymentAllocationOrder[] = []; + currentItems.forEach((item: any) => { + paymentAllocationOrder.push(this.getItemByCode(item.paymentAllocationRule, defaultItems)); + }); + return paymentAllocationOrder; + } + + public getItemByCode(code: string, + options: any[]): any { + let transaction: any; + options.forEach((option: any) => { + if (option.code === code) { + transaction = option; + } + }); + return transaction; + } + + public isDefault(transaction: PaymentAllocationTransactionType): boolean { + return (transaction.code === PaymentAllocationTransactionTypes.DEFAULT_TRANSACTION.code); + } + } diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html index cb209026d..8afe5fe34 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.html @@ -324,42 +324,19 @@
Repayment Strategy: - {{ loanProduct.transactionProcessingStrategyCode | + {{ loanProduct.transactionProcessingStrategyCode | find:loanProductsTemplate.transactionProcessingStrategyOptions:'code':'name' }}
-
-
-
- Transaction Type: - {{ paymentAllocation.transactionType }} -
- -
- Future Installment Allocation: - {{ paymentAllocation.futureInstallmentAllocationRule }} -
- -
- Payment Allocation Order - - - - - - - - - - - - - - -
Payment Allocation RuleOrder
{{ paymentAllocation.paymentAllocationRule }}{{ (idx + 1) }}
-
-
-
+
+ Advanced Payment Allocation Transactions: + + + + + +
diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.scss b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.scss index 87258dacb..40f3944d7 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.scss +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.scss @@ -1,3 +1,5 @@ +@import "assets/styles/colours"; + table { width: 100%; } @@ -22,3 +24,7 @@ mat-divider { .margin-t { margin-top: 1em; } + +.repayment-strategy { + color: $status-approved; +} diff --git a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.ts b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.ts index 6fdda9a55..e6884c25e 100644 --- a/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.ts +++ b/src/app/products/loan-products/loan-product-stepper/loan-product-preview-step/loan-product-preview-step.component.ts @@ -1,11 +1,11 @@ -import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; @Component({ selector: 'mifosx-loan-product-preview-step', templateUrl: './loan-product-preview-step.component.html', styleUrls: ['./loan-product-preview-step.component.scss'] }) -export class LoanProductPreviewStepComponent implements OnInit { +export class LoanProductPreviewStepComponent implements OnInit, OnChanges { @Input() loanProductsTemplate: any; @Input() accountingRuleData: any; @@ -17,9 +17,16 @@ export class LoanProductPreviewStepComponent implements OnInit { paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId']; feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId']; + isAdvancedPaymentAllocation = false; + constructor() { } ngOnInit() { + this.isAdvancedPaymentAllocation = (this.loanProduct.transactionProcessingStrategyCode === 'advanced-payment-allocation-strategy'); + } + + ngOnChanges(changes: SimpleChanges): void { + this.isAdvancedPaymentAllocation = (this.loanProduct.transactionProcessingStrategyCode === 'advanced-payment-allocation-strategy'); } } diff --git a/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.html b/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.html index e9431490c..6810658e7 100644 --- a/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.html +++ b/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.html @@ -328,41 +328,18 @@
Repayment Strategy: - {{ loanProduct.transactionProcessingStrategyName }} + {{ loanProduct.transactionProcessingStrategyName }}
-
-
- Transaction Type: - {{ paymentAllocation.transactionType }} -
- -
- Future Installment Allocation: - {{ paymentAllocation.futureInstallmentAllocationRule }} -
- -
- Payment Allocation Order - - - - - - - - - - - - - - -
Payment Allocation RuleOrder
{{ paymentAllocation.paymentAllocationRule }}{{ (idx + 1) }}
-
-
-
+ Advanced Payment Allocation Transactions: + + + + + +
diff --git a/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.scss b/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.scss index fafc40cc8..9135adef8 100644 --- a/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.scss +++ b/src/app/products/loan-products/view-loan-product/general-tab/general-tab.component.scss @@ -20,3 +20,7 @@ font-weight: 200; color: $status-approved; } + +.repayment-strategy { + color: $status-approved; +} diff --git a/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.html b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.html new file mode 100644 index 000000000..2d242ee34 --- /dev/null +++ b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.html @@ -0,0 +1,42 @@ + + + +
+ Transaction Type: + {{ paymentAllocation.transactionType }} +
+
+
+ +
+
+ Transaction Type: + {{ paymentAllocation.transactionType }} +
+ +
+ Future Installment Allocation: + {{ paymentAllocation.futureInstallmentAllocationRule }} +
+ +
+ Payment Allocation Order + + + + + + + + + + + + + + +
Payment Allocation RuleOrder
{{ paymentAllocation.paymentAllocationRule }}{{ (idx + 1) }}
+
+
+
+
diff --git a/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.scss b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.scss new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.scss @@ -0,0 +1 @@ + diff --git a/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.spec.ts b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.spec.ts new file mode 100644 index 000000000..9a9ee51e5 --- /dev/null +++ b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ViewAdvancePaymenyAllocationComponent } from './view-advance-paymeny-allocation.component'; + +describe('ViewAdvancePaymenyAllocationComponent', () => { + let component: ViewAdvancePaymenyAllocationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ViewAdvancePaymenyAllocationComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ViewAdvancePaymenyAllocationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.ts b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.ts new file mode 100644 index 000000000..c69685ffe --- /dev/null +++ b/src/app/products/loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { PaymentAllocation } from 'app/products/loan-products/loan-product-stepper/loan-product-payment-strategy-step/payment-allocation-model'; + +@Component({ + selector: 'mifosx-view-advance-paymeny-allocation', + templateUrl: './view-advance-paymeny-allocation.component.html', + styleUrls: ['./view-advance-paymeny-allocation.component.scss'] +}) +export class ViewAdvancePaymenyAllocationComponent implements OnInit { + + @Input() paymentAllocation: PaymentAllocation; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/products/products.module.ts b/src/app/products/products.module.ts index d9baef068..57ba92d0e 100644 --- a/src/app/products/products.module.ts +++ b/src/app/products/products.module.ts @@ -117,6 +117,8 @@ import { RecurringDepositGeneralTabComponent } from './recurring-deposit-product import { ShareProductGeneralTabComponent } from './share-products/view-share-product/share-product-general-tab/share-product-general-tab.component'; import { ShareProductDatatableTabComponent } from './share-products/view-share-product/share-product-datatable-tab/share-product-datatable-tab.component'; import { LoanProductPaymentStrategyStepComponent } from './loan-products/loan-product-stepper/loan-product-payment-strategy-step/loan-product-payment-strategy-step.component'; +import { ViewAdvancePaymenyAllocationComponent } from './loan-products/view-loan-product/shared/view-advance-paymeny-allocation/view-advance-paymeny-allocation.component'; +import { AdvancePaymentAllocationTabComponent } from './loan-products/loan-product-stepper/loan-product-payment-strategy-step/advance-payment-allocation-tab/advance-payment-allocation-tab.component'; /** * Products Module @@ -241,7 +243,9 @@ import { LoanProductPaymentStrategyStepComponent } from './loan-products/loan-pr RecurringDepositDatatableTabComponent, RecurringDepositGeneralTabComponent, ShareProductGeneralTabComponent, - ShareProductDatatableTabComponent + ShareProductDatatableTabComponent, + ViewAdvancePaymenyAllocationComponent, + AdvancePaymentAllocationTabComponent ] }) export class ProductsModule { } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 7a7deb492..1aba36c84 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -42,6 +42,7 @@ import { ViewJournalEntryTransactionComponent } from './accounting/view-journal- import { AccountNumberComponent } from './account-number/account-number.component'; import { EntityNameComponent } from './entity-name/entity-name.component'; import { TransactionPaymentDetailComponent } from './transaction-payment-detail/transaction-payment-detail.component'; +import { StepperButtonsComponent } from './steppers/stepper-buttons/stepper-buttons.component'; /** * Shared Module @@ -90,7 +91,8 @@ import { TransactionPaymentDetailComponent } from './transaction-payment-detail/ ViewJournalEntryTransactionComponent, AccountNumberComponent, EntityNameComponent, - TransactionPaymentDetailComponent + TransactionPaymentDetailComponent, + StepperButtonsComponent ], exports: [ FileUploadComponent, @@ -117,7 +119,8 @@ import { TransactionPaymentDetailComponent } from './transaction-payment-detail/ ViewJournalEntryTransactionComponent, SvgIconComponent, EntityNameComponent, - TransactionPaymentDetailComponent + TransactionPaymentDetailComponent, + StepperButtonsComponent ] }) export class SharedModule { } diff --git a/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.html b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.html new file mode 100644 index 000000000..8dbdc4869 --- /dev/null +++ b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.html @@ -0,0 +1,11 @@ + +
+ + +
diff --git a/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.scss b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.spec.ts b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.spec.ts new file mode 100644 index 000000000..77d17703f --- /dev/null +++ b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StepperButtonsComponent } from './stepper-buttons.component'; + +describe('StepperButtonsComponent', () => { + let component: StepperButtonsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ StepperButtonsComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(StepperButtonsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.ts b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.ts new file mode 100644 index 000000000..716cc4387 --- /dev/null +++ b/src/app/shared/steppers/stepper-buttons/stepper-buttons.component.ts @@ -0,0 +1,18 @@ +import { Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'mifosx-stepper-buttons', + templateUrl: './stepper-buttons.component.html', + styleUrls: ['./stepper-buttons.component.scss'] +}) +export class StepperButtonsComponent implements OnInit { + + @Input() disablePrevious = false; + @Input() disableNext = false; + + constructor() { } + + ngOnInit(): void { + } + +}