refractor: accounting module (#300)
* Refractor components. * Add resolvers. * Add relative router links. * Replace mat-icons by font-awesome icons. * Add comments. Fixes: #298
This commit is contained in:
+23
-8
@@ -1,3 +1,4 @@
|
||||
<!-- TODO: Responsiveness/design enhancement and reduction in form loading time -->
|
||||
<div class="container">
|
||||
|
||||
<mat-card>
|
||||
@@ -9,11 +10,15 @@
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column">
|
||||
|
||||
<mat-form-field fxFlex="88%">
|
||||
<mat-select placeholder="Office" required formControlName="officeId">
|
||||
<mat-label>Office</mat-label>
|
||||
<mat-select required formControlName="officeId">
|
||||
<mat-option *ngFor="let office of officeData" [value]="office.id">
|
||||
{{ office.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="openingBalancesForm.controls.officeId.hasError('required')">
|
||||
Office is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<button mat-button type="button" color="primary" fxFlex="4%" (click)="retrieveOpeningBalances()">Retrieve</button>
|
||||
@@ -25,17 +30,25 @@
|
||||
<label fxFlex="98%" class="content"><span class="header">Opening Balances Contra Account:</span> {{ openingBalancesData.contraAccount.name + ' (' + openingBalancesData.contraAccount.glCode + ')' }}</label>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<mat-select placeholder="Currency" required formControlName="currencyCode">
|
||||
<mat-label>Currency</mat-label>
|
||||
<mat-select required formControlName="currencyCode">
|
||||
<mat-option *ngFor="let currency of currencyData" [value]="currency.code">
|
||||
{{ currency.displayLabel }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="openingBalancesForm.controls.currencyCode.hasError('required')">
|
||||
Currency is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field fxFlex="48%">
|
||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="openingBalancesDatePicker" placeholder="Opening Balances Date" required formControlName="transactionDate">
|
||||
<mat-label>Opening Balances Date</mat-label>
|
||||
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="openingBalancesDatePicker" required formControlName="transactionDate">
|
||||
<mat-datepicker-toggle matSuffix [for]="openingBalancesDatePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #openingBalancesDatePicker></mat-datepicker>
|
||||
<mat-error *ngIf="openingBalancesForm.controls.transactionDate.hasError('required')">
|
||||
Opening Balances Date is <strong>required</strong>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" class="content" fxFlex="100%">
|
||||
@@ -63,7 +76,7 @@
|
||||
</div>
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayout.lt-md="column" class="content" formArrayName="glAccountEntries"
|
||||
*ngFor="let credit of getFormArrayData('glAccountEntries').controls; let i = index;">
|
||||
*ngFor="let credit of glAccountEntries.controls; let i = index;">
|
||||
|
||||
<div fxFlexFill fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" [formGroupName]="i">
|
||||
|
||||
@@ -81,13 +94,15 @@
|
||||
|
||||
<div fxFlex="23%">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" placeholder="Debit" formControlName="debit">
|
||||
<mat-label>Debit</mat-label>
|
||||
<input matInput type="number" formControlName="debit">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div fxFlex="23%">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" placeholder="Credit" formControlName="credit">
|
||||
<mat-label>Credit</mat-label>
|
||||
<input matInput type="number" formControlName="credit">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@@ -100,8 +115,8 @@
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px" *ngIf="openingBalancesData">
|
||||
<button type="button" mat-raised-button [routerLink]="['/accounting']">Cancel</button>
|
||||
<button mat-raised-button color="primary">Submit</button>
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!openingBalancesForm.valid">Submit</button>
|
||||
</mat-card-actions>
|
||||
|
||||
</form>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
div {
|
||||
margin: 1rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: 500;
|
||||
&.header {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators, FormArray, ValidatorFn, ValidationErrors } from '@angular/forms';
|
||||
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
/** Custom Services */
|
||||
import { AccountingService } from '../accounting.service';
|
||||
|
||||
const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm: FormGroup): ValidationErrors | null => {
|
||||
const debit = glAccountEntriesForm.controls.debit.value;
|
||||
const credit = glAccountEntriesForm.controls.credit.value;
|
||||
return ((debit || credit) && !(debit && credit)) ? null : { 'error': true };
|
||||
};
|
||||
/** Custom Validators */
|
||||
import { onlyOneOfTheFieldsIsRequiredValidator } from './only-one-of-the-fields-is-required.validator';
|
||||
|
||||
/**
|
||||
* Migrate opening balances component.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-migrate-opening-balances',
|
||||
templateUrl: './migrate-opening-balances.component.html',
|
||||
@@ -16,37 +19,53 @@ const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm
|
||||
})
|
||||
export class MigrateOpeningBalancesComponent implements OnInit {
|
||||
|
||||
/** Minimum opening balances date allowed. */
|
||||
minDate = new Date(2000, 0, 1);
|
||||
/** Maximum opening balances date allowed. */
|
||||
maxDate = new Date();
|
||||
/** Opening balances form. */
|
||||
openingBalancesForm: FormGroup;
|
||||
/** Opening balances data. */
|
||||
openingBalancesData: any;
|
||||
/** Office data. */
|
||||
officeData: any;
|
||||
/** Currency data. */
|
||||
currencyData: any;
|
||||
|
||||
/** Sum total of debits. */
|
||||
debitsSum = 0;
|
||||
/** Sum total of credits. */
|
||||
creditsSum = 0;
|
||||
|
||||
constructor(private accountingService: AccountingService,
|
||||
private formBuilder: FormBuilder) { }
|
||||
/**
|
||||
* Retrieves the offices and currencies from `resolve`.
|
||||
* @param {FormBuilder} formBuilder Form Builder.
|
||||
* @param {AccountingService} accountingService Accounting Service.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Router} router Router for navigation.
|
||||
*/
|
||||
constructor(private formBuilder: FormBuilder,
|
||||
private accountingService: AccountingService,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router) {
|
||||
this.route.data.subscribe((data: {
|
||||
offices: any,
|
||||
currencies: any
|
||||
}) => {
|
||||
this.officeData = data.offices;
|
||||
this.currencyData = data.currencies.selectedCurrencyOptions;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the opening balances form. (initially retrieves gl accounts on the basis of specified office)
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.createOpeningBalancesForm();
|
||||
this.getOffices();
|
||||
this.getCurrencies();
|
||||
}
|
||||
|
||||
getOffices() {
|
||||
this.accountingService.getOffices().subscribe(officeData => {
|
||||
this.officeData = officeData;
|
||||
});
|
||||
}
|
||||
|
||||
getCurrencies() {
|
||||
this.accountingService.getCurrencies().subscribe(currencyData => {
|
||||
this.currencyData = currencyData.selectedCurrencyOptions;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the opening balances form.
|
||||
*/
|
||||
createOpeningBalancesForm() {
|
||||
this.openingBalancesForm = this.formBuilder.group({
|
||||
'officeId': ['', Validators.required],
|
||||
@@ -56,6 +75,11 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the gl account entry form.
|
||||
* @param glAccount GL Account for which form is returned.
|
||||
* @returns {FormGroup} GL Account entry form.
|
||||
*/
|
||||
createGLAccountEntryForm(glAccount: any): FormGroup {
|
||||
return this.formBuilder.group({
|
||||
'glAccountId': [glAccount.glAccountId],
|
||||
@@ -64,19 +88,32 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
||||
}, { validator: onlyOneOfTheFieldsIsRequiredValidator });
|
||||
}
|
||||
|
||||
getFormArrayData(type: string): FormArray {
|
||||
return <FormArray>this.openingBalancesForm.get(type);
|
||||
/**
|
||||
* Gets the gl account entries form array.
|
||||
* @returns {FormArray} GL Account entries form array.
|
||||
*/
|
||||
get glAccountEntries(): FormArray {
|
||||
return this.openingBalancesForm.get('glAccountEntries') as FormArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves gl accounts on the basis of specified office.
|
||||
*/
|
||||
retrieveOpeningBalances() {
|
||||
this.accountingService.retrieveOpeningBalances(this.openingBalancesForm.value.officeId)
|
||||
.subscribe((openingBalancesData: any) => {
|
||||
const entry = this.openingBalancesForm.get('glAccountEntries') as FormArray;
|
||||
|
||||
openingBalancesData.glAccounts = openingBalancesData.assetAccountOpeningBalances
|
||||
.concat(openingBalancesData.liabityAccountOpeningBalances, openingBalancesData.equityAccountOpeningBalances, openingBalancesData.incomeAccountOpeningBalances, openingBalancesData.expenseAccountOpeningBalances);
|
||||
.concat(openingBalancesData.liabityAccountOpeningBalances,
|
||||
openingBalancesData.equityAccountOpeningBalances,
|
||||
openingBalancesData.incomeAccountOpeningBalances,
|
||||
openingBalancesData.expenseAccountOpeningBalances);
|
||||
|
||||
openingBalancesData.glAccounts.forEach((glAccount: any) => {
|
||||
entry.push(this.createGLAccountEntryForm(glAccount));
|
||||
});
|
||||
|
||||
this.openingBalancesData = openingBalancesData;
|
||||
|
||||
entry.valueChanges.subscribe(() => {
|
||||
@@ -90,32 +127,41 @@ export class MigrateOpeningBalancesComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the opening balances form and defines opening balances,
|
||||
* if successful redirects to view created transaction.
|
||||
*/
|
||||
submit() {
|
||||
// TODO: Validate
|
||||
if (this.openingBalancesForm.status !== 'INVALID') {
|
||||
const openingBalances = this.openingBalancesForm.value;
|
||||
// TODO: Update once language and date settings are setup
|
||||
openingBalances.locale = 'en';
|
||||
openingBalances.dateFormat = 'dd MMMM yyyy';
|
||||
openingBalances.transactionDate = '07 August 2018';
|
||||
openingBalances.debits = [];
|
||||
openingBalances.credits = [];
|
||||
this.openingBalancesForm.value.glAccountEntries.forEach((entry: any) => {
|
||||
if (entry.debit) {
|
||||
openingBalances.debits.push({ glAccountId: entry.glAccountId, amount: entry.debit });
|
||||
}
|
||||
if (entry.credit) {
|
||||
openingBalances.credits.push({ glAccountId: entry.glAccountId, amount: entry.credit });
|
||||
}
|
||||
});
|
||||
delete openingBalances.glAccountEntries;
|
||||
this.accountingService.defineOpeningBalances(openingBalances)
|
||||
.subscribe((response: any) => {
|
||||
console.log(response);
|
||||
});
|
||||
} else {
|
||||
console.log('Errors exist in form!');
|
||||
const openingBalances = this.openingBalancesForm.value;
|
||||
// TODO: Update once language and date settings are setup
|
||||
openingBalances.locale = 'en';
|
||||
openingBalances.dateFormat = 'yyyy-MM-dd';
|
||||
if (openingBalances.transactionDate instanceof Date) {
|
||||
let day = openingBalances.transactionDate.getDate();
|
||||
let month = openingBalances.transactionDate.getMonth() + 1;
|
||||
const year = openingBalances.transactionDate.getFullYear();
|
||||
if (day < 10) {
|
||||
day = `0${day}`;
|
||||
}
|
||||
if (month < 10) {
|
||||
month = `0${month}`;
|
||||
}
|
||||
openingBalances.transactionDate = `${year}-${month}-${day}`;
|
||||
}
|
||||
openingBalances.debits = [];
|
||||
openingBalances.credits = [];
|
||||
this.openingBalancesForm.value.glAccountEntries.forEach((entry: any) => {
|
||||
if (entry.debit) {
|
||||
openingBalances.debits.push({ glAccountId: entry.glAccountId, amount: entry.debit });
|
||||
}
|
||||
if (entry.credit) {
|
||||
openingBalances.credits.push({ glAccountId: entry.glAccountId, amount: entry.credit });
|
||||
}
|
||||
});
|
||||
delete openingBalances.glAccountEntries;
|
||||
this.accountingService.defineOpeningBalances(openingBalances).subscribe((response: any) => {
|
||||
this.router.navigate(['/accounting/journal-entries/transactions/view', response.transactionId]);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/** Angular Imports */
|
||||
import { FormGroup, ValidatorFn, ValidationErrors } from '@angular/forms';
|
||||
|
||||
/** Validates that atleast one of the fields debit or credit is filled (but not both) for a given gl account. */
|
||||
export const onlyOneOfTheFieldsIsRequiredValidator: ValidatorFn = (glAccountEntriesForm: FormGroup): ValidationErrors | null => {
|
||||
const debit = glAccountEntriesForm.controls.debit.value;
|
||||
const credit = glAccountEntriesForm.controls.credit.value;
|
||||
return ((debit || credit) && !(debit && credit)) ? null : { 'error': true };
|
||||
};
|
||||
Reference in New Issue
Block a user