Savings and Deposit products using Accrual periodic accounting

This commit is contained in:
Jose Alberto Hernandez
2024-02-26 22:42:27 -06:00
parent e2c6562656
commit d6dec3dc8d
48 changed files with 1320 additions and 932 deletions
@@ -29,7 +29,7 @@ export class SidenavComponent implements OnInit, AfterViewInit {
/** True if sidenav is in collapsed state. */
@Input() sidenavCollapsed: boolean;
/** Tooltip position */
tooltipPosition: string = 'after';
tooltipPosition = 'after';
/** Username of authenticated user. */
username: string;
/** Array of all user activities */
+64
View File
@@ -0,0 +1,64 @@
import { Injectable } from '@angular/core';
import { AccountingMapping, GLAccount } from 'app/shared/models/general.model';
import { OptionData } from 'app/shared/models/option-data.model';
@Injectable({
providedIn: 'root'
})
export class Accounting {
public getAccountingRulesForSavings(): string[] {
return ['None', 'Cash', 'Accrual (periodic)'];
}
public isNoneAccounting(accountingRule: OptionData): boolean {
return (accountingRule.id === 1);
}
public isNoneAccountingRuleId(accountingRuleId: number): boolean {
return (accountingRuleId === 1);
}
public isCashOrAccrualAccounting(accountingRule: OptionData): boolean {
return ((accountingRule.id === 2) || (accountingRule.id === 3));
}
public isCashOrAccrualAccountingRuleId(accountingRuleId: number): boolean {
return ((accountingRuleId === 2) || (accountingRuleId === 3));
}
public isAccrualAccounting(accountingRule: OptionData): boolean {
return (accountingRule.id === 3);
}
public isAccrualAccountingRuleId(accountingRuleId: number): boolean {
return (accountingRuleId === 3);
}
public getAccountingRuleFrom(accountingRuleId: number): OptionData {
if (accountingRuleId === 1) {
return {code: 'NONE', id: accountingRuleId, value: 'None'};
} else if (accountingRuleId === 2) {
return {code: 'CASH', id: accountingRuleId, value: 'Cash'};
} else if (accountingRuleId === 3) {
return {code: 'ACCRUAL_PERIODIC', id: accountingRuleId, value: 'Accural (periodic)'};
} else if (accountingRuleId === 4) {
return {code: 'ACCRUAL_UPFRONT', id: accountingRuleId, value: 'Accural (upfront)'};
}
return {code: 'INVALID', id: accountingRuleId, value: 'Invalid'};
}
public glAccountLookUp(glAccountId: number, glAccounts: GLAccount[]): AccountingMapping {
let accountMapping: AccountingMapping | null = null;
if (glAccountId) {
glAccounts.some((glAccount: GLAccount) => {
if (glAccount.id === glAccountId) {
accountMapping = { id: glAccount.id, name: glAccount.name, glCode: glAccount.glCode };
}
});
}
return accountMapping;
}
}
@@ -230,7 +230,7 @@ export class RecurringDepositsAccountViewComponent implements OnInit {
private postInterest() {
const postInterestAccountDialogRef = this.dialog.open(RecurringDepositConfirmationDialogComponent, {
data: { heading: this.translateService.instant('labels.heading.Post Interest'),
dialogContext: this.translateService.instant('lables.text.Are you sure you want to post interest') + ' ?'
dialogContext: this.translateService.instant('labels.text.Are you sure you want to post interest') + ' ?'
}
});
postInterestAccountDialogRef.afterClosed().subscribe((response: any) => {
@@ -14,6 +14,7 @@ import { FixedDepositProductAccountingStepComponent } from '../fixed-deposit-pro
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-create-fixed-deposit-product',
@@ -31,7 +32,7 @@ export class CreateFixedDepositProductComponent implements OnInit {
@ViewChild(FixedDepositProductAccountingStepComponent, { static: true }) fixedDepositProductAccountingStep: FixedDepositProductAccountingStepComponent;
fixedDepositProductsTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -43,10 +44,12 @@ export class CreateFixedDepositProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { fixedDepositProductsTemplate: any }) => {
this.fixedDepositProductsTemplate = data.fixedDepositProductsTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -14,6 +14,7 @@ import { FixedDepositProductAccountingStepComponent } from '../fixed-deposit-pro
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-edit-fixed-deposit-product',
@@ -31,7 +32,7 @@ export class EditFixedDepositProductComponent implements OnInit {
@ViewChild(FixedDepositProductAccountingStepComponent, { static: true }) fixedDepositProductAccountingStep: FixedDepositProductAccountingStepComponent;
fixedDepositProductsTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -43,10 +44,12 @@ export class EditFixedDepositProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { fixedDepositProductAndTemplate: any }) => {
this.fixedDepositProductsTemplate = data.fixedDepositProductAndTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -10,93 +10,93 @@
<mat-divider fxFlex="98%"></mat-divider>
<div *ngIf="fixedDepositProductAccountingForm.value.accountingRule === 2" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<div *ngIf="isCashOrAccrualAccounting()" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<h4 fxFlex="98%" class="mat-h4">Assets</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Assets' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Saving reference</mat-label>
<mat-select formControlName="savingsReferenceAccountId" required>
<mat-option *ngFor="let assetAccount of assetAccountData" [value]="assetAccount.id">
({{ assetAccount.glCode }}) {{ assetAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Saving reference is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.savingsReferenceAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Saving reference'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="fixedDepositProductAccountingForm.controls.feesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Fees Receivable'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="fixedDepositProductAccountingForm.controls.penaltiesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Penalties Receivable'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Liabilities</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Liabilities' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Saving control</mat-label>
<mat-select formControlName="savingsControlAccountId" required>
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
({{ liabilityAccount.glCode }}) {{ liabilityAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Saving control is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.savingsControlAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Saving control'"
>
</mifosx-gl-account-selector>
<mat-form-field fxFlex="48%">
<mat-label>Savings transfers in suspense</mat-label>
<mat-select formControlName="transfersInSuspenseAccountId" required>
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
({{ liabilityAccount.glCode }}) {{ liabilityAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Savings transfers in suspense is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.transfersInSuspenseAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Savings transfers in suspense'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="fixedDepositProductAccountingForm.controls.interestPayableAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Interest Payable'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Expenses</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Expenses' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Interest on savings</mat-label>
<mat-select formControlName="interestOnSavingsAccountId" required>
<mat-option *ngFor="let expenseAccount of expenseAccountData" [value]="expenseAccount.id">
({{ expenseAccount.glCode }}) {{ expenseAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Interest on savings is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.interestOnSavingsAccountId"
[glAccountList]="expenseAccountData"
[required]="true"
[inputLabel]="'Interest on savings'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Income</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Income' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Income from fees</mat-label>
<mat-select formControlName="incomeFromFeeAccountId" required>
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
({{ incomeAccount.glCode }}) {{ incomeAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Income from fees Repayments is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.incomeFromFeeAccountId"
[glAccountList]="incomeAccountData"
[required]="true"
[inputLabel]="'Income from fees'"
>
</mifosx-gl-account-selector>
<mat-form-field fxFlex="48%">
<mat-label>Income from penalties</mat-label>
<mat-select formControlName="incomeFromPenaltyAccountId" required>
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
({{ incomeAccount.glCode }}) {{ incomeAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Income from penalties is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="fixedDepositProductAccountingForm.controls.incomeFromPenaltyAccountId"
[glAccountList]="incomeAccountData"
[required]="true"
[inputLabel]="'Income from penalties'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
@@ -7,6 +7,7 @@ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.co
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-fixed-deposit-product-accounting-step',
@@ -33,7 +34,8 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId', 'actions'];
constructor(private formBuilder: UntypedFormBuilder,
public dialog: MatDialog) {
public dialog: MatDialog,
private accounting: Accounting) {
this.createfixedDepositProductAccountingForm();
this.setConditionalControls();
}
@@ -52,10 +54,10 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
}
assignAccountingStepData() {
if (this.fixedDepositProductsTemplate.accountingRule.id === 2) {
this.fixedDepositProductAccountingForm.patchValue({
'accountingRule': this.fixedDepositProductsTemplate.accountingRule.id
});
this.fixedDepositProductAccountingForm.patchValue({
'accountingRule': this.fixedDepositProductsTemplate.accountingRule.id
});
if (this.isCashOrAccrualAccounting()) {
this.fixedDepositProductAccountingForm.patchValue({
'savingsReferenceAccountId': this.fixedDepositProductsTemplate.accountingMappings.savingsReferenceAccount.id,
'savingsControlAccountId': this.fixedDepositProductsTemplate.accountingMappings.savingsControlAccount.id,
@@ -64,6 +66,15 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
'incomeFromPenaltyAccountId': this.fixedDepositProductsTemplate.accountingMappings.incomeFromPenaltyAccount.id,
'interestOnSavingsAccountId': this.fixedDepositProductsTemplate.accountingMappings.interestOnSavingsAccount.id
});
if (this.isAccrualAccounting()) {
this.fixedDepositProductAccountingForm.patchValue({
'feesReceivableAccountId': this.fixedDepositProductsTemplate.accountingMappings.feeReceivableAccount.id,
'penaltiesReceivableAccountId': this.fixedDepositProductsTemplate.accountingMappings.penaltyReceivableAccount.id,
'interestPayableAccountId': this.fixedDepositProductsTemplate.accountingMappings.interestPayableAccount.id
});
}
if (this.fixedDepositProductsTemplate.paymentChannelToFundSourceMappings || this.fixedDepositProductsTemplate.feeToIncomeAccountMappings || this.fixedDepositProductsTemplate.penaltyToIncomeAccountMappings) {
this.fixedDepositProductAccountingForm.patchValue({
'advancedAccountingRules': true
@@ -111,7 +122,7 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
setConditionalControls() {
this.fixedDepositProductAccountingForm.get('accountingRule').valueChanges
.subscribe((accountingRule: any) => {
if (accountingRule === 2) {
if (accountingRule === 2 || accountingRule === 3) {
this.fixedDepositProductAccountingForm.addControl('savingsReferenceAccountId', new UntypedFormControl('', Validators.required));
this.fixedDepositProductAccountingForm.addControl('savingsControlAccountId', new UntypedFormControl('', Validators.required));
this.fixedDepositProductAccountingForm.addControl('transfersInSuspenseAccountId', new UntypedFormControl('', Validators.required));
@@ -120,6 +131,12 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
this.fixedDepositProductAccountingForm.addControl('incomeFromPenaltyAccountId', new UntypedFormControl('', Validators.required));
this.fixedDepositProductAccountingForm.addControl('advancedAccountingRules', new UntypedFormControl(false));
if (accountingRule === 3) {
this.fixedDepositProductAccountingForm.addControl('feesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.fixedDepositProductAccountingForm.addControl('penaltiesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.fixedDepositProductAccountingForm.addControl('interestPayableAccountId', new UntypedFormControl('', Validators.required));
}
this.fixedDepositProductAccountingForm.get('advancedAccountingRules').valueChanges
.subscribe((advancedAccountingRules: boolean) => {
if (advancedAccountingRules) {
@@ -144,6 +161,9 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
this.fixedDepositProductAccountingForm.removeControl('incomeFromInterestId');
this.fixedDepositProductAccountingForm.removeControl('advancedAccountingRules');
this.fixedDepositProductAccountingForm.removeControl('escheatLiabilityId');
this.fixedDepositProductAccountingForm.removeControl('feesReceivableAccountId');
this.fixedDepositProductAccountingForm.removeControl('penaltiesReceivableAccountId');
this.fixedDepositProductAccountingForm.removeControl('interestPayableAccountId');
}
});
}
@@ -269,4 +289,12 @@ export class FixedDepositProductAccountingStepComponent implements OnInit {
return this.fixedDepositProductAccountingForm.value;
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccountingRuleId(this.fixedDepositProductAccountingForm.value.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccountingRuleId(this.fixedDepositProductAccountingForm.value.accountingRule);
}
}
@@ -111,6 +111,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
this.chartsDetail[i].chartSlabs.forEach((chartSlabDetail: any, j: number) => {
const chartSlabInfo = this.formBuilder.group({
id: [chartSlabDetail.id],
amountRangeFrom: [chartSlabDetail.amountRangeFrom || ''],
amountRangeTo: [chartSlabDetail.amountRangeTo || ''],
annualInterestRate: [chartSlabDetail.annualInterestRate, Validators.required],
@@ -155,6 +156,9 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
description: chartData.description,
chartSlabs: this.getChartSlabsData(chartData)
};
if (chartData.id) {
chart['id'] = chartData.id;
}
this.chartsDetail.push(chart);
});
this.fixedDepositProductInterestRateChartForm.patchValue({
@@ -183,6 +187,9 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
toPeriod: eachChartSlabData.toPeriod,
incentives: this.getIncentivesData(chartSlabData)
};
if (eachChartSlabData.id) {
chartSlab['id'] = eachChartSlabData.id;
}
chartSlabs.push(chartSlab);
});
return chartSlabs;
@@ -225,6 +232,7 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
createChartForm(): UntypedFormGroup {
return this.formBuilder.group({
'id': [null],
'name': [''],
'description': [''],
'fromDate': ['', Validators.required],
@@ -382,6 +390,9 @@ export class FixedDepositProductInterestRateChartStepComponent implements OnInit
if (chart.endDate === '') {
delete chart.endDate;
}
if (chart.id === null) {
delete chart.id;
}
}
return fixedDepositProductInterestRateChart;
}
@@ -346,148 +346,107 @@
<mat-divider fxFlexFill></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ accountingRuleData[fixedDepositProduct.accountingRule-1] }}</span>
</div>
<mifosx-view-savings-accounting-details *ngIf="!isNoneAccounting()"
[accountingRule]="accountingRule"
[accountingMappings]="accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div fxFlexFill *ngIf="fixedDepositProduct.accountingRule === 2" fxLayout="row wrap" fxLayout.lt-md="column">
<div
*ngIf="fixedDepositProduct.advancedAccountingRules && (fixedDepositProduct.paymentChannelToFundSourceMappings?.length || fixedDepositProduct.feeToIncomeAccountMappings?.length || fixedDepositProduct.penaltyToIncomeAccountMappings?.length)"
fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">Assets</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="fixedDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:fixedDepositProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
<div fxFlexFill>
<span fxFlex="40%">Saving reference:</span>
<span fxFlex="60%">{{ fixedDepositProduct.savingsReferenceAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
<div *ngIf="fixedDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:fixedDepositProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving control:</span>
<span fxFlex="60%">{{ fixedDepositProduct.savingsControlAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Savings transfers in suspense:</span>
<span fxFlex="60%">{{ fixedDepositProduct.transfersInSuspenseAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Expenses</h4>
<div *ngIf="fixedDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<div fxFlexFill>
<span fxFlex="40%">Interest on savings:</span>
<span fxFlex="60%">{{ fixedDepositProduct.interestOnSavingsAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
</div>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<h4 fxFlexFill class="mat-h4">Income</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.penaltyToIncomeAccountMappings">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Income from fees:</span>
<span fxFlex="60%">{{ fixedDepositProduct.incomeFromFeeAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Income from penalties:</span>
<span fxFlex="60%">{{ fixedDepositProduct.incomeFromPenaltyAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:fixedDepositProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<div
*ngIf="fixedDepositProduct.advancedAccountingRules && (fixedDepositProduct.paymentChannelToFundSourceMappings?.length || fixedDepositProduct.feeToIncomeAccountMappings?.length || fixedDepositProduct.penaltyToIncomeAccountMappings?.length)"
fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="fixedDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:fixedDepositProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="fixedDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:fixedDepositProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="fixedDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProduct.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:fixedDepositProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId |
find:fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -1,5 +1,7 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Component, OnInit, Input, Output, EventEmitter, SimpleChanges, OnChanges } from '@angular/core';
import { trigger, state, transition, animate, style } from '@angular/animations';
import { Accounting } from 'app/core/utils/accounting';
import { OptionData } from 'app/shared/models/option-data.model';
@Component({
selector: 'mifosx-fixed-deposit-product-preview-step',
@@ -13,7 +15,7 @@ import { trigger, state, transition, animate, style } from '@angular/animations'
])
]
})
export class FixedDepositProductPreviewStepComponent implements OnInit {
export class FixedDepositProductPreviewStepComponent implements OnInit, OnChanges {
@Input() fixedDepositProductsTemplate: any;
@Input() chartSlabsDisplayedColumns: any[];
@@ -29,9 +31,55 @@ export class FixedDepositProductPreviewStepComponent implements OnInit {
expandChartSlabIndex: number[] = [];
constructor() { }
accountingMappings: any = {};
accountingRule: OptionData;
constructor(private accounting: Accounting) { }
ngOnInit() {
this.setCurrentValues();
}
ngOnChanges(changes: SimpleChanges): void {
this.setCurrentValues();
}
setCurrentValues(): void {
if (this.isCashOrAccrualAccounting()) {
this.accountingRule = this.accounting.getAccountingRuleFrom(this.fixedDepositProduct.accountingRule);
const assetAccountData = this.fixedDepositProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
const incomeAccountData = this.fixedDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
const expenseAccountData = this.fixedDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
const liabilityAccountData = this.fixedDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
this.accountingMappings = {
'savingsReferenceAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.savingsReferenceAccountId, assetAccountData),
'savingsControlAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.savingsControlAccountId, liabilityAccountData),
'transfersInSuspenseAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.transfersInSuspenseAccountId, liabilityAccountData),
'interestOnSavingsAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.interestOnSavingsAccountId, expenseAccountData),
'incomeFromFeeAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.incomeFromFeeAccountId, incomeAccountData),
'incomeFromPenaltyAccount': this.accounting.glAccountLookUp(this.fixedDepositProduct.incomeFromPenaltyAccountId, incomeAccountData)
};
if (this.isAccrualAccounting()) {
this.accountingMappings['feeReceivableAccount'] = this.accounting.glAccountLookUp(this.fixedDepositProduct.feesReceivableAccountId, assetAccountData);
this.accountingMappings['penaltyReceivableAccount'] = this.accounting.glAccountLookUp(this.fixedDepositProduct.penaltiesReceivableAccountId, assetAccountData);
this.accountingMappings['interestPayableAccount'] = this.accounting.glAccountLookUp(this.fixedDepositProduct.interestPayableAccountId, liabilityAccountData);
}
}
}
isNoneAccounting(): boolean {
return this.accounting.isNoneAccountingRuleId(this.fixedDepositProduct.accountingRule);
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccountingRuleId(this.fixedDepositProduct.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccountingRuleId(this.fixedDepositProduct.accountingRule);
}
}
@@ -367,141 +367,105 @@
<mat-divider [inset]="true"></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingRule.value }}</span>
</div>
<mifosx-view-savings-accounting-details class="container"
[accountingRule]="fixedDepositProductData.accountingRule"
[accountingMappings]="fixedDepositProductData.accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div fxFlexFill *ngIf="fixedDepositProductData.accountingRule.id === 2" fxLayout="row wrap"
fxLayout.lt-md="column">
<div fxFlexFill
*ngIf="fixedDepositProductData.advancedAccountingRules && (fixedDepositProductData.paymentChannelToFundSourceMappings?.length || fixedDepositProductData.feeToIncomeAccountMappings?.length || fixedDepositProductData.penaltyToIncomeAccountMappings?.length)"
fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">Assets</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving reference:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.savingsReferenceAccount.name }}</span>
</div>
<mat-divider [inset]="true"></mat-divider>
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
<hr>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving control:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.savingsControlAccount.name }}</span>
<span fxFlex="40%">Savings transfers in suspense:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.transfersInSuspenseAccount.name }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Expenses</h4>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Interest on savings:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.interestOnSavingsAccount.name }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Income</h4>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Income from fees:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.incomeFromFeeAccount.name }}</span>
<span fxFlex="40%">Income from penalties:</span>
<span fxFlex="60%">{{ fixedDepositProductData.accountingMappings.incomeFromPenaltyAccount.name }}</span>
</div>
<div fxFlexFill
*ngIf="fixedDepositProductData.advancedAccountingRules && (fixedDepositProductData.paymentChannelToFundSourceMappings?.length || fixedDepositProductData.feeToIncomeAccountMappings?.length || fixedDepositProductData.penaltyToIncomeAccountMappings?.length)"
<div *ngIf="fixedDepositProductData.paymentChannelToFundSourceMappings?.length" fxFlexFill
fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Configure Fund Sources for Payment Channels</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.paymentChannelToFundSourceMappings">
<mat-divider [inset]="true"></mat-divider>
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
<hr>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<div *ngIf="fixedDepositProductData.paymentChannelToFundSourceMappings?.length" fxFlexFill
fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Configure Fund Sources for Payment Channels</h4>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.paymentChannelToFundSourceMappings">
</table>
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
</div>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<div *ngIf="fixedDepositProductData.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
</table>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.feeToIncomeAccountMappings">
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
<div *ngIf="fixedDepositProductData.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.feeToIncomeAccountMappings">
</table>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
</div>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
<div *ngIf="fixedDepositProductData.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
</table>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.penaltyToIncomeAccountMappings">
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
<div *ngIf="fixedDepositProductData.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="fixedDepositProductData.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -1,5 +1,9 @@
@import "assets/styles/helper";
.container {
width: 100%;
}
.tab-container {
padding: 1%;
margin: 1%;
@@ -11,10 +15,6 @@
color: $status-approved;
}
table {
width: 100%;
}
.mat-elevation-z1 {
margin: 1em 0 1.5em 0;
}
@@ -14,6 +14,7 @@ import { RecurringDepositProductAccountingStepComponent } from '../recurring-dep
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-create-recurring-deposit-product',
@@ -31,7 +32,7 @@ export class CreateRecurringDepositProductComponent implements OnInit {
@ViewChild(RecurringDepositProductAccountingStepComponent, { static: true }) recurringDepositProductAccountingStep: RecurringDepositProductAccountingStepComponent;
recurringDepositProductsTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -43,10 +44,12 @@ export class CreateRecurringDepositProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { recurringDepositProductsTemplate: any }) => {
this.recurringDepositProductsTemplate = data.recurringDepositProductsTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -14,6 +14,7 @@ import { RecurringDepositProductAccountingStepComponent } from '../recurring-dep
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-edit-recurring-deposit-product',
@@ -31,7 +32,7 @@ export class EditRecurringDepositProductComponent implements OnInit {
@ViewChild(RecurringDepositProductAccountingStepComponent, { static: true }) recurringDepositProductAccountingStep: RecurringDepositProductAccountingStepComponent;
recurringDepositProductsTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -43,10 +44,12 @@ export class EditRecurringDepositProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { recurringDepositProductAndTemplate: any }) => {
this.recurringDepositProductsTemplate = data.recurringDepositProductAndTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -11,94 +11,93 @@
<mat-divider fxFlex="98%"></mat-divider>
<div *ngIf="recurringDepositProductAccountingForm.value.accountingRule === 2" fxFlexFill fxLayout="row wrap"
fxLayoutGap="2%" fxLayout.lt-md="column">
<div *ngIf="isCashOrAccrualAccounting()" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<h4 fxFlex="98%" class="mat-h4">Assets</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Assets' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Saving reference</mat-label>
<mat-select formControlName="savingsReferenceAccountId" required>
<mat-option *ngFor="let assetAccount of assetAccountData" [value]="assetAccount.id">
({{ assetAccount.glCode }}) {{ assetAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Saving reference is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.savingsReferenceAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Saving reference'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="recurringDepositProductAccountingForm.controls.feesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Fees Receivable'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="recurringDepositProductAccountingForm.controls.penaltiesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Penalties Receivable'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Liabilities</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Liabilities' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Saving control</mat-label>
<mat-select formControlName="savingsControlAccountId" required>
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
({{ liabilityAccount.glCode }}) {{ liabilityAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Saving control is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.savingsControlAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Saving control'"
>
</mifosx-gl-account-selector>
<mat-form-field fxFlex="48%">
<mat-label>Savings transfers in suspense</mat-label>
<mat-select formControlName="transfersInSuspenseAccountId" required>
<mat-option *ngFor="let liabilityAccount of liabilityAccountData" [value]="liabilityAccount.id">
({{ liabilityAccount.glCode }}) {{ liabilityAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Savings transfers in suspense is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.transfersInSuspenseAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Savings transfers in suspense'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="recurringDepositProductAccountingForm.controls.interestPayableAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Interest Payable'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Expenses</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Expenses' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Interest on savings</mat-label>
<mat-select formControlName="interestOnSavingsAccountId" required>
<mat-option *ngFor="let expenseAccount of expenseAccountData" [value]="expenseAccount.id">
({{ expenseAccount.glCode }}) {{ expenseAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Interest on savings is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.interestOnSavingsAccountId"
[glAccountList]="expenseAccountData"
[required]="true"
[inputLabel]="'Interest on savings'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">Income</h4>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Income' | translate}}</h4>
<mat-form-field fxFlex="48%">
<mat-label>Income from fees</mat-label>
<mat-select formControlName="incomeFromFeeAccountId" required>
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
({{ incomeAccount.glCode }}) {{ incomeAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Income from fees Repayments is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.incomeFromFeeAccountId"
[glAccountList]="incomeAccountData"
[required]="true"
[inputLabel]="'Income from fees'"
>
</mifosx-gl-account-selector>
<mat-form-field fxFlex="48%">
<mat-label>Income from penalties</mat-label>
<mat-select formControlName="incomeFromPenaltyAccountId" required>
<mat-option *ngFor="let incomeAccount of incomeAccountData" [value]="incomeAccount.id">
({{ incomeAccount.glCode }}) {{ incomeAccount.name }}
</mat-option>
</mat-select>
<mat-error>
Income from penalties is <strong>required</strong>
</mat-error>
</mat-form-field>
<mifosx-gl-account-selector fxFlex="48%"
[inputFormControl]="recurringDepositProductAccountingForm.controls.incomeFromPenaltyAccountId"
[glAccountList]="incomeAccountData"
[required]="true"
[inputLabel]="'Income from penalties'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
@@ -7,6 +7,7 @@ import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.co
import { FormfieldBase } from 'app/shared/form-dialog/formfield/model/formfield-base';
import { SelectBase } from 'app/shared/form-dialog/formfield/model/select-base';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-recurring-deposit-product-accounting-step',
@@ -33,7 +34,8 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId', 'actions'];
constructor(private formBuilder: UntypedFormBuilder,
public dialog: MatDialog) {
public dialog: MatDialog,
private accounting: Accounting) {
this.createrecurringDepositProductAccountingForm();
this.setConditionalControls();
}
@@ -52,10 +54,11 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
}
assignAccountingStepData() {
if (this.recurringDepositProductsTemplate.accountingRule.id === 2) {
this.recurringDepositProductAccountingForm.patchValue({
'accountingRule': this.recurringDepositProductsTemplate.accountingRule.id
});
this.recurringDepositProductAccountingForm.patchValue({
'accountingRule': this.recurringDepositProductsTemplate.accountingRule.id
});
if (this.isCashOrAccrualAccounting()) {
this.recurringDepositProductAccountingForm.patchValue({
'savingsReferenceAccountId': this.recurringDepositProductsTemplate.accountingMappings.savingsReferenceAccount.id,
'savingsControlAccountId': this.recurringDepositProductsTemplate.accountingMappings.savingsControlAccount.id,
@@ -64,6 +67,15 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
'incomeFromPenaltyAccountId': this.recurringDepositProductsTemplate.accountingMappings.incomeFromPenaltyAccount.id,
'interestOnSavingsAccountId': this.recurringDepositProductsTemplate.accountingMappings.interestOnSavingsAccount.id
});
if (this.isAccrualAccounting()) {
this.recurringDepositProductAccountingForm.patchValue({
'feesReceivableAccountId': this.recurringDepositProductsTemplate.accountingMappings.feeReceivableAccount.id,
'penaltiesReceivableAccountId': this.recurringDepositProductsTemplate.accountingMappings.penaltyReceivableAccount.id,
'interestPayableAccountId': this.recurringDepositProductsTemplate.accountingMappings.interestPayableAccount.id
});
}
if (this.recurringDepositProductsTemplate.paymentChannelToFundSourceMappings || this.recurringDepositProductsTemplate.feeToIncomeAccountMappings || this.recurringDepositProductsTemplate.penaltyToIncomeAccountMappings) {
this.recurringDepositProductAccountingForm.patchValue({
'advancedAccountingRules': true
@@ -111,7 +123,7 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
setConditionalControls() {
this.recurringDepositProductAccountingForm.get('accountingRule').valueChanges
.subscribe((accountingRule: any) => {
if (accountingRule === 2) {
if (accountingRule === 2 || accountingRule === 3) {
this.recurringDepositProductAccountingForm.addControl('savingsReferenceAccountId', new UntypedFormControl('', Validators.required));
this.recurringDepositProductAccountingForm.addControl('savingsControlAccountId', new UntypedFormControl('', Validators.required));
this.recurringDepositProductAccountingForm.addControl('transfersInSuspenseAccountId', new UntypedFormControl('', Validators.required));
@@ -120,6 +132,12 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
this.recurringDepositProductAccountingForm.addControl('incomeFromPenaltyAccountId', new UntypedFormControl('', Validators.required));
this.recurringDepositProductAccountingForm.addControl('advancedAccountingRules', new UntypedFormControl(false));
if (accountingRule === 3) {
this.recurringDepositProductAccountingForm.addControl('feesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.recurringDepositProductAccountingForm.addControl('penaltiesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.recurringDepositProductAccountingForm.addControl('interestPayableAccountId', new UntypedFormControl('', Validators.required));
}
this.recurringDepositProductAccountingForm.get('advancedAccountingRules').valueChanges
.subscribe((advancedAccountingRules: boolean) => {
if (advancedAccountingRules) {
@@ -144,6 +162,9 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
this.recurringDepositProductAccountingForm.removeControl('incomeFromInterestId');
this.recurringDepositProductAccountingForm.removeControl('advancedAccountingRules');
this.recurringDepositProductAccountingForm.removeControl('escheatLiabilityId');
this.recurringDepositProductAccountingForm.removeControl('feesReceivableAccountId');
this.recurringDepositProductAccountingForm.removeControl('penaltiesReceivableAccountId');
this.recurringDepositProductAccountingForm.removeControl('interestPayableAccountId');
}
});
}
@@ -269,4 +290,12 @@ export class RecurringDepositProductAccountingStepComponent implements OnInit {
return this.recurringDepositProductAccountingForm.value;
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccountingRuleId(this.recurringDepositProductAccountingForm.value.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccountingRuleId(this.recurringDepositProductAccountingForm.value.accountingRule);
}
}
@@ -320,131 +320,96 @@
<mat-divider fxFlexFill></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ accountingRuleData[recurringDepositProduct.accountingRule-1] }}</span>
</div>
<mifosx-view-savings-accounting-details *ngIf="!isNoneAccounting()"
[accountingRule]="accountingRule"
[accountingMappings]="accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div fxFlexFill *ngIf="recurringDepositProduct.accountingRule === 2" fxLayout="row wrap" fxLayout.lt-md="column">
<div *ngIf="recurringDepositProduct.advancedAccountingRules && (recurringDepositProduct.paymentChannelToFundSourceMappings?.length || recurringDepositProduct.feeToIncomeAccountMappings?.length || recurringDepositProduct.penaltyToIncomeAccountMappings?.length)" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">Assets</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:recurringDepositProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
<div fxFlexFill>
<span fxFlex="40%">Saving reference:</span>
<span fxFlex="60%">{{ recurringDepositProduct.savingsReferenceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
<div *ngIf="recurringDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:recurringDepositProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving control:</span>
<span fxFlex="60%">{{ recurringDepositProduct.savingsControlAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Savings transfers in suspense:</span>
<span fxFlex="60%">{{ recurringDepositProduct.transfersInSuspenseAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Expenses</h4>
<div *ngIf="recurringDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<div fxFlexFill>
<span fxFlex="40%">Interest on savings:</span>
<span fxFlex="60%">{{ recurringDepositProduct.interestOnSavingsAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
</div>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<h4 fxFlexFill class="mat-h4">Income</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.penaltyToIncomeAccountMappings">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Income from fees:</span>
<span fxFlex="60%">{{ recurringDepositProduct.incomeFromFeeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Income from penalties:</span>
<span fxFlex="60%">{{ recurringDepositProduct.incomeFromPenaltyAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:recurringDepositProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<div *ngIf="recurringDepositProduct.advancedAccountingRules && (recurringDepositProduct.paymentChannelToFundSourceMappings?.length || recurringDepositProduct.feeToIncomeAccountMappings?.length || recurringDepositProduct.penaltyToIncomeAccountMappings?.length)" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:recurringDepositProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="recurringDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:recurringDepositProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="recurringDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="recurringDepositProduct.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:recurringDepositProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId | find:recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -1,5 +1,7 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { trigger, state, transition, animate, style } from '@angular/animations';
import { OptionData } from 'app/shared/models/option-data.model';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-recurring-deposit-product-preview-step',
@@ -13,7 +15,7 @@ import { trigger, state, transition, animate, style } from '@angular/animations'
])
]
})
export class RecurringDepositProductPreviewStepComponent implements OnInit {
export class RecurringDepositProductPreviewStepComponent implements OnInit, OnChanges {
@Input() recurringDepositProductsTemplate: any;
@Input() chartSlabsDisplayedColumns: any[];
@@ -29,9 +31,55 @@ export class RecurringDepositProductPreviewStepComponent implements OnInit {
expandChartSlabIndex: number[] = [];
constructor() { }
accountingMappings: any = {};
accountingRule: OptionData;
constructor(private accounting: Accounting) { }
ngOnInit() {
this.setCurrentValues();
}
ngOnChanges(changes: SimpleChanges): void {
this.setCurrentValues();
}
setCurrentValues(): void {
if (this.isCashOrAccrualAccounting()) {
this.accountingRule = this.accounting.getAccountingRuleFrom(this.recurringDepositProduct.accountingRule);
const assetAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
const incomeAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
const expenseAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
const liabilityAccountData = this.recurringDepositProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
this.accountingMappings = {
'savingsReferenceAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.savingsReferenceAccountId, assetAccountData),
'savingsControlAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.savingsControlAccountId, liabilityAccountData),
'transfersInSuspenseAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.transfersInSuspenseAccountId, liabilityAccountData),
'interestOnSavingsAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.interestOnSavingsAccountId, expenseAccountData),
'incomeFromFeeAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.incomeFromFeeAccountId, incomeAccountData),
'incomeFromPenaltyAccount': this.accounting.glAccountLookUp(this.recurringDepositProduct.incomeFromPenaltyAccountId, incomeAccountData)
};
if (this.isAccrualAccounting()) {
this.accountingMappings['feeReceivableAccount'] = this.accounting.glAccountLookUp(this.recurringDepositProduct.feesReceivableAccountId, assetAccountData);
this.accountingMappings['penaltyReceivableAccount'] = this.accounting.glAccountLookUp(this.recurringDepositProduct.penaltiesReceivableAccountId, assetAccountData);
this.accountingMappings['interestPayableAccount'] = this.accounting.glAccountLookUp(this.recurringDepositProduct.interestPayableAccountId, liabilityAccountData);
}
}
}
isNoneAccounting(): boolean {
return this.accounting.isNoneAccountingRuleId(this.recurringDepositProduct.accountingRule);
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccountingRuleId(this.recurringDepositProduct.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccountingRuleId(this.recurringDepositProduct.accountingRule);
}
}
@@ -352,141 +352,102 @@
<mat-divider [inset]="true"></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingRule.value }}</span>
</div>
<mifosx-view-savings-accounting-details class="container"
[accountingRule]="recurringDepositProduct.accountingRule"
[accountingMappings]="recurringDepositProduct.accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div fxFlexFill *ngIf="recurringDepositProduct.accountingRule.id === 2" fxLayout="row wrap" fxLayout.lt-md="column">
<div fxFlexFill *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length || recurringDepositProduct.feeToIncomeAccountMappings?.length || recurringDepositProduct.penaltyToIncomeAccountMappings?.length " fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">Assets</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving reference:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.savingsReferenceAccount.name }}</span>
<mat-divider [inset]="true"></mat-divider>
<div *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Configure Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
</div>
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving control:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.savingsControlAccount.name }}</span>
<span fxFlex="40%">Savings transfers in suspense:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.transfersInSuspenseAccount.name }}</span>
<div *ngIf="recurringDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
<h4 fxFlexFill class="mat-h4">Expenses</h4>
<div *ngIf="recurringDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Interest on savings:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.interestOnSavingsAccount.name }}</span>
<span *ngIf="recurringDepositProduct.accountingMappings.writeOffAccount">
<span fxFlex="40%">Write-off:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.writeOffAccount.name }}</span>
</span>
</div>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<h4 fxFlexFill class="mat-h4">Income</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.penaltyToIncomeAccountMappings">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Income from fees:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.incomeFromFeeAccount.name }}</span>
<span fxFlex="40%">Income from penalties:</span>
<span fxFlex="60%">{{ recurringDepositProduct.accountingMappings.incomeFromPenaltyAccount.name }}</span>
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
<div fxFlexFill *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length || recurringDepositProduct.feeToIncomeAccountMappings?.length || recurringDepositProduct.penaltyToIncomeAccountMappings?.length " fxLayout="row wrap" fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<mat-divider [inset]="true"></mat-divider>
<div *ngIf="recurringDepositProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Configure Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="recurringDepositProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="recurringDepositProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="recurringDepositProduct.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -1,5 +1,9 @@
@import "assets/styles/helper";
.container {
width: 100%;
}
.tab-container {
padding: 1%;
margin: 1%;
@@ -11,27 +15,10 @@
color: $status-approved;
}
table {
width: 100%;
}
.mat-elevation-z1 {
margin: 1em 0 1.5em 0;
}
h2, h3, h4 {
margin: 0;
font-weight: 500;
}
span {
margin: 0.5em 0;
}
.margin-t {
margin-top: 1em;
}
.interestCarts {
float:right;
}
@@ -13,6 +13,7 @@ import { SavingProductAccountingStepComponent } from '../saving-product-stepper/
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-create-saving-product',
@@ -29,7 +30,7 @@ export class CreateSavingProductComponent implements OnInit {
@ViewChild(SavingProductAccountingStepComponent, { static: true }) savingProductAccountingStep: SavingProductAccountingStepComponent;
savingProductsTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -41,10 +42,12 @@ export class CreateSavingProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { savingProductsTemplate: any }) => {
this.savingProductsTemplate = data.savingProductsTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -13,6 +13,7 @@ import { SavingProductAccountingStepComponent } from '../saving-product-stepper/
/** Custom Services */
import { ProductsService } from 'app/products/products.service';
import { SettingsService } from 'app/settings/settings.service';
import { Accounting } from 'app/core/utils/accounting';
@Component({
@@ -30,7 +31,7 @@ export class EditSavingProductComponent implements OnInit {
@ViewChild(SavingProductAccountingStepComponent, { static: true }) savingProductAccountingStep: SavingProductAccountingStepComponent;
savingProductAndTemplate: any;
accountingRuleData = ['None', 'Cash'];
accountingRuleData: string[] = [];
/**
* @param {ActivatedRoute} route Activated Route.
@@ -42,10 +43,12 @@ export class EditSavingProductComponent implements OnInit {
constructor(private route: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
private settingsService: SettingsService) {
private settingsService: SettingsService,
private accounting: Accounting) {
this.route.data.subscribe((data: { savingProductAndTemplate: any }) => {
this.savingProductAndTemplate = data.savingProductAndTemplate;
});
this.accountingRuleData = this.accounting.getAccountingRulesForSavings();
}
ngOnInit() {
@@ -10,7 +10,7 @@
<mat-divider fxFlex="98%"></mat-divider>
<div *ngIf="savingProductAccountingForm.value.accountingRule === 2" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<div *ngIf="isCashOrAccrualAccounting()" fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Assets' | translate}}</h4>
@@ -30,6 +30,22 @@
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="savingProductAccountingForm.controls.feesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Fees Receivable'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="savingProductAccountingForm.controls.penaltiesReceivableAccountId"
[glAccountList]="assetAccountData"
[required]="true"
[inputLabel]="'Penalties Receivable'"
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Liabilities' | translate}}</h4>
@@ -50,6 +66,14 @@
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isAccrualAccounting()"
[inputFormControl]="savingProductAccountingForm.controls.interestPayableAccountId"
[glAccountList]="liabilityAccountData"
[required]="true"
[inputLabel]="'Interest Payable'"
>
</mifosx-gl-account-selector>
<mifosx-gl-account-selector fxFlex="48%" *ngIf="isDormancyTrackingActive.value"
[inputFormControl]="savingProductAccountingForm.controls.escheatLiabilityId"
[glAccountList]="liabilityAccountData"
@@ -58,8 +82,6 @@
>
</mifosx-gl-account-selector>
<mat-divider fxFlex="98%"></mat-divider>
<h4 fxFlex="98%" class="mat-h4">{{'labels.heading.Expenses' | translate}}</h4>
<mifosx-gl-account-selector fxFlex="48%"
@@ -36,7 +36,7 @@ export class SavingProductAccountingStepComponent implements OnInit {
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId', 'actions'];
constructor(private formBuilder: UntypedFormBuilder,
public dialog: MatDialog) {
public dialog: MatDialog) {
this.createsavingProductAccountingForm();
this.setConditionalControls();
}
@@ -71,32 +71,42 @@ export class SavingProductAccountingStepComponent implements OnInit {
'accountingRule': this.savingProductsTemplate.accountingRule.id
});
if (this.savingProductsTemplate.accountingRule.id === 2) {
if (this.isCashOrAccrualAccounting()) {
this.savingProductAccountingForm.patchValue({
'savingsReferenceAccountId': this.savingProductsTemplate.accountingMappings.savingsReferenceAccount.id,
'overdraftPortfolioControlId': this.savingProductsTemplate.accountingMappings.overdraftPortfolioControl.id,
'savingsControlAccountId': this.savingProductsTemplate.accountingMappings.savingsControlAccount.id,
'transfersInSuspenseAccountId': this.savingProductsTemplate.accountingMappings.transfersInSuspenseAccount.id,
'interestOnSavingsAccountId': this.savingProductsTemplate.accountingMappings.interestOnSavingsAccount.id,
'writeOffAccountId': this.savingProductsTemplate.accountingMappings.writeOffAccount.id,
'incomeFromFeeAccountId': this.savingProductsTemplate.accountingMappings.incomeFromFeeAccount.id,
'incomeFromPenaltyAccountId': this.savingProductsTemplate.accountingMappings.incomeFromPenaltyAccount.id,
'incomeFromInterestId': this.savingProductsTemplate.accountingMappings.incomeFromInterest.id,
'advancedAccountingRules': (this.savingProductsTemplate.paymentChannelToFundSourceMappings || this.savingProductsTemplate.feeToIncomeAccountMappings
|| this.savingProductsTemplate.penaltyToIncomeAccountMappings || this.savingProductsTemplate.accrualCharges) ? true : false
});
if (this.isAccrualAccounting()) {
this.savingProductAccountingForm.patchValue({
'savingsReferenceAccountId': this.savingProductsTemplate.accountingMappings.savingsReferenceAccount.id,
'overdraftPortfolioControlId': this.savingProductsTemplate.accountingMappings.overdraftPortfolioControl.id,
'savingsControlAccountId': this.savingProductsTemplate.accountingMappings.savingsControlAccount.id,
'transfersInSuspenseAccountId': this.savingProductsTemplate.accountingMappings.transfersInSuspenseAccount.id,
'interestOnSavingsAccountId': this.savingProductsTemplate.accountingMappings.interestOnSavingsAccount.id,
'writeOffAccountId': this.savingProductsTemplate.accountingMappings.writeOffAccount.id,
'incomeFromFeeAccountId': this.savingProductsTemplate.accountingMappings.incomeFromFeeAccount.id,
'incomeFromPenaltyAccountId': this.savingProductsTemplate.accountingMappings.incomeFromPenaltyAccount.id,
'incomeFromInterestId': this.savingProductsTemplate.accountingMappings.incomeFromInterest.id,
'advancedAccountingRules': (this.savingProductsTemplate.paymentChannelToFundSourceMappings || this.savingProductsTemplate.feeToIncomeAccountMappings || this.savingProductsTemplate.penaltyToIncomeAccountMappings) ? true : false
'feesReceivableAccountId': this.savingProductsTemplate.accountingMappings.feeReceivableAccount.id,
'penaltiesReceivableAccountId': this.savingProductsTemplate.accountingMappings.penaltyReceivableAccount.id,
'interestPayableAccountId': this.savingProductsTemplate.accountingMappings.interestPayableAccount.id
});
}
if (this.isDormancyTrackingActive.value) {
this.savingProductAccountingForm.patchValue({
'escheatLiabilityId': this.savingProductsTemplate.accountingMappings.escheatLiabilityAccount.id,
});
}
this.savingProductAccountingForm.setControl('paymentChannelToFundSourceMappings',
this.formBuilder.array((this.savingProductsTemplate.paymentChannelToFundSourceMappings || []).map((paymentFundSource: any) =>
this.savingProductAccountingForm.setControl('paymentChannelToFundSourceMappings',
this.formBuilder.array((this.savingProductsTemplate.paymentChannelToFundSourceMappings || []).map((paymentFundSource: any) =>
({ paymentTypeId: paymentFundSource.paymentType.id, fundSourceAccountId: paymentFundSource.fundSourceAccount.id }))));
this.savingProductAccountingForm.setControl('feeToIncomeAccountMappings',
this.formBuilder.array((this.savingProductsTemplate.feeToIncomeAccountMappings || []).map((feesIncome: any) =>
this.savingProductAccountingForm.setControl('feeToIncomeAccountMappings',
this.formBuilder.array((this.savingProductsTemplate.feeToIncomeAccountMappings || []).map((feesIncome: any) =>
({ chargeId: feesIncome.charge.id, incomeAccountId: feesIncome.incomeAccount.id }))));
this.savingProductAccountingForm.setControl('penaltyToIncomeAccountMappings',
this.formBuilder.array((this.savingProductsTemplate.penaltyToIncomeAccountMappings || []).map((penaltyIncome: any) =>
this.savingProductAccountingForm.setControl('penaltyToIncomeAccountMappings',
this.formBuilder.array((this.savingProductsTemplate.penaltyToIncomeAccountMappings || []).map((penaltyIncome: any) =>
({ chargeId: penaltyIncome.charge.id, incomeAccountId: penaltyIncome.incomeAccount.id }))));
}
}
@@ -110,7 +120,7 @@ export class SavingProductAccountingStepComponent implements OnInit {
setConditionalControls() {
this.savingProductAccountingForm.get('accountingRule').valueChanges
.subscribe((accountingRule: any) => {
if (accountingRule === 2) {
if (accountingRule === 2 || accountingRule === 3) {
this.savingProductAccountingForm.addControl('savingsReferenceAccountId', new UntypedFormControl('', Validators.required));
this.savingProductAccountingForm.addControl('overdraftPortfolioControlId', new UntypedFormControl('', Validators.required));
this.savingProductAccountingForm.addControl('savingsControlAccountId', new UntypedFormControl('', Validators.required));
@@ -122,6 +132,12 @@ export class SavingProductAccountingStepComponent implements OnInit {
this.savingProductAccountingForm.addControl('incomeFromInterestId', new UntypedFormControl('', Validators.required));
this.savingProductAccountingForm.addControl('advancedAccountingRules', new UntypedFormControl(false));
if (accountingRule === 3) {
this.savingProductAccountingForm.addControl('feesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.savingProductAccountingForm.addControl('penaltiesReceivableAccountId', new UntypedFormControl('', Validators.required));
this.savingProductAccountingForm.addControl('interestPayableAccountId', new UntypedFormControl('', Validators.required));
}
if (this.isDormancyTrackingActive.value) {
this.savingProductAccountingForm.addControl('escheatLiabilityId', new UntypedFormControl('', Validators.required));
}
@@ -159,6 +175,9 @@ export class SavingProductAccountingStepComponent implements OnInit {
this.savingProductAccountingForm.removeControl('incomeFromInterestId');
this.savingProductAccountingForm.removeControl('advancedAccountingRules');
this.savingProductAccountingForm.removeControl('escheatLiabilityId');
this.savingProductAccountingForm.removeControl('feesReceivableAccountId');
this.savingProductAccountingForm.removeControl('penaltiesReceivableAccountId');
this.savingProductAccountingForm.removeControl('interestPayableAccountId');
}
});
}
@@ -293,4 +312,13 @@ export class SavingProductAccountingStepComponent implements OnInit {
return this.savingProductAccountingForm.value;
}
isCashOrAccrualAccounting(): boolean {
return ((this.savingProductAccountingForm.value.accountingRule === 2) ||
(this.savingProductAccountingForm.value.accountingRule === 3));
}
isAccrualAccounting(): boolean {
return (this.savingProductAccountingForm.value.accountingRule === 3);
}
}
@@ -25,7 +25,7 @@ export class SavingProductCurrencyStepComponent implements OnInit {
this.savingProductCurrencyForm.patchValue({
'currencyCode': this.savingProductsTemplate.currency.code || this.currencyData[0].code,
'digitsAfterDecimal': this.savingProductsTemplate.currency.code ? this.savingProductsTemplate.currency.decimalPlaces : 2,
'inMultiplesOf': this.savingProductsTemplate.currency.inMultiplesOf
'inMultiplesOf': this.savingProductsTemplate.currency.inMultiplesOf || 1
});
}
@@ -191,141 +191,96 @@
<mat-divider fxFlexFill></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ accountingRuleData[savingProduct.accountingRule-1] }}</span>
</div>
<mifosx-view-savings-accounting-details
[accountingRule]="accountingRule"
[accountingMappings]="accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div fxFlexFill *ngIf="savingProduct.accountingRule === 2" fxLayout="row wrap" fxLayout.lt-md="column">
<div *ngIf="savingProduct.advancedAccountingRules && (savingProduct.paymentChannelToFundSourceMappings?.length || savingProduct.feeToIncomeAccountMappings?.length || savingProduct.penaltyToIncomeAccountMappings?.length)" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">Assets</h4>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="savingProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:savingProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId | find:savingProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving reference:</span>
<span fxFlex="60%">{{ savingProduct.savingsReferenceAccountId | find:savingProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Overdraft portfolio:</span>
<span fxFlex="60%">{{ savingProduct.overdraftPortfolioControlId | find:savingProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}</span>
</div>
<h4 fxFlexFill class="mat-h4">Liabilities</h4>
<div *ngIf="savingProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:savingProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Saving control:</span>
<span fxFlex="60%">{{ savingProduct.savingsControlAccountId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Savings transfers in suspense:</span>
<span fxFlex="60%">{{ savingProduct.transfersInSuspenseAccountId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
<div fxFlexFill *ngIf="savingProduct.isDormancyTrackingActive">
<span fxFlex="40%">Escheat liability:</span>
<span fxFlex="60%">{{ savingProduct.escheatLiabilityId | find:savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions:'id':'name' }}</span>
</div>
</div>
<h4 fxFlexFill class="mat-h4">Expenses</h4>
<div *ngIf="savingProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Interest on savings:</span>
<span fxFlex="60%">{{ savingProduct.interestOnSavingsAccountId | find:savingProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Write-off:</span>
<span fxFlex="60%">{{ savingProduct.writeOffAccountId | find:savingProductsTemplate.accountingMappingOptions.expenseAccountOptions:'id':'name' }}</span>
</div>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<h4 fxFlexFill class="mat-h4">Income</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.penaltyToIncomeAccountMappings">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Income from fees:</span>
<span fxFlex="60%">{{ savingProduct.incomeFromFeeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Income from penalties:</span>
<span fxFlex="60%">{{ savingProduct.incomeFromPenaltyAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
<span fxFlex="40%">Overdraft Interest Income:</span>
<span fxFlex="60%">{{ savingProduct.incomeFromInterestId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}</span>
</div>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:savingProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<div *ngIf="savingProduct.advancedAccountingRules && (savingProduct.paymentChannelToFundSourceMappings?.length || savingProduct.feeToIncomeAccountMappings?.length || savingProduct.penaltyToIncomeAccountMappings?.length)" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<mat-divider fxFlexFill></mat-divider>
<div *ngIf="savingProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.paymentChannelToFundSourceMappings">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentTypeId | find:savingProductsTemplate.paymentTypeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.fundSourceAccountId | find:savingProductsTemplate.accountingMappingOptions.assetAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="savingProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.feeToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.chargeId | find:savingProductsTemplate.chargeOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.incomeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
<div *ngIf="savingProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.chargeId | find:savingProductsTemplate.penaltyOptions:'id':'name' }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.incomeAccountId | find:savingProductsTemplate.accountingMappingOptions.incomeAccountOptions:'id':'name' }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -1,5 +1,47 @@
@import "assets/styles/helper";
.tab-container {
padding: 1%;
margin: 1%;
}
.mat-h3 {
margin-top: 10px !important;
font-weight: 300;
color: $status-approved;
}
.mat-elevation-z1 {
margin: 1em 0 1.5em 0;
}
.interestCarts {
float:right;
}
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 {
@@ -1,11 +1,13 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
import { Accounting } from 'app/core/utils/accounting';
import { OptionData } from 'app/shared/models/option-data.model';
@Component({
selector: 'mifosx-saving-product-preview-step',
templateUrl: './saving-product-preview-step.component.html',
styleUrls: ['./saving-product-preview-step.component.scss']
})
export class SavingProductPreviewStepComponent implements OnInit {
export class SavingProductPreviewStepComponent implements OnInit, OnChanges {
@Input() savingProductsTemplate: any;
@Input() accountingRuleData: any;
@@ -17,9 +19,56 @@ export class SavingProductPreviewStepComponent implements OnInit {
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId'];
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId'];
constructor() { }
accountingMappings: any = {};
accountingRule: OptionData;
constructor(private accounting: Accounting) { }
ngOnInit() {
this.setCurrentValues();
}
ngOnChanges(changes: SimpleChanges): void {
this.setCurrentValues();
}
setCurrentValues(): void {
if (this.isCashOrAccrualAccounting()) {
this.accountingRule = this.accounting.getAccountingRuleFrom(this.savingProduct.accountingRule);
const assetAccountData = this.savingProductsTemplate.accountingMappingOptions.assetAccountOptions || [];
const incomeAccountData = this.savingProductsTemplate.accountingMappingOptions.incomeAccountOptions || [];
const expenseAccountData = this.savingProductsTemplate.accountingMappingOptions.expenseAccountOptions || [];
const liabilityAccountData = this.savingProductsTemplate.accountingMappingOptions.liabilityAccountOptions || [];
this.accountingMappings = {
'savingsReferenceAccount': this.accounting.glAccountLookUp(this.savingProduct.savingsReferenceAccountId, assetAccountData),
'overdraftPortfolioControl': this.accounting.glAccountLookUp(this.savingProduct.overdraftPortfolioControlId, assetAccountData),
'savingsControlAccount': this.accounting.glAccountLookUp(this.savingProduct.savingsControlAccountId, liabilityAccountData),
'transfersInSuspenseAccount': this.accounting.glAccountLookUp(this.savingProduct.transfersInSuspenseAccountId, liabilityAccountData),
'escheatLiability': this.accounting.glAccountLookUp(this.savingProduct.escheatLiabilityId, liabilityAccountData),
'interestOnSavingsAccount': this.accounting.glAccountLookUp(this.savingProduct.interestOnSavingsAccountId, expenseAccountData),
'writeOffAccount': this.accounting.glAccountLookUp(this.savingProduct.writeOffAccountId, expenseAccountData),
'incomeFromFeeAccount': this.accounting.glAccountLookUp(this.savingProduct.incomeFromFeeAccountId, incomeAccountData),
'incomeFromPenaltyAccount': this.accounting.glAccountLookUp(this.savingProduct.incomeFromPenaltyAccountId, incomeAccountData),
'incomeFromInterest': this.accounting.glAccountLookUp(this.savingProduct.incomeFromInterestId, incomeAccountData)
};
if (this.isAccrualAccounting()) {
this.accountingMappings['feesReceivableAccount'] = this.accounting.glAccountLookUp(this.savingProduct.feesReceivableAccountId, assetAccountData);
this.accountingMappings['penaltiesReceivableAccount'] = this.accounting.glAccountLookUp(this.savingProduct.penaltiesReceivableAccountId, assetAccountData);
this.accountingMappings['interestPayableAccount'] = this.accounting.glAccountLookUp(this.savingProduct.interestPayableAccountId, liabilityAccountData);
}
}
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isAccrualAccountingRuleId(this.savingProduct.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccounting(this.savingProduct.accountingRule);
}
}
@@ -201,145 +201,103 @@
<mat-divider [inset]="true"></mat-divider>
<div fxFlexFill>
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ savingProduct.accountingRule.value }}</span>
</div>
<mifosx-view-savings-accounting-details
[accountingRule]="savingProduct.accountingRule"
[accountingMappings]="savingProduct.accountingMappings"
>
</mifosx-view-savings-accounting-details>
<div
*ngIf="savingProduct.paymentChannelToFundSourceMappings?.length || savingProduct.feeToIncomeAccountMappings?.length || savingProduct.penaltyToIncomeAccountMappings?.length"
fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<div fxFlexFill *ngIf="savingProduct.accountingRule.id === 2" fxLayout="row wrap" fxLayout.lt-md="column">
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Assets' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Saving reference'"
[glAccount]="savingProduct.accountingMappings.savingsReferenceAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Overdraft portfolio'"
[glAccount]="savingProduct.accountingMappings.overdraftPortfolioControl" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mat-divider [inset]="true"></mat-divider>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Income' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from fees'"
[glAccount]="savingProduct.accountingMappings.incomeFromFeeAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from penalties'"
[glAccount]="savingProduct.accountingMappings.incomeFromPenaltyAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from penalties'"
[glAccount]="savingProduct.accountingMappings.incomeFromInterest" [withTitle]="'40%'">
</mifosx-gl-account-display>
<div *ngIf="savingProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Expenses' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Interest on savings'"
[glAccount]="savingProduct.accountingMappings.interestOnSavingsAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Write-off'"
[glAccount]="savingProduct.accountingMappings.writeOffAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Liabilities' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Saving control'"
[glAccount]="savingProduct.accountingMappings.savingsControlAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Savings transfers in suspense'"
[glAccount]="savingProduct.accountingMappings.transfersInSuspenseAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Escheat liability'"
*ngIf="savingProduct.accountingMappings.escheatLiabilityAccount"
[glAccount]="savingProduct.accountingMappings.escheatLiabilityAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="savingProduct.paymentChannelToFundSourceMappings">
<div
*ngIf="savingProduct.paymentChannelToFundSourceMappings?.length || savingProduct.feeToIncomeAccountMappings?.length || savingProduct.penaltyToIncomeAccountMappings?.length"
fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
<h3 class="mat-h3" fxFlexFill>Advanced Accounting Rules</h3>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
({{ paymentFundSource.fundSourceAccount.glCode }}) {{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<mat-divider [inset]="true"></mat-divider>
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
<div *ngIf="savingProduct.paymentChannelToFundSourceMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
</table>
<h4 class="mat-h4" fxFlexFill>Fund Sources for Payment Channels</h4>
</div>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="savingProduct.paymentChannelToFundSourceMappings">
<div *ngIf="savingProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<ng-container matColumnDef="paymentTypeId">
<th mat-header-cell *matHeaderCellDef> Payment Type </th>
<td mat-cell *matCellDef="let paymentFundSource">
{{ paymentFundSource.paymentType.name }}
</td>
</ng-container>
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
<ng-container matColumnDef="fundSourceAccountId">
<th mat-header-cell *matHeaderCellDef> Fund Source </th>
<td mat-cell *matCellDef="let paymentFundSource">
({{ paymentFundSource.fundSourceAccount.glCode }}) {{ paymentFundSource.fundSourceAccount.name }}
</td>
</ng-container>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.feeToIncomeAccountMappings">
<tr mat-header-row *matHeaderRowDef="paymentFundSourceDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: paymentFundSourceDisplayedColumns;"></tr>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
</table>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
({{ feesIncome.incomeAccount.glCode }}) {{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
</div>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<div *ngIf="savingProduct.feeToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
</table>
<h4 class="mat-h4" fxFlexFill>Fees to Specific Income Accounts</h4>
</div>
<table fxFlexFill class="mat-elevation-z1" mat-table [dataSource]="savingProduct.feeToIncomeAccountMappings">
<div *ngIf="savingProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Fees </th>
<td mat-cell *matCellDef="let feesIncome">
{{ feesIncome.charge.name }}
</td>
</ng-container>
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let feesIncome">
({{ feesIncome.incomeAccount.glCode }}) {{ feesIncome.incomeAccount.name }}
</td>
</ng-container>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="savingProduct.penaltyToIncomeAccountMappings">
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
</table>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
({{ penaltyIncome.incomeAccount.glCode }}) {{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
</div>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
<div *ngIf="savingProduct.penaltyToIncomeAccountMappings?.length" fxFlexFill fxLayout="row wrap"
fxLayout.lt-md="column">
<h4 class="mat-h4" fxFlexFill>Penalties to Specific Income Accounts</h4>
<table fxFlexFill class="mat-elevation-z1" mat-table
[dataSource]="savingProduct.penaltyToIncomeAccountMappings">
<ng-container matColumnDef="chargeId">
<th mat-header-cell *matHeaderCellDef> Penalty </th>
<td mat-cell *matCellDef="let penaltyIncome">
{{ penaltyIncome.charge.name }}
</td>
</ng-container>
<ng-container matColumnDef="incomeAccountId">
<th mat-header-cell *matHeaderCellDef> Income Account </th>
<td mat-cell *matCellDef="let penaltyIncome">
({{ penaltyIncome.incomeAccount.glCode }}) {{ penaltyIncome.incomeAccount.name }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="feesPenaltyIncomeDisplayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: feesPenaltyIncomeDisplayedColumns;"></tr>
</table>
</div>
</table>
</div>
@@ -3,10 +3,6 @@
.tab-container {
padding: 1%;
margin: 1%;
div: {
margin-top: 3px;
}
}
.mat-h3 {
@@ -14,3 +10,53 @@
font-weight: 300;
color: $status-approved;
}
.interestCarts {
float:right;
}
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;
}
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Accounting } from 'app/core/utils/accounting';
@Component({
selector: 'mifosx-saving-product-general-tab',
@@ -13,7 +14,8 @@ export class SavingProductGeneralTabComponent implements OnInit {
paymentFundSourceDisplayedColumns: string[] = ['paymentTypeId', 'fundSourceAccountId'];
feesPenaltyIncomeDisplayedColumns: string[] = ['chargeId', 'incomeAccountId'];
constructor(private route: ActivatedRoute) {
constructor(private route: ActivatedRoute,
private accounting: Accounting) {
this.route.data.subscribe((data: { savingProduct: any }) => {
this.savingProduct = data.savingProduct;
});
@@ -21,4 +23,13 @@ export class SavingProductGeneralTabComponent implements OnInit {
ngOnInit() {
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccounting(this.savingProduct.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccounting(this.savingProduct.accountingRule);
}
}
@@ -0,0 +1,59 @@
<div fxLayout="row wrap" fxLayout.lt-md="column">
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column">
<span fxFlex="40%">Type:</span>
<span fxFlex="60%">{{ accountingRule.value }}</span>
</div>
<div fxFlexFill *ngIf="isCashOrAccrualAccounting()" fxLayout="row wrap" fxLayout.lt-md="column">
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Assets' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Saving reference'"
[glAccount]="accountingMappings.savingsReferenceAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Overdraft portfolio'" *ngIf="accountingMappings.overdraftPortfolioControl"
[glAccount]="accountingMappings.overdraftPortfolioControl" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Fees Receivable'" *ngIf="isAccrualAccounting()"
[glAccount]="accountingMappings.feeReceivableAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Penalties Receivable'" *ngIf="isAccrualAccounting()"
[glAccount]="accountingMappings.penaltyReceivableAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Liabilities' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Saving control'"
[glAccount]="accountingMappings.savingsControlAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Savings transfers in suspense'"
[glAccount]="accountingMappings.transfersInSuspenseAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Interest Payable'" *ngIf="isAccrualAccounting()"
[glAccount]="accountingMappings.interestPayableAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Escheat liability'"
*ngIf="accountingMappings.escheatLiabilityAccount" [glAccount]="accountingMappings.escheatLiabilityAccount"
[withTitle]="'40%'">
</mifosx-gl-account-display>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Income' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from fees'"
[glAccount]="accountingMappings.incomeFromFeeAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from penalties'"
[glAccount]="accountingMappings.incomeFromPenaltyAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Income from Interest'" *ngIf="accountingMappings.incomeFromInterest"
[glAccount]="accountingMappings.incomeFromInterest" [withTitle]="'40%'">
</mifosx-gl-account-display>
<h4 fxFlexFill class="mat-h4">{{'labels.heading.Expenses' | translate}}</h4>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Interest on savings'"
[glAccount]="accountingMappings.interestOnSavingsAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
<mifosx-gl-account-display fxFlex="100%" [accountTitle]="'Write-off'" *ngIf="accountingMappings.writeOffAccount"
[glAccount]="accountingMappings.writeOffAccount" [withTitle]="'40%'">
</mifosx-gl-account-display>
</div>
</div>
@@ -0,0 +1,59 @@
@import "assets/styles/colours";
.container {
padding: 1%;
margin: 1%;
width: 100%;
}
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-h4 {
margin-top: 10px !important;
font-weight: 200;
color: $status-approved;
}
.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;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ViewSavingsAccountingDetailsComponent } from './view-savings-accounting-details.component';
describe('ViewSavingsAccountingDetailsComponent', () => {
let component: ViewSavingsAccountingDetailsComponent;
let fixture: ComponentFixture<ViewSavingsAccountingDetailsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ViewSavingsAccountingDetailsComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(ViewSavingsAccountingDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,28 @@
import { Component, Input, OnInit } from '@angular/core';
import { Accounting } from 'app/core/utils/accounting';
import { OptionData } from 'app/shared/models/option-data.model';
@Component({
selector: 'mifosx-view-savings-accounting-details',
templateUrl: './view-savings-accounting-details.component.html',
styleUrls: ['./view-savings-accounting-details.component.scss']
})
export class ViewSavingsAccountingDetailsComponent implements OnInit {
@Input() accountingRule: OptionData;
@Input() accountingMappings: any[] = [];
constructor(private accounting: Accounting) { }
ngOnInit(): void {
}
isCashOrAccrualAccounting(): boolean {
return this.accounting.isCashOrAccrualAccounting(this.accountingRule);
}
isAccrualAccounting(): boolean {
return this.accounting.isAccrualAccounting(this.accountingRule);
}
}
+5 -2
View File
@@ -45,6 +45,7 @@ import { TransactionPaymentDetailComponent } from './transaction-payment-detail/
import { StepperButtonsComponent } from './steppers/stepper-buttons/stepper-buttons.component';
import { GlAccountSelectorComponent } from './accounting/gl-account-selector/gl-account-selector.component';
import { GlAccountDisplayComponent } from './accounting/gl-account-display/gl-account-display.component';
import { ViewSavingsAccountingDetailsComponent } from './accounting/view-savings-accounting-details/view-savings-accounting-details.component';
/**
* Shared Module
@@ -96,7 +97,8 @@ import { GlAccountDisplayComponent } from './accounting/gl-account-display/gl-ac
TransactionPaymentDetailComponent,
StepperButtonsComponent,
GlAccountSelectorComponent,
GlAccountDisplayComponent
GlAccountDisplayComponent,
ViewSavingsAccountingDetailsComponent
],
exports: [
FileUploadComponent,
@@ -126,7 +128,8 @@ import { GlAccountDisplayComponent } from './accounting/gl-account-display/gl-ac
TransactionPaymentDetailComponent,
StepperButtonsComponent,
GlAccountSelectorComponent,
GlAccountDisplayComponent
GlAccountDisplayComponent,
ViewSavingsAccountingDetailsComponent,
]
})
export class SharedModule { }
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Převést klienta",
"Transfer Clients": "Převod klientů",
"Unassign Staff": "Zrušit přidělení personálu",
"Undo": "vrátit",
"Undo Rejection": "Zrušit odmítnutí",
"Undo Transfer": "Vrátit zpět převod",
"Update Default Savings": "Aktualizovat výchozí úspory",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Doby odkladu úroků",
"Interest Method": "Zájmová metoda",
"Interest Outstanding": "Neuvěřitelný zájem",
"Interest Payable": "Zájem päyable",
"Interest Posted": "Zájem zveřejněn",
"Interest Posting Period": "Období účtování úroků",
"Interest Posting period": "Úrokové období zveřejnění",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Client übertragen",
"Transfer Clients": "Kunden übertragen",
"Unassign Staff": "Personalzuweisung aufheben",
"Undo": "Rückgängig machen",
"Undo Rejection": "Ablehnung rückgängig machen",
"Undo Transfer": "Übertragung rückgängig machen",
"Update Default Savings": "Standardeinsparungen aktualisieren",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Zinsschonfristen",
"Interest Method": "Zinsmethode",
"Interest Outstanding": "Ausstehende Zinsen",
"Interest Payable": "Interesse päylierbar",
"Interest Posted": "Interesse gepostet",
"Interest Posting Period": "Zinsbuchungszeitraum",
"Interest Posting period": "Zinsbuchungszeitraum",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Transfer Client",
"Transfer Clients": "Transfer Clients",
"Unassign Staff": "Unassign Staff",
"Undo": "Undo",
"Undo Rejection": "Undo Rejection",
"Undo Transfer": "Undo Transfer",
"Update Default Savings": "Update Default Savings",
@@ -1398,6 +1399,7 @@
"Interest Grace Periods": "Interest Grace Periods",
"Interest Method": "Interest Method",
"Interest Outstanding": "Interest Outstanding",
"Interest Payable": "Interest Payable",
"Interest Posted": "Interest Posted",
"Interest Posting Period": "Interest Posting Period",
"Interest Posting period": "Interest Posting period",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Transferir cliente",
"Transfer Clients": "Transferir Clientes",
"Unassign Staff": "Desasignar personal",
"Undo": "Deshacer",
"Undo Rejection": "Deshacer rechazo",
"Undo Transfer": "Deshacer transferencia",
"Update Default Savings": "Actualizar ahorros predeterminados",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Períodos de gracia de intereses",
"Interest Method": "Método de interés",
"Interest Outstanding": "Interés pendiente",
"Interest Payable": "Intereses a pagar",
"Interest Posted": "Interés publicado",
"Interest Posting Period": "Período de contabilización de intereses",
"Interest Posting period": "Periodo de contabilización de intereses",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Client de transfert",
"Transfer Clients": "Transférer des clients",
"Unassign Staff": "Annuler l'affectation du personnel",
"Undo": "annuler",
"Undo Rejection": "Annuler le rejet",
"Undo Transfer": "Annuler le transfert",
"Update Default Savings": "Mettre à jour les économies par défaut",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Délais de grâce des intérêts",
"Interest Method": "Méthode d'intérêt",
"Interest Outstanding": "Intérêts impayés",
"Interest Payable": "Intérêts payables",
"Interest Posted": "Intérêt affiché",
"Interest Posting Period": "Période de comptabilisation des intérêts",
"Interest Posting period": "Période de comptabilisation des intérêts",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Trasferisci cliente",
"Transfer Clients": "Trasferisci clienti",
"Unassign Staff": "Annulla assegnazione del personale",
"Undo": "Disfare",
"Undo Rejection": "Annulla rifiuto",
"Undo Transfer": "Annulla trasferimento",
"Update Default Savings": "Aggiorna i risparmi predefiniti",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Periodi di grazia degli interessi",
"Interest Method": "Metodo degli interessi",
"Interest Outstanding": "Interessi in sospeso",
"Interest Payable": "Interesse päyable",
"Interest Posted": "Interesse pubblicato",
"Interest Posting Period": "Periodo di registrazione degli interessi",
"Interest Posting period": "Periodo di registrazione degli interessi",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "클라이언트 이전",
"Transfer Clients": "클라이언트 이전",
"Unassign Staff": "직원 할당 해제",
"Undo": "실행 취소",
"Undo Rejection": "거부 취소",
"Undo Transfer": "전송 취소",
"Update Default Savings": "기본 절감액 업데이트",
@@ -1400,6 +1401,7 @@
"Interest Grace Periods": "이자 유예 기간",
"Interest Method": "이자방식",
"Interest Outstanding": "미결제 이자",
"Interest Payable": "관심있는 관심",
"Interest Posted": "게시된 관심",
"Interest Posting Period": "이자 공시 기간",
"Interest Posting period": "이자 공시 기간",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Perkelti klientą",
"Transfer Clients": "Klientų perkėlimas",
"Unassign Staff": "Atšaukti personalo priskyrimą",
"Undo": "Anuliuoti",
"Undo Rejection": "Anuliuoti atmetimą",
"Undo Transfer": "Anuliuoti perkėlimą",
"Update Default Savings": "Atnaujinkite numatytuosius taupymo elementus",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Palūkanų lengvatinis laikotarpis",
"Interest Method": "Palūkanų metodas",
"Interest Outstanding": "Susidomėjimas išskirtinis",
"Interest Payable": "Mokėtinos palūkanos",
"Interest Posted": "Paskelbtas susidomėjimas",
"Interest Posting Period": "Interesų skelbimo laikotarpis",
"Interest Posting period": "Interesų paskelbimo laikotarpis",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Pārsūtīt klientu",
"Transfer Clients": "Pārsūtīt klientus",
"Unassign Staff": "Atcelt personāla piešķiršanu",
"Undo": "Atsaukt",
"Undo Rejection": "Atsaukt noraidījumu",
"Undo Transfer": "Atsaukt pārsūtīšanu",
"Update Default Savings": "Atjauniniet noklusējuma ietaupījumus",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Procentu labvēlības periodi",
"Interest Method": "Interešu metode",
"Interest Outstanding": "Interese Izcila",
"Interest Payable": "Procenti Päyable",
"Interest Posted": "Interese publicēta",
"Interest Posting Period": "Interešu publicēšanas periods",
"Interest Posting period": "Interešu publicēšanas periods",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "ग्राहक स्थानान्तरण",
"Transfer Clients": "ग्राहक हस्तान्तरण",
"Unassign Staff": "कर्मचारी नियुक्ति रद्द गर्नुहोस्",
"Undo": "पूर्वकार्य",
"Undo Rejection": "अस्वीकार अनडू गर्नुहोस्",
"Undo Transfer": "स्थानान्तरण अनडू गर्नुहोस्",
"Update Default Savings": "पूर्वनिर्धारित बचत अद्यावधिक गर्नुहोस्",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "ब्याज अनुग्रह अवधिहरू",
"Interest Method": "ब्याज विधि",
"Interest Outstanding": "बकाया ब्याज",
"Interest Payable": "ब्याज päyy",
"Interest Posted": "चासो पोस्ट गरियो",
"Interest Posting Period": "रुचि पोस्टिङ अवधि",
"Interest Posting period": "ब्याज पोस्टिङ अवधि",
+2
View File
@@ -474,6 +474,7 @@
"Transfer Client": "Cliente de transferência",
"Transfer Clients": "Transferir clientes",
"Unassign Staff": "Cancelar atribuição de equipe",
"Undo": "Desfazer",
"Undo Rejection": "Desfazer rejeição",
"Undo Transfer": "Desfazer transferência",
"Update Default Savings": "Atualizar economia padrão",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Períodos de carência de juros",
"Interest Method": "Método de juros",
"Interest Outstanding": "Juros pendentes",
"Interest Payable": "Juros a pagar",
"Interest Posted": "Interesse Postado",
"Interest Posting Period": "Período de postagem de juros",
"Interest Posting period": "Período de postagem de juros",
+2
View File
@@ -475,6 +475,7 @@
"Transfer Clients": "Wateja wa Uhamisho",
"Unassign Staff": "Batilisha Wafanyikazi",
"Undo Rejection": "Tendua Kukataliwa",
"Undo": "Tengeneza",
"Undo Transfer": "Tendua Uhamisho",
"Update Default Savings": "Sasisha Akiba Chaguomsingi",
"Upload": "Pakia",
@@ -1399,6 +1400,7 @@
"Interest Grace Periods": "Vipindi vya Neema vya Riba",
"Interest Method": "Mbinu ya Maslahi",
"Interest Outstanding": "Maslahi Bora",
"Interest Payable": "Riba inaelezewa",
"Interest Posted": "Nia Imetumwa",
"Interest Posting Period": "Kipindi cha Kuchapisha Riba",
"Interest Posting period": "Kipindi cha Kuchapisha Riba",