Commit 763fddca authored by palidanx's avatar palidanx
Browse files

adding search, copy paste, date filters, csv export

parent 74dccf63
Pipeline #113144173 failed with stages
in 5 minutes and 4 seconds
{
"name": "financier",
"private": true,
"version": "1.7.3",
"releaseDate": "2019-10-23",
"version": "1.7.2",
"releaseDate": "2018-04-05",
"description": "Straightforward budgeting",
"main": "index.js",
"scripts": {
......@@ -81,6 +81,7 @@
"dependencies": {
"angular": "^1.5.9",
"angular-animate": "^1.5.9",
"angular-clipboard": "^1.7.0",
"angular-dateParser": "^1.1.0",
"angular-dynamic-locale": "^0.1.32",
"angular-hotkeys": "^1.7.0",
......
......@@ -3,7 +3,7 @@
<msapplication>
<tile>
<square150x150logo src="/assets/icons/mstile-150x150.png"/>
<TileColor>#76b852</TileColor>
<TileColor>#68c4af</TileColor>
</tile>
</msapplication>
</browserconfig>
......@@ -12,7 +12,7 @@
"type": "image\/png"
}
],
"theme_color": "#76b852",
"theme_color": "#68c4af",
"start_url": "http:\/\/app.financier.io",
"display": "standalone"
}
......@@ -16,7 +16,7 @@
"REPORTS": "Reports",
"ACCOUNTS": "Accounts",
"ALL_ACCOUNTS": "All Accounts",
"ADD_A_NEW_TRANSACTION": "Add a new transaction",
"ADD_A_NEW_TRANSACTION": "Add tx",
"CLEARED_BALANCE": "Cleared balance",
"UNCLEARED_BALANCE": "Uncleared balance",
"WORKING_BALANCE": "Working balance",
......@@ -47,7 +47,7 @@
"YOU_NEED_TO_CLEAR_SPENDING": "You need to clear {{amount}} of spending to reconcile this account.",
"YOU_NEED_TO_CLEAR_INCOME": "You need to clear {{amount}} of income to reconcile this account.",
"RECONCILE_CLEARED_BALANCE_MATCHES": "Your cleared balance matches your actual account balance.",
"MAKE_A_TRANSFER": "Make a transfer",
"MAKE_A_TRANSFER": "Transfer",
"BULK_EDIT_TRANSACTIONS_AMOUNT": "Edit ({{number}})",
"ON_BUDGET": "On Budget",
"OFF_BUDGET": "Off Budget",
......
......@@ -11,10 +11,10 @@
<link rel="icon" type="image/png" href="/assets/icons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/assets/icons/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/assets/icons/manifest.json">
<link rel="mask-icon" href="/assets/icons/safari-pinned-tab.svg" color="#76b852">
<link rel="mask-icon" href="/assets/icons/safari-pinned-tab.svg" color="#68c4af">
<link rel="shortcut icon" href="/assets/icons/favicon.ico">
<meta name="msapplication-config" content="/assets/icons/browserconfig.xml">
<meta name="theme-color" content="#76b852">
<meta name="theme-color" content="#68c4af">
<link type="text/plain" rel="author" href="humans.txt">
......@@ -40,8 +40,8 @@ html {
right: 0;
bottom: 0;
left: 0;
background: -webkit-linear-gradient(#87d25d, #5b903f);
background: linear-gradient(#87d25d, #5b903f);
background: -webkit-linear-gradient(#68c4af, #5b903f);
background: linear-gradient(#68c4af, #5b903f);
display: flex;
align-items: center;
justify-content: center;
......
......@@ -15,6 +15,7 @@ import 'angular-hotkeys-light';
import 'angular-hotkeys';
import 'angular-legacy-sortablejs-maintained';
import 'angular-ladda-lw/dist/angular-ladda-lw';
import 'angular-clipboard/angular-clipboard.js';
import moment from 'moment';
......@@ -34,7 +35,8 @@ let financier = angular.module('financier', [
'angularResizable',
'fps.hotkeys',
'ng-sortable',
'angular-ladda-lw'
'angular-ladda-lw',
'angular-clipboard'
]).run((offline, $rootScope, $timeout, $filter, $state) => {
const dateFilter = $filter('date');
......
import moment from 'moment';
angular.module('financier').controller('accountCtrl', function ($translate, $timeout, $document, $element, $scope, $rootScope, $stateParams, data, transaction, payee, myBudget, budgetRecord, Hotkeys) {
var fapp = angular.module('financier').controller('accountCtrl', function ($translate, $timeout, $document, $element, $scope, $rootScope, $stateParams, data, transaction, payee, myBudget, budgetRecord, Hotkeys, $filter, clipboard) {
const that = this;
const Transaction = transaction($stateParams.budgetId);
const Payee = payee($stateParams.budgetId);
$rootScope.dbCtrl = $scope.dbCtrl;
$rootScope.actCtrl = this;
const { manager } = data;
$rootScope.sumBalance = 0;
$rootScope.selectedBalance = 0;
var sum = $rootScope.selectedBalance;
this.accountId = $stateParams.accountId;
//addition
$rootScope.all = [];
if ($stateParams.accountId) {
this.account = manager.getAccount($stateParams.accountId);
......@@ -204,15 +211,33 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
}
};
this.selectAll = () => {
this.selectAll = () => {
console.log( "selectAll");
$scope.displayedTransactions = $filter('searchFromTransactions')($scope.displayedTransactions, $scope.search);
$scope.displayedTransactions = $filter('searchByDateStartEnd')($scope.displayedTransactions, $scope.dateStart, $scope.dateEnd);
this.selectedTransactions = $scope.displayedTransactions;
//selected Balance logic
sum = 0;
angular.forEach(this.selectedTransactions, function (item) {
var outFlowIntCurrency = $filter('intCurrency')(item.outflow, true, 2);
var inFlowIntCurrency = $filter('intCurrency')(item.inflow, true, 2);
(outFlowIntCurrency != undefined ? sum += parseFloat(outFlowIntCurrency) : 0);
(inFlowIntCurrency != undefined ? sum += parseFloat(inFlowIntCurrency) : 0);
});
$rootScope.selectedBalance = $filter('currency')(sum, '$', 2);
};
this.isAllSelected = val => {
$scope.tempdata = [];
this.isAllSelected = val => {
if (angular.isDefined(val)) {
if (val) {
if (val) {
this.selectAll();
} else {
$rootScope.selectedBalance = $filter('currency')("0.00", '$', 2);
this.selectedTransactions = [];
}
}
......@@ -220,7 +245,7 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
return this.selectedTransactions.length === ($scope.displayedTransactions || []).length;
};
const documentClickHandler = () => {
const documentClickHandler = () => {
that.selectedTransactions = [];
that.selectedTransactionIndexes = [];
this.editingTransaction = null;
......@@ -260,6 +285,31 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
Hotkeys.deregisterHotkey(hotkeys);
});
this.copyToClipboard = (input) => {
var text = "";
angular.forEach(input, function (item) {
var i = '';
if (item.transfer && item.transfer.account) {
i = item.transfer.account;
}
var account = $rootScope.actCtrl.manager.getAccount(item.account).name || 'No account';
var date = $filter('date')(item._data.date ? item._data.date : "", "shortDate");
var payee = $rootScope.dbCtrl.getAccountName(i) || $rootScope.dbCtrl.getPayeeName(item.payee);
var category = $rootScope.dbCtrl.getCategoryName(item.category, item.date) || ($rootScope.actCtrl.transactionNeedsCategory(item) ? 'No Category' : '');
var memo = item._data.memo ? item._data.memo : "";
var inflow = $filter('intCurrency')(item.inflow ? item.inflow : "", true, 2);
var infl = $filter('currency')(inflow, '$', 2);
var outflow = $filter('intCurrency')(item.outflow ? item.outflow : "", true, 2);
var out = $filter('currency')(outflow, '$', 2);
text += account + "\t"+ date+ "\t"+ payee+ "\t"+ category+ "\t"+ memo+ "\t"+ out+ "\t"+ infl +"\n";
});
clipboard.copyText(text);
$rootScope.selectedBalance = 0;
}
this.stopEditing = () => {
if (this.newTransaction) {
this.newTransaction = null;
......@@ -271,7 +321,14 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
}
};
this.selectRow = function (event, rowIndex) {
this.selectRow = function (event, rowIndex) {
console.log( "selectRow");
$scope.displayedTransactions = $filter('searchFromTransactions')($scope.displayedTransactions, $scope.search);
$scope.displayedTransactions = $filter('searchByDateStartEnd')($scope.displayedTransactions, $scope.dateStart, $scope.dateEnd);
$scope.dbCtrl.stopPropagation(event);
this.editingTransaction = null;
......@@ -318,6 +375,16 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
that.selectedTransactions = that.selectedTransactionIndexes.map(i => $scope.displayedTransactions[i]);
//selected Balance logic
sum = 0;
angular.forEach(this.selectedTransactions, function (item) {
var outFlowIntCurrency = $filter('intCurrency')(item.outflow, true, 2);
var inFlowIntCurrency = $filter('intCurrency')(item.inflow, true, 2);
(outFlowIntCurrency != undefined ? sum += parseFloat(outFlowIntCurrency) : 0);
(inFlowIntCurrency != undefined ? sum += parseFloat(inFlowIntCurrency) : 0);
});
$rootScope.selectedBalance = $filter('currency')(sum, '$', 2);
$rootScope.$broadcast('vsRepeatTrigger');
};
......@@ -349,20 +416,30 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
var selectFromIndex = Math.min(rowIndex, lastSelectedRowIndex);
var selectToIndex = Math.max(rowIndex, lastSelectedRowIndex);
selectRows(selectFromIndex, selectToIndex);
}
function selectRows(selectFromIndex, selectToIndex) {
for (var rowToSelect = selectFromIndex; rowToSelect <= selectToIndex; rowToSelect++) {
select(rowToSelect);
}
}
}
function changeSelectionStatus(rowIndex) {
function changeSelectionStatus(rowIndex) {
var outFlowIntCurrency = $filter('intCurrency')($scope.displayedTransactions[rowIndex].outflow, true, 2);
var inFlowIntCurrency = $filter('intCurrency')($scope.displayedTransactions[rowIndex].inflow, true, 2);
if (isRowSelected(rowIndex)) {
(outFlowIntCurrency != undefined ? sum -= parseFloat(outFlowIntCurrency) : 0);
(inFlowIntCurrency != undefined ? sum -= parseFloat(inFlowIntCurrency) : 0);
unselect(rowIndex);
} else {
} else {
(outFlowIntCurrency != undefined ? sum += parseFloat(outFlowIntCurrency) : 0);
(inFlowIntCurrency != undefined ? sum += parseFloat(inFlowIntCurrency) : 0);
select(rowIndex);
}
}
$rootScope.selectedBalance = $filter('currency')(sum, '$', 2);
}
function select(rowIndex) {
......@@ -377,6 +454,11 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
that.selectedTransactionIndexes.splice(rowIndexInSelectedRowsList, unselectOnlyOneRow);
}
function isValidDate(dateString) {
var regEx = /^\d{4}-\d{2}-\d{2}$/;
return dateString.match(regEx) != null;
}
this.toggle = (index, event) => {
$scope.dbCtrl.stopPropagation(event);
......@@ -420,3 +502,121 @@ angular.module('financier').controller('accountCtrl', function ($translate, $tim
Hotkeys.deregisterHotkey(clearedHotkeys);
});
});
//this searches transactions
angular.module('financier').filter('searchFromTransactions', function($rootScope, $filter) {
//input is the entire set of rows
//search is the phrase
return function (input, search) {
if( typeof search == 'undefined' ) {
console.log( "no search input");
return input;
}
console.log( "search transactions: " + search );
var output = [];
var sumBalance = 0;
//if you search once, this path gets taken
if (!search) {
console.log( "no search field");
return input;
/*
output = input;
if ($rootScope.all.length == 0) {
$rootScope.all = input;
}
else {
console.log( "input length: " + input.length );
output = $rootScope.all;
}*/
} else {
//input = $rootScope.all;
angular.forEach(input, function (item) {
var i = '';
if (item.transfer && item.transfer.account) {
i = item.transfer.account;
}
//payee
var payee = $rootScope.dbCtrl.getAccountName(i) || $rootScope.dbCtrl.getPayeeName(item.payee);
var category = $rootScope.dbCtrl.getCategoryName(item.category, item.date) || $rootScope.actCtrl.transactionNeedsCategory(item);
var memo = item._data.memo ? item._data.memo : "";
var searchField = (payee ? payee : " " ) + (category ? category : " ") + (memo ? memo : " ");
if( searchField.toLowerCase().indexOf( search.toLowerCase() ) != -1 ) {
output.push(item);
}
});
}
//sumBalance Logic
for (var i in output) {
if (output[i].inflow) {
sumBalance -= parseInt((output[i].inflow || 0));
sumBalance += parseInt((output[i].outflow ||0));
}
}
sumBalance = Math.abs(sumBalance);
var intCurrency = $filter('intCurrency')(sumBalance, true, 2);
var currency = $filter('currency')(intCurrency, '$', 2);
$rootScope.sumBalance = currency;
console.log( "returning output length: " + output.length);
return output;
}
})
//searches by start and end date
angular.module('financier').filter('searchByDateStartEnd', function($rootScope, $filter) {
console.log( "search by date start end");
return function (input, dateStart, dateEnd) {
if( typeof dateStart == 'undefined' ) {
return input;
}
if( typeof dateEnd == 'undefined' ) {
return input;
}
console.log( "datestart: " + dateStart);
console.log( "dateEnd: " + dateEnd);
var output = [];
var sumBalance = 0;
var dateStart = $filter('date')(dateStart, "yyyy-MM-dd");
var dateEnd = $filter('date')(dateEnd, "yyyy-MM-dd");
if (!dateEnd || !dateStart) {
console.log( "date ranges are not valid");
output = input;
} else {
angular.forEach(input, function (item) {
var i = '';
if (item._data.date >= dateStart && item._data.date <= dateEnd) {
output.push(item);
}
});
}
//sumBalance Logic
for (var i in output) {
if (output[i].inflow) {
sumBalance -= parseInt((output[i].inflow || 0));
sumBalance += parseInt((output[i].outflow ||0));
}
}
sumBalance = Math.abs(sumBalance);
var intCurrency = $filter('intCurrency')(sumBalance, true, 2);
var currency = $filter('currency')(intCurrency, '$', 2);
$rootScope.sumBalance = currency;
return output;
}
})
\ No newline at end of file
......@@ -4,7 +4,7 @@ angular.module('financier').controller('dbCtrl', function (exportCsv, monthManag
const that = this;
const dateFilter = $filter('date');
console.log("data",data)
let {manager, categories, masterCategories, payees} = data;
const budgetId = $stateParams.budgetId;
......@@ -38,6 +38,27 @@ angular.module('financier').controller('dbCtrl', function (exportCsv, monthManag
});
};
this.accountFilteredExport = output => {
var tmpoutput = {};
for (var i in output) {
if (!tmpoutput[output[i].id]) {
tmpoutput[output[i].id] = output[i];
}
}
this.manager.transactions = tmpoutput;
exportCsv.create({
transactions:Object.keys(this.manager.transactions).map(id => this.manager.transactions[id]),
accounts: this.accounts,
masterCategories: this.masterCategories,
categories: this.categories,
payees: this.payees,
currencySymbol: this.currencySymbol,
currencyDigits: this.currencyDigits,
months: this.manager.months,
budgetName: this.budgetRecord.name
});
};
this.getTransactionHeight = trans => {
const unitHeight = 30; // one "row" of transaction table
let rows;
......
// http://www.color-hex.com/color-palette/1147
$primary: #76b852;
$primary: #68c4af;
$primary-hover: #96ead7;
$light-primary: #87d25d;
......
......@@ -34,6 +34,18 @@
<div class="account__balance-value" ng-class="{'account__balance-value--negative': accountCtrl.account.cache.balance < 0}">{{accountCtrl.account.cache.balance | intCurrency : true : dbCtrl.currencyDigits | currency : dbCtrl.currencySymbol : dbCtrl.currencyDigits}}</div>
</div>
</div>
<div class="account__balance">
<div>
<div class="account__balance-title">Sum Balance</div>
<div class="account__balance-value" ng-class="account__balance-value">{{sumBalance}}</div>
</div>
</div>
<div class="account__balance">
<div>
<div class="account__balance-title">Selected Balance</div>
<div class="account__balance-value" ng-class="account__balance-value">{{selectedBalance}}</div>
</div>
</div>
</div>
</div>
<div class="account__reconcile" ng-if="accountCtrl.accountId">
......@@ -69,8 +81,36 @@
<div class="account__tr">
<button class="account__add-button" ng-click="dbCtrl.stopPropagation($event); accountCtrl.createTransaction()"><i class="fa fa-plus"></i> {{'ADD_A_NEW_TRANSACTION' | translate}}</button>
<button class="account__add-button" ng-click="dbCtrl.stopPropagation($event); accountCtrl.createTransaction()"><i class="fa fa-exchange"></i> {{'MAKE_A_TRANSFER' | translate}}</button>
<!-- add -->
Filter Field <input type="text"
id="name"
name="search"
ng-model="search"
size="20">
Date Start
<input type="text"
name="dateStart"
size = "10"
ng-model="dateStart"/>
Date End
<input type="text"
name="dateEnd"
size= "10"
ng-model="dateEnd"/>
CSV
<button class="account__add-button">
<i class="fa fa-cog app-view__budget-options"
budget-options
on-export="dbCtrl.accountFilteredExport(displayedTransactions | searchFromTransactions:search | searchByDateStartEnd :dateStart:dateEnd)"
on-backup="dbCtrl.backup()"></i></button>
<button class="account__add-button" ng-if="accountCtrl.selectedTransactions.length" bulk-edit-transactions="accountCtrl.selectedTransactions" manager="dbCtrl.manager" stop-propagation="dbCtrl.stopPropagation" payees="dbCtrl.payees"><i class="fa fa-edit"></i> <span translate="BULK_EDIT_TRANSACTIONS_AMOUNT" translate-values="{number: accountCtrl.selectedTransactions.length}"></span> <i class="fa fa-sort-desc"></i></button>
<button class="account__add-button" ng-click="accountCtrl.copyToClipboard(accountCtrl.selectedTransactions)">COPY</button>
</div>
</div>
<div class="account__thead" ng-click="dbCtrl.stopPropagation($event)">
......@@ -98,10 +138,14 @@
class="account__transaction-editor"
ng-click="dbCtrl.stopPropagation($event)"></transaction-editor>
</div>
</div>
<div class="account__tbody account__tbody--striped virtual-list" vs-repeat vs-size="dbCtrl.getTransactionHeight(transaction)" ng-class="{'odd-total': displayedTransactions.length % 2}">
<div ng-repeat="transaction in displayedTransactions track by transaction.id">
<!-- add -->
<div ng-repeat="transaction in displayedTransactions | searchFromTransactions:search | searchByDateStartEnd :dateStart:dateEnd track by transaction.id">
<div class="account__tr"
ng-if="accountCtrl.editingTransaction !== transaction"
ng-click="accountCtrl.selectRow($event, $index+startIndex)"
......@@ -116,7 +160,7 @@
</span>
</div>
<div class="account__td account__td--flag"><div class="account__flag" ng-style="{'color': transaction.flag}" flag ng-model="transaction.flag"><div></div></div></div>
<div class="account__td account__td--date" transaction-field-focus-name="date">
<div class="account__td account__td--date">
<span><span>{{transaction.date | date : 'shortDate'}}</span></span>
</div>
<div class="account__td account__td--check" ng-if="accountCtrl.checkNumber" transaction-field-focus-name="check">
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment