You've already forked openaccounting-web
forked from cybercinch/openaccounting-web
got new transaction working
This commit is contained in:
@@ -1,28 +1,10 @@
|
|||||||
<h1>New Transaction</h1>
|
<h1>New Transaction</h1>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
<form [formGroup]="form" (ngSubmit)="onSubmit()" *ngIf="accountTree">
|
||||||
<ngb-accordion #acc="ngbAccordion" activeIds="toggle-1">
|
<ngb-accordion #acc="ngbAccordion" activeIds="toggle-1">
|
||||||
<ngb-panel id="toggle-1" [title]="getToggle1Title()">
|
<ngb-panel id="toggle-1" [title]="getToggle1Title()">
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<!-- <input type="radio" class="btn btn-outline-primary mr-2" id="type-expense" value="Expense">
|
|
||||||
<input type="radio" class="btn btn-outline-primary mr-2" id="type-income" value="Income">
|
|
||||||
<input type="radio" class="btn btn-outline-primary mr-2" id="type-ob" value="Opening Balance">
|
|
||||||
<input type="radio" class="btn btn-outline-primary mr-2" id="type-other" value="Other"> -->
|
|
||||||
<div>
|
|
||||||
<!-- <button type="button" class="btn mr-2" (click)="setType('expense')" [ngClass]="{'btn-outline-primary': type !== 'expense', 'btn-primary': type === 'expense'}">
|
|
||||||
Expense
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn mr-2" (click)="setType('income')" [ngClass]="{'btn-outline-primary': type !== 'income', 'btn-primary': type === 'income'}">
|
|
||||||
Income
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn mr-2" (click)="setType('openingBalance')" [ngClass]="{'btn-outline-primary': type !== 'openingBalance', 'btn-primary': type === 'openingBalance'}">
|
|
||||||
Opening Balance
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn mr-2" (click)="setType('other')" [ngClass]="{'btn-outline-primary': type !== 'other', 'btn-primary': type === 'other'}">
|
|
||||||
Other
|
|
||||||
</button> -->
|
|
||||||
|
|
||||||
<div class="btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="type">
|
<div class="btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="type">
|
||||||
<label ngbButtonLabel class="btn-primary mr-2">
|
<label ngbButtonLabel class="btn-primary mr-2">
|
||||||
<input ngbButton type="radio" value="expense"> Expense
|
<input ngbButton type="radio" value="expense"> Expense
|
||||||
@@ -30,14 +12,13 @@
|
|||||||
<label ngbButtonLabel class="btn-primary mr-2">
|
<label ngbButtonLabel class="btn-primary mr-2">
|
||||||
<input ngbButton type="radio" value="income"> Income
|
<input ngbButton type="radio" value="income"> Income
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary mr-2">
|
<label ngbButtonLabel class="btn-primary mr-2" *ngIf="openingBalances">
|
||||||
<input ngbButton type="radio" value="openingBalance"> Opening Balance
|
<input ngbButton type="radio" value="openingBalance"> Opening Balance
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary mr-2">
|
<label ngbButtonLabel class="btn-primary mr-2">
|
||||||
<input ngbButton type="radio" value="other"> Other
|
<input ngbButton type="radio" value="other"> Other
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="firstAccountPrimary" *ngIf="form.value?.type === 'expense'" class="mt-3">
|
<div id="firstAccountPrimary" *ngIf="form.value?.type === 'expense'" class="mt-3">
|
||||||
<div class="btn-group-toggle" ngbRadioGroup name="radioBasic2" formControlName="firstAccountPrimary">
|
<div class="btn-group-toggle" ngbRadioGroup name="radioBasic2" formControlName="firstAccountPrimary">
|
||||||
<label *ngFor="let account of expenseAccounts" ngbButtonLabel class="btn-primary mr-2">
|
<label *ngFor="let account of expenseAccounts" ngbButtonLabel class="btn-primary mr-2">
|
||||||
@@ -78,9 +59,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="firstAccountPrimary" *ngIf="form.value?.type === 'openingBalance'" class="mt-3">
|
||||||
|
<div id="firstAccountSelect" class="mt-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="firstAccountSecondary" class="col-sm-3 col-form-label">Choose Account</label>
|
||||||
|
<select class="form-control" id="account" formControlName="firstAccountSecondary">
|
||||||
|
<option *ngFor="let account of paymentAccountsAll" [value]="account.id">
|
||||||
|
{{account.label | slice:0:30}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
<ngb-panel id="toggle-2" [title]="getTitle()">
|
<ngb-panel id="toggle-2" [title]="getToggle2Title()" *ngIf="form.value?.type !== 'openingBalance'">
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<div id="secondAccountPrimary" *ngIf="form.value?.type === 'expense'" class="mt-3">
|
<div id="secondAccountPrimary" *ngIf="form.value?.type === 'expense'" class="mt-3">
|
||||||
<div class="btn-group-toggle" ngbRadioGroup name="secondAccountPrimary" formControlName="secondAccountPrimary">
|
<div class="btn-group-toggle" ngbRadioGroup name="secondAccountPrimary" formControlName="secondAccountPrimary">
|
||||||
@@ -122,22 +115,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="secondAccountSelect" *ngIf="form.value?.type === 'openingBalance'" class="mt-3">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="secondAccountSecondary" class="col-sm-3 col-form-label">Choose Account</label>
|
|
||||||
<select class="form-control" id="account" formControlName="secondAccountSecondary">
|
|
||||||
<option *ngFor="let account of paymentAccountsAll" [value]="account.id">
|
|
||||||
{{account.label | slice:0:30}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
<ngb-panel id="toggle-3" title="Amount">
|
<ngb-panel id="toggle-3" title="Amount">
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="number" class="form-control" id="amount" formControlName="amount">
|
<input #amount type="number" class="form-control" id="amount" formControlName="amount">
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
@@ -157,17 +140,47 @@
|
|||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
<ngb-panel id="toggle-6" title="Advanced">
|
<ngb-panel id="toggle-6" title="Advanced">
|
||||||
<ng-template ngbPanelContent>
|
<ng-template ngbPanelContent>
|
||||||
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon
|
<div class="container-fluid" formArrayName="splits">
|
||||||
officia
|
<div class="row">
|
||||||
aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon
|
<div class="col-8">
|
||||||
tempor,
|
<h3>Account</h3>
|
||||||
sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh
|
</div>
|
||||||
helvetica,
|
<div class="col-2">
|
||||||
craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo.
|
<h3>Debit</h3>
|
||||||
Leggings
|
</div>
|
||||||
occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them
|
<div class="col-2">
|
||||||
accusamus
|
<h3>Credit</h3>
|
||||||
labore sustainable VHS.
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" *ngFor="let split of form.get('splits').controls; let i=index" [formGroup]="split">
|
||||||
|
<div class="col-8">
|
||||||
|
<div class="form-group">
|
||||||
|
<select class="form-control" id="account" formControlName="accountId">
|
||||||
|
<option *ngFor="let account of selectAccounts" [value]="account.id">
|
||||||
|
{{account.fullName | slice:0:50}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="number" class="form-control" formControlName="debit" [ngClass]="{'positive': accountMap[split.value.accountId]?.debitBalance, 'negative': !accountMap[split.value.accountId]?.debitBalance}"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="number" class="form-control" formControlName="credit" [ngClass]="{'positive': !accountMap[split.value.accountId]?.debitBalance, 'negative': accountMap[split.value.accountId]?.debitBalance}"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-8">
|
||||||
|
<p>
|
||||||
|
<a (click)="addSplit()">Add Split</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ngb-panel>
|
</ngb-panel>
|
||||||
</ngb-accordion>
|
</ngb-accordion>
|
||||||
|
|||||||
@@ -13,4 +13,7 @@
|
|||||||
color: $blue;
|
color: $blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,22 @@
|
|||||||
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
|
import { Component, ViewEncapsulation, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
FormControl,
|
FormControl,
|
||||||
Validators,
|
Validators,
|
||||||
FormBuilder,
|
FormBuilder,
|
||||||
|
FormArray,
|
||||||
AbstractControl,
|
AbstractControl,
|
||||||
ValidationErrors
|
ValidationErrors
|
||||||
} from '@angular/forms';
|
} from '@angular/forms';
|
||||||
import { AccountService } from '../core/account.service';
|
import { AccountService } from '../core/account.service';
|
||||||
|
import { TransactionService } from '../core/transaction.service';
|
||||||
import { OrgService } from '../core/org.service';
|
import { OrgService } from '../core/org.service';
|
||||||
import { Account, AccountApi, AccountTree } from '../shared/account';
|
import { Account, AccountApi, AccountTree } from '../shared/account';
|
||||||
import { Util } from '../shared/util';
|
import { Util } from '../shared/util';
|
||||||
import { AppError } from '../shared/error';
|
import { AppError } from '../shared/error';
|
||||||
|
import { Transaction, Split } from '../shared/transaction';
|
||||||
|
import { Logger } from '../core/logger';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-txnew',
|
selector: 'app-txnew',
|
||||||
@@ -38,109 +42,240 @@ export class NewTransactionPage {
|
|||||||
public incomeAccountsAll: any[] = [];
|
public incomeAccountsAll: any[] = [];
|
||||||
public paymentAccountsAll: any[] = [];
|
public paymentAccountsAll: any[] = [];
|
||||||
public assetAccountsAll: any[] = [];
|
public assetAccountsAll: any[] = [];
|
||||||
|
public openingBalances: Account;
|
||||||
private accountTree: AccountTree;
|
private accountTree: AccountTree;
|
||||||
|
public accountMap: any;
|
||||||
@ViewChild('acc') acc: any;
|
@ViewChild('acc') acc: any;
|
||||||
|
@ViewChild('amount') amount: ElementRef
|
||||||
|
|
||||||
|
// TODO This code needs to be cleaned up
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private accountService: AccountService,
|
private accountService: AccountService,
|
||||||
|
private txService: TransactionService,
|
||||||
private orgService: OrgService,
|
private orgService: OrgService,
|
||||||
private fb: FormBuilder) {
|
private fb: FormBuilder,
|
||||||
|
private log: Logger) {
|
||||||
|
|
||||||
this.numAccountsShown = 3;
|
this.numAccountsShown = 3;
|
||||||
|
|
||||||
let org = this.orgService.getCurrentOrg();
|
let org = this.orgService.getCurrentOrg();
|
||||||
|
|
||||||
let dateString = Util.getLocalDateString(new Date());
|
let dateString = Util.getLocalDateString(new Date());
|
||||||
this.form = fb.group({
|
this.form = this.fb.group({
|
||||||
'type': ['', Validators.required],
|
type: ['', Validators.required],
|
||||||
'firstAccountPrimary': [null, Validators.required],
|
firstAccountPrimary: [null, Validators.required],
|
||||||
'firstAccountSecondary': [null],
|
firstAccountSecondary: [null],
|
||||||
'secondAccountPrimary': [null, Validators.required],
|
secondAccountPrimary: [null, Validators.required],
|
||||||
'secondAccountSecondary': [null],
|
secondAccountSecondary: [null],
|
||||||
'amount': [null, Validators.required],
|
amount: [null, Validators.required],
|
||||||
'description': [''],
|
description: [''],
|
||||||
'date': [dateString, Validators.required]
|
date: [dateString, Validators.required],
|
||||||
|
splits: fb.array([]),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.accountService.getAccountTree().subscribe(tree => {
|
this.addSplit();
|
||||||
|
this.addSplit();
|
||||||
|
|
||||||
|
this.accountService.getAccountTree().take(1).subscribe(tree => {
|
||||||
this.accountTree = tree;
|
this.accountTree = tree;
|
||||||
|
this.accountMap = tree.accountMap;
|
||||||
this.selectAccounts = tree.getFlattenedAccounts().filter(account => {
|
this.selectAccounts = tree.getFlattenedAccounts().filter(account => {
|
||||||
let isAsset = account.fullName.match(/^Assets/);
|
return !account.children.length;
|
||||||
let isLiability = account.fullName.match(/^Liabilities/);
|
|
||||||
return !account.children.length && (isAsset || isLiability);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.getExpenseAccounts();
|
this.getExpenseAccounts();
|
||||||
this.getIncomeAccounts();
|
this.getIncomeAccounts();
|
||||||
this.getPaymentAccounts();
|
this.getPaymentAccounts();
|
||||||
this.getAssetAccounts();
|
this.getAssetAccounts();
|
||||||
|
|
||||||
|
this.openingBalances = tree.getAccountByName('Opening Balances', 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('type').valueChanges.subscribe(val => {
|
|
||||||
if(val === 'openingBalance') {
|
|
||||||
this.acc.collapse('toggle-1');
|
|
||||||
this.acc.expand('toggle-2');
|
|
||||||
this.form.patchValue({description: 'Opening Balance'});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.form.get('firstAccountPrimary').valueChanges.subscribe(val => {
|
this.form.get('firstAccountPrimary').valueChanges.subscribe(val => {
|
||||||
if(val === 'other') {
|
if (val === 'other') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.acc.collapse('toggle-1');
|
this.acc.collapse('toggle-1');
|
||||||
this.acc.expand('toggle-2');
|
this.acc.expand('toggle-2');
|
||||||
|
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (splits.length > 0) {
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
accountId: val
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('firstAccountSecondary').valueChanges.subscribe(val => {
|
this.form.get('firstAccountSecondary').valueChanges.subscribe(val => {
|
||||||
|
if (this.form.value.type === 'openingBalance') {
|
||||||
|
this.acc.collapse('toggle-1');
|
||||||
|
this.acc.expand('toggle-3');
|
||||||
|
this.acc.expand('toggle-4');
|
||||||
|
this.form.patchValue({
|
||||||
|
description: 'Opening Balance',
|
||||||
|
firstAccountPrimary: 'other',
|
||||||
|
secondAccountPrimary: this.openingBalances.id
|
||||||
|
});
|
||||||
|
this.focusAmount();
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (splits.length > 1) {
|
||||||
|
let firstAccount = this.getFirstAccount();
|
||||||
|
let secondAccount = this.openingBalances;
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
accountId: firstAccount.id
|
||||||
|
});
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
accountId: secondAccount.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.acc.collapse('toggle-1');
|
this.acc.collapse('toggle-1');
|
||||||
this.acc.expand('toggle-2');
|
this.acc.expand('toggle-2');
|
||||||
|
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (splits.length > 0) {
|
||||||
|
let account = this.getFirstAccount();
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
accountId: account.id
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('secondAccountPrimary').valueChanges.subscribe(val => {
|
this.form.get('secondAccountPrimary').valueChanges.subscribe(val => {
|
||||||
if(val === 'other') {
|
if (val === 'other') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.acc.collapse('toggle-2');
|
this.acc.collapse('toggle-2');
|
||||||
this.acc.expand('toggle-3');
|
this.acc.expand('toggle-3');
|
||||||
this.acc.expand('toggle-4');
|
this.acc.expand('toggle-4');
|
||||||
|
this.focusAmount();
|
||||||
|
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (splits.length > 1) {
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
accountId: val
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.form.get('secondAccountSecondary').valueChanges.subscribe(val => {
|
this.form.get('secondAccountSecondary').valueChanges.subscribe(val => {
|
||||||
this.acc.collapse('toggle-2');
|
this.acc.collapse('toggle-2');
|
||||||
this.acc.expand('toggle-3');
|
this.acc.expand('toggle-3');
|
||||||
this.acc.expand('toggle-4');
|
this.acc.expand('toggle-4');
|
||||||
|
this.focusAmount();
|
||||||
|
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (splits.length > 1) {
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
accountId: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.form.get('amount').valueChanges.subscribe(amount => {
|
||||||
|
let type = this.form.get('type').value;
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
if (type === 'expense') {
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
debit: amount
|
||||||
|
});
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
credit: amount
|
||||||
|
});
|
||||||
|
} else if (type === 'income') {
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
credit: amount
|
||||||
|
});
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
debit: amount
|
||||||
|
});
|
||||||
|
} else if (type === 'openingBalance') {
|
||||||
|
let firstAccount = this.getFirstAccount();
|
||||||
|
|
||||||
|
if (firstAccount.debitBalance) {
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
debit: amount
|
||||||
|
});
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
credit: amount
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
splits.at(0).patchValue({
|
||||||
|
credit: amount
|
||||||
|
});
|
||||||
|
splits.at(1).patchValue({
|
||||||
|
debit: amount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
let account = new AccountApi(this.form.value);
|
this.error = null;
|
||||||
account.id = Util.newGuid();
|
|
||||||
let parentAccount = this.accountTree.accountMap[account.parent];
|
|
||||||
|
|
||||||
if(!parentAccount) {
|
let date = new Date();
|
||||||
this.error = new AppError('Invalid parent account');
|
let formDate = Util.getDateFromLocalDateString(this.form.value.date);
|
||||||
return;
|
|
||||||
|
if (formDate.getTime()) {
|
||||||
|
// make the time be at the very end of the day
|
||||||
|
formDate.setHours(23, 59, 59, 999);
|
||||||
}
|
}
|
||||||
|
|
||||||
let org = this.orgService.getCurrentOrg();
|
let sameDay = formDate.getFullYear() === date.getFullYear() &&
|
||||||
account.orgId = org.id;
|
formDate.getMonth() === date.getMonth() &&
|
||||||
account.debitBalance = parentAccount.debitBalance;
|
formDate.getDate() === date.getDate();
|
||||||
account.currency = account.currency || parentAccount.currency;
|
|
||||||
account.precision = account.precision !== null ? account.precision : parentAccount.precision;
|
|
||||||
|
|
||||||
this.accountService.newAccount(account)
|
if (formDate.getTime() && !sameDay) {
|
||||||
.subscribe(
|
date = formDate;
|
||||||
account => {
|
}
|
||||||
this.router.navigate(['/accounts']);
|
|
||||||
},
|
let tx = new Transaction({
|
||||||
err => {
|
id: Util.newGuid(),
|
||||||
this.error = err;
|
description: this.form.value.description,
|
||||||
}
|
date: date,
|
||||||
);
|
splits: []
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < this.form.value.splits.length; i++) {
|
||||||
|
let split = this.form.value.splits[i];
|
||||||
|
let account = this.accountTree.accountMap[split.accountId];
|
||||||
|
|
||||||
|
if (!account) {
|
||||||
|
this.error = new AppError('Invalid account');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let amount = split.debit ? parseFloat(split.debit) : -parseFloat(split.credit);
|
||||||
|
amount = Math.round(amount * Math.pow(10, account.precision));
|
||||||
|
|
||||||
|
tx.splits.push(new Split({
|
||||||
|
accountId: split.accountId,
|
||||||
|
amount: amount,
|
||||||
|
nativeAmount: amount
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log.debug(tx);
|
||||||
|
|
||||||
|
this.txService.newTransaction(tx)
|
||||||
|
.subscribe(tx => {
|
||||||
|
this.router.navigate(['/dashboard']);
|
||||||
|
}, error => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getExpenseAccounts() {
|
getExpenseAccounts() {
|
||||||
@@ -199,7 +334,7 @@ export class NewTransactionPage {
|
|||||||
id: account.id,
|
id: account.id,
|
||||||
name: account.name,
|
name: account.name,
|
||||||
label: this.accountTree.getAccountLabel(account, depth),
|
label: this.accountTree.getAccountLabel(account, depth),
|
||||||
hidden: i < this.numAccountsShown ? false: true
|
hidden: i < this.numAccountsShown ? false : true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -210,19 +345,19 @@ export class NewTransactionPage {
|
|||||||
let aAlpha = a.label.charCodeAt(0) >= 65 && a.label.charCodeAt(0) <= 122;
|
let aAlpha = a.label.charCodeAt(0) >= 65 && a.label.charCodeAt(0) <= 122;
|
||||||
let bAlpha = b.label.charCodeAt(0) >= 65 && b.label.charCodeAt(0) <= 122;
|
let bAlpha = b.label.charCodeAt(0) >= 65 && b.label.charCodeAt(0) <= 122;
|
||||||
|
|
||||||
if(!aAlpha && bAlpha) {
|
if (!aAlpha && bAlpha) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(aAlpha && !bAlpha) {
|
if (aAlpha && !bAlpha) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a.label > b.label) {
|
if (a.label > b.label) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(a.label < b.label) {
|
if (a.label < b.label) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,9 +375,9 @@ export class NewTransactionPage {
|
|||||||
|
|
||||||
let type = this.form.value.type;
|
let type = this.form.value.type;
|
||||||
|
|
||||||
if(type) {
|
if (type) {
|
||||||
str += type.charAt(0).toUpperCase() + type.substr(1);
|
str += type.charAt(0).toUpperCase() + type.substr(1);
|
||||||
if(account) {
|
if (account) {
|
||||||
str += ' (' + account.name + ')';
|
str += ' (' + account.name + ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,12 +385,12 @@ export class NewTransactionPage {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitle() {
|
getToggle2Title() {
|
||||||
let account = this.getSecondAccount();
|
let account = this.getSecondAccount();
|
||||||
|
|
||||||
if(this.form.value.type === 'income') {
|
if (this.form.value.type === 'income') {
|
||||||
return 'Where was the money sent? ' + (account ? account.name : '');
|
return 'Where was the money sent? ' + (account ? account.name : '');
|
||||||
} else if(this.form.value.type === 'openingBalance') {
|
} else if (this.form.value.type === 'openingBalance') {
|
||||||
return 'What account? ' + (account ? account.name : '');
|
return 'What account? ' + (account ? account.name : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,30 +398,119 @@ export class NewTransactionPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFirstAccount() {
|
getFirstAccount() {
|
||||||
if(!this.accountTree) {
|
if (this.form.value.firstAccountPrimary && this.form.value.firstAccountPrimary !== 'other') {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.form.value.firstAccountPrimary && this.form.value.firstAccountPrimary !== 'other') {
|
|
||||||
return this.accountTree.accountMap[this.form.value.firstAccountPrimary];
|
return this.accountTree.accountMap[this.form.value.firstAccountPrimary];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.accountTree.accountMap[this.form.value.firstAccountSecondary];
|
return this.accountTree.accountMap[this.form.value.firstAccountSecondary];
|
||||||
}
|
}
|
||||||
|
|
||||||
getSecondAccount() {
|
getFirstAccountAmount() {
|
||||||
if(!this.accountTree) {
|
let account = this.getFirstAccount();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(this.form.value.secondAccountPrimary && this.form.value.secondAccountPrimary !== 'other') {
|
switch (this.form.value.type) {
|
||||||
|
case 'expense':
|
||||||
|
return this.form.value.amount * Math.pow(10, account.precision);
|
||||||
|
case 'income':
|
||||||
|
return -this.form.value.amount * Math.pow(10, account.precision);
|
||||||
|
case 'openingBalance':
|
||||||
|
return this.form.value.amount * Math.pow(10, account.precision)
|
||||||
|
* (account.debitBalance ? 1 : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSecondAccount() {
|
||||||
|
if (this.form.value.secondAccountPrimary && this.form.value.secondAccountPrimary !== 'other') {
|
||||||
return this.accountTree.accountMap[this.form.value.secondAccountPrimary];
|
return this.accountTree.accountMap[this.form.value.secondAccountPrimary];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.accountTree.accountMap[this.form.value.secondAccountSecondary];
|
return this.accountTree.accountMap[this.form.value.secondAccountSecondary];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSecondAccountAmount() {
|
||||||
|
let firstAccount = this.getFirstAccount();
|
||||||
|
let secondAccount = this.getSecondAccount();
|
||||||
|
|
||||||
|
switch (this.form.value.type) {
|
||||||
|
case 'expense':
|
||||||
|
return -this.form.value.amount * Math.pow(10, secondAccount.precision);
|
||||||
|
case 'income':
|
||||||
|
return this.form.value.amount * Math.pow(10, secondAccount.precision);
|
||||||
|
case 'openingBalance':
|
||||||
|
return this.form.value.amount * Math.pow(10, secondAccount.precision)
|
||||||
|
* (firstAccount.debitBalance ? -1 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addSplit() {
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
|
||||||
|
let control = new FormGroup({
|
||||||
|
accountId: new FormControl(),
|
||||||
|
debit: new FormControl(),
|
||||||
|
credit: new FormControl()
|
||||||
|
}, { updateOn: 'blur' });
|
||||||
|
|
||||||
|
control.valueChanges.subscribe(val => {
|
||||||
|
this.fillEmptySplit();
|
||||||
|
});
|
||||||
|
splits.push(control);
|
||||||
|
|
||||||
|
this.fillEmptySplit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fillEmptySplit() {
|
||||||
|
// Total up splits and fill in any empty split with the leftover value
|
||||||
|
let splits = this.form.get('splits') as FormArray;
|
||||||
|
let amount = 0;
|
||||||
|
let emptySplit: AbstractControl;
|
||||||
|
for (let i = 0; i < splits.length; i++) {
|
||||||
|
let split = splits.at(i);
|
||||||
|
amount += parseFloat(split.get('debit').value) || 0;
|
||||||
|
amount -= parseFloat(split.get('credit').value) || 0;
|
||||||
|
|
||||||
|
if (!split.get('debit').value && !split.get('credit').value) {
|
||||||
|
emptySplit = split;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emptySplit) {
|
||||||
|
let precision = 2;
|
||||||
|
|
||||||
|
let accountId = emptySplit.get('accountId').value;
|
||||||
|
let account = null;
|
||||||
|
|
||||||
|
if (this.accountTree && accountId) {
|
||||||
|
account = this.accountTree.accountMap[emptySplit.get('accountId').value];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (account) {
|
||||||
|
precision = account.precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
amount = this.round(-amount, precision);
|
||||||
|
|
||||||
|
if (amount) {
|
||||||
|
emptySplit.patchValue({
|
||||||
|
debit: amount >= 0 ? amount : '',
|
||||||
|
credit: amount < 0 ? -amount : ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(amount, precision) {
|
||||||
|
return Math.round(amount * Math.pow(10, precision)) / Math.pow(10, precision);
|
||||||
|
}
|
||||||
|
|
||||||
|
focusAmount() {
|
||||||
|
// TODO Not sure how to get rid of this hack
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.amount) {
|
||||||
|
this.amount.nativeElement.focus();
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -87,3 +87,11 @@ a:hover {
|
|||||||
padding: 0 0.5rem;
|
padding: 0 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.positive {
|
||||||
|
color: $positive;
|
||||||
|
}
|
||||||
|
|
||||||
|
.negative {
|
||||||
|
color: $negative;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user