525 lines
18 KiB
JavaScript
525 lines
18 KiB
JavaScript
var transactionControllers = angular.module('transactionControllers', ['ngResource']);
|
|
|
|
function amountToNumber(amount) {
|
|
var number = amount.toString().replace('.', '').replace(',', '.');
|
|
if (number.charAt(0) !== '+' && number.charAt(0) !== '-') {
|
|
number = '-' + number;
|
|
}
|
|
return number;
|
|
}
|
|
|
|
function numberToAmount(number) {
|
|
var amount = number.toFixed(2).toString().replace('.', ',');
|
|
if (amount.charAt(0) !== '-' && amount !== '0,00') {
|
|
amount = "+" + amount;
|
|
}
|
|
return amount;
|
|
}
|
|
|
|
transactionControllers.controller('TransactionListCtrl', [ '$scope', '$routeParams', '$resource', '$q', '$uibModal', '$log', 'Transaction', function($scope, $routeParams, $resource, $q, $uibModal, $log, Transaction) {
|
|
|
|
function refreshExpenses() {
|
|
var accountUsers = $resource($scope.account._links.users.href).get();
|
|
accountUsers.$promise.then(function(data) {
|
|
$scope.accountUsers = accountUsers._embedded.users;
|
|
|
|
// get outstandings (expenses and withdrawals) for all users of the account
|
|
var promises = new Array($scope.accountUsers.length);
|
|
for (i = 0; i < $scope.accountUsers.length; i++) {
|
|
var resource = $resource('/api/transactions/search/outstandings', { accountId: $scope.account.id, userId: $scope.accountUsers[i].id, size: 500 }).get();
|
|
promises[i] = resource.$promise;
|
|
}
|
|
|
|
$q.all(promises).then(function(data) {
|
|
for (i = 0; i < data.length; i++) {
|
|
$scope.accountUsers[i].outstandings = new Array(data[i]._embedded.transactions.length);
|
|
$scope.accountUsers[i].outstandingSum = 0.0;
|
|
|
|
for (j = 0; j < data[i]._embedded.transactions.length; j++) {
|
|
|
|
$scope.accountUsers[i].outstandings[j] = new Object();
|
|
|
|
$scope.accountUsers[i].outstandings[j].date = data[i]._embedded.transactions[j].date;
|
|
$scope.accountUsers[i].outstandings[j].description = data[i]._embedded.transactions[j].description;
|
|
|
|
$scope.accountUsers[i].outstandings[j].href = data[i]._embedded.transactions[j]._links.self.href;
|
|
$scope.accountUsers[i].outstandings[j].category = data[i]._embedded.transactions[j].category.name;
|
|
|
|
if ($scope.accountUsers[i].outstandings[j].category === 'Private Entnahme') { // magic strings ftw
|
|
$scope.accountUsers[i].outstandingSum += data[i]._embedded.transactions[j].amount;
|
|
$scope.accountUsers[i].outstandings[j].amount = numberToAmount(data[i]._embedded.transactions[j].amount);
|
|
}
|
|
else {
|
|
$scope.accountUsers[i].outstandingSum -= data[i]._embedded.transactions[j].amount;
|
|
$scope.accountUsers[i].outstandings[j].amount = numberToAmount(-data[i]._embedded.transactions[j].amount);
|
|
}
|
|
}
|
|
|
|
$scope.accountUsers[i].outstandingAmount = numberToAmount($scope.accountUsers[i].outstandingSum);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
$scope.refreshList = function() {
|
|
|
|
// reset form
|
|
if ($scope.form) {
|
|
$scope.form.$setPristine();
|
|
$scope.form.$setUntouched();
|
|
}
|
|
|
|
$scope.transaction = {
|
|
amount: undefined,
|
|
date: new Date(),
|
|
creditor: ""
|
|
};
|
|
|
|
if (typeof $scope.categories !== 'undefined') {
|
|
$scope.transaction.category = $scope.categories[0];
|
|
|
|
// XXX dirty hack - one day we will have to move that into the database...
|
|
if ($scope.account.name == 'Gemeinschaftskonto') {
|
|
$scope.transaction.category = $scope.categories[3];
|
|
}
|
|
}
|
|
|
|
$scope.checkCategory();
|
|
|
|
// get recent transactions
|
|
var transactions = $resource('/api/transactions/search/forAccount', { accountId: $scope.account.id, size: $scope.pageSize, sort: 'date,desc' }).get();
|
|
transactions.$promise.then(function(data) {
|
|
$scope.transactions = transactions._embedded.transactions;
|
|
$scope.nextPageAvailable = (transactions.page.totalPages !== transactions.page.number + 1);
|
|
$scope.prevPageAvailable = (transactions.page.number > 0);
|
|
$scope.pageNumber = transactions.page.number;
|
|
|
|
for (i = 0; i < $scope.transactions.length; i++) {
|
|
$scope.transactions[i].amount = numberToAmount($scope.transactions[i].amount);
|
|
}
|
|
});
|
|
|
|
refreshExpenses();
|
|
}
|
|
|
|
$scope.checkCategory = function() {
|
|
|
|
// if this is selected to be a withdrawal, preselect the current user and disable "no creditor" radio button
|
|
if ($scope.transaction.category.name === 'Private Entnahme') {
|
|
$scope.transaction.creditor = $scope.userinfo._links.self.href;
|
|
document.getElementById('noCreditorRadioButton').disabled = true;
|
|
}
|
|
else {
|
|
document.getElementById('noCreditorRadioButton').disabled = false;
|
|
document.getElementById('noCreditorRadioButton').checked = true;
|
|
}
|
|
}
|
|
|
|
$scope.initList = function() {
|
|
$scope.pageSize = 20;
|
|
|
|
var userinfo = $resource('/user').get();
|
|
userinfo.$promise.then(function(data) {
|
|
$scope.userid = userinfo.name;
|
|
|
|
userinfo = $resource('/api/users/search/findByUsername', { username: $scope.userid }).get();
|
|
userinfo.$promise.then(function(data) {
|
|
$scope.userinfo = userinfo;
|
|
});
|
|
|
|
var accountInfo = $resource('/api/accounts/search/findByUserName', { username: $scope.userid }).get();
|
|
accountInfo.$promise.then(function(data) {
|
|
$scope.accounts = accountInfo._embedded.accounts;
|
|
if ($scope.account == undefined) {
|
|
$scope.account = $scope.accounts[0];
|
|
if ($routeParams.account != undefined) {
|
|
for (i = 0; i < $scope.accounts.length; i++) {
|
|
if ($scope.accounts[i].name == $routeParams.account)
|
|
$scope.account = $scope.accounts[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
var categories = $resource('/api/categories/search/listForAccount', { accountId: $scope.account.id }).get();
|
|
categories.$promise.then(function(data) {
|
|
$scope.categories = categories._embedded.categories;
|
|
|
|
// remove retired categories
|
|
for (i = 0; i < $scope.categories.length; i++) {
|
|
if ($scope.categories[i].retired) {
|
|
$scope.categories.splice(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
$scope.refreshList();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
$scope.submitTransaction = function() {
|
|
if (document.getElementById('amountInput').value) {
|
|
document.getElementById('transactionSubmit').disabled = true;
|
|
$scope.waitingForSubmission = true;
|
|
|
|
var newTransaction = new Transaction({
|
|
"account" : $scope.account._links.self.href,
|
|
"amount" : amountToNumber($scope.transaction.amount),
|
|
"date" : $scope.transaction.date,
|
|
"description" : $scope.transaction.description != undefined ? $scope.transaction.description : '',
|
|
"category" : $scope.transaction.category._links.self.href,
|
|
"creditor" : $scope.transaction.creditor
|
|
});
|
|
|
|
newTransaction.$save(function(transaction) {
|
|
console.log(transaction);
|
|
document.getElementById('transactionSubmit').disabled = false;
|
|
$scope.waitingForSubmission = false;
|
|
$scope.refreshList();
|
|
$scope.lastSubmission = newTransaction;
|
|
$scope.lastSubmission.amount = numberToAmount(newTransaction.amount);
|
|
});
|
|
}
|
|
}
|
|
|
|
$scope.deleteLastSubmission = function() {
|
|
var testTrns = $resource($scope.lastSubmission._links.self.href).delete(function() {
|
|
$scope.lastSubmission = undefined;
|
|
$scope.refreshList();
|
|
});
|
|
};
|
|
|
|
$scope.moreTransactions = function() {
|
|
if ($scope.nextPageAvailable) {
|
|
$scope.pageNumber++;
|
|
var transactions = $resource('/api/transactions/search/forAccount', { accountId: $scope.account.id, size: $scope.pageSize, sort: 'date,desc', page: $scope.pageNumber }).get();
|
|
transactions.$promise.then(function(data) {
|
|
for (i = 0; i < transactions._embedded.transactions.length; i++) {
|
|
transactions._embedded.transactions[i].amount = numberToAmount(transactions._embedded.transactions[i].amount);
|
|
}
|
|
|
|
$scope.transactions = $scope.transactions.concat(transactions._embedded.transactions);
|
|
$scope.nextPageAvailable = (transactions.page.totalPages !== transactions.page.number + 1);
|
|
$scope.prevPageAvailable = (transactions.page.number > 0);
|
|
$scope.pageNumber = transactions.page.number;
|
|
});
|
|
}
|
|
};
|
|
|
|
$scope.updateSuggestions = function(val) {
|
|
var suggestions = $resource('/api/transactions/search/descriptions', { accountId: $scope.account.id, prefix: val.toLowerCase() }).get();
|
|
return suggestions.$promise.then(function(data) {
|
|
var newSuggestions = new Array();
|
|
var numSuggestions = 0;
|
|
var idx = 0;
|
|
|
|
while (numSuggestions < 6 && idx < suggestions._embedded.transactions.length) {
|
|
if (newSuggestions.indexOf(suggestions._embedded.transactions[idx].description) < 0) {
|
|
newSuggestions[numSuggestions] = suggestions._embedded.transactions[idx].description;
|
|
numSuggestions++;
|
|
}
|
|
idx++;
|
|
}
|
|
|
|
return newSuggestions;
|
|
});
|
|
};
|
|
|
|
$scope.openDetails = function(transaction) {
|
|
var modalInstance = $uibModal.open({
|
|
templateUrl: 'detailsTemplate.html',
|
|
controller: 'DetailsModalCtrl',
|
|
resolve: {
|
|
transactionId: transaction.id,
|
|
categories: function () {
|
|
return $scope.categories;
|
|
},
|
|
accountUsers: function () {
|
|
return $scope.accountUsers;
|
|
}
|
|
}
|
|
});
|
|
|
|
modalInstance.result.then(function(editedTransaction) {
|
|
|
|
$scope.lastSubmission = undefined;
|
|
|
|
if (editedTransaction.amount != undefined) {
|
|
transaction.amount = editedTransaction.amount;
|
|
transaction.date = editedTransaction.date;
|
|
transaction.description = editedTransaction.description;
|
|
|
|
transaction.creditor = $resource(editedTransaction.creditor).get();
|
|
transaction.category = $resource(editedTransaction.category).get();
|
|
}
|
|
else {
|
|
// if the transaction has been deleted, only the ID is returned
|
|
for (i = 0; i < $scope.transactions.length; i++) {
|
|
if ($scope.transactions[i].id == editedTransaction) {
|
|
$scope.transactions.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshExpenses();
|
|
|
|
}, function () {
|
|
$log.info('DetailsModal dismissed ' + new Date());
|
|
});
|
|
};
|
|
|
|
$scope.openOutstandings = function(user) {
|
|
var modalInstance = $uibModal.open({
|
|
templateUrl: 'outstandingsTemplate.html',
|
|
controller: 'OutstandingsModalCtrl',
|
|
resolve: {
|
|
accountUser: user
|
|
}
|
|
});
|
|
|
|
modalInstance.result.then(function() {
|
|
$scope.refreshList();
|
|
}, function () {
|
|
$log.info('OutstandingsModal dismissed ' + new Date());
|
|
});
|
|
};
|
|
|
|
// initialize (http://stackoverflow.com/a/25662066/3761783)
|
|
$scope.initList();
|
|
|
|
} ]);
|
|
|
|
transactionControllers.controller('DetailsModalCtrl', [ '$scope', '$resource', '$uibModalInstance', 'Transaction', 'transactionId', 'categories', 'accountUsers', function($scope, $resource, $uibModalInstance, Transaction, transactionId, categories, accountUsers) {
|
|
|
|
$scope.accountUsers = accountUsers;
|
|
|
|
var transaction = Transaction.get({ id: transactionId });
|
|
transaction.$promise.then(function(data) {
|
|
transaction.amount = numberToAmount(transaction.amount);
|
|
transaction.date = new Date(transaction.date);
|
|
transaction.creditor = $resource(transaction._links.creditor.href).get();
|
|
transaction.category = $resource(transaction._links.category.href).get();
|
|
|
|
transaction.category.$promise.then(function(data) {
|
|
$scope.transaction = transaction;
|
|
$scope.categories = categories;
|
|
|
|
for (i = 0; i < $scope.categories.length; i++) {
|
|
if ($scope.categories[i].name == $scope.transaction.category.name) {
|
|
$scope.transaction.category = $scope.categories[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
transaction.creditor.$promise.then(function(data) {
|
|
$scope.transaction.creditor = $scope.transaction.creditor._links.user.href;
|
|
},
|
|
function(error) { // transactions without a creditor return a HTTP 404 error
|
|
$scope.transaction.creditor = "";
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
$scope.ok = function () {
|
|
$scope.transaction.category = $scope.transaction.category._links.self.href;
|
|
$scope.transaction.amount = amountToNumber($scope.transaction.amount);
|
|
$scope.transaction.$update(function(data) {}).then(
|
|
$uibModalInstance.close($scope.transaction)
|
|
);
|
|
};
|
|
|
|
$scope.cancel = function () {
|
|
$uibModalInstance.dismiss('cancel');
|
|
};
|
|
|
|
$scope.deleteTransaction = function() {
|
|
var deletedTransactionId = $scope.transaction.id;
|
|
$resource($scope.transaction._links.self.href).remove().$promise.then(function() {
|
|
$uibModalInstance.close(deletedTransactionId);
|
|
});
|
|
}
|
|
} ]);
|
|
|
|
transactionControllers.controller('OutstandingsModalCtrl', [ '$scope', '$uibModalInstance', '$http', '$resource', '$q', 'accountUser', function($scope, $uibModalInstance, $http, $resource, $q, accountUser) {
|
|
|
|
$scope.accountUser = accountUser;
|
|
|
|
$scope.ok = function () {
|
|
$uibModalInstance.close();
|
|
};
|
|
|
|
$scope.close = function () {
|
|
$uibModalInstance.dismiss('close');
|
|
};
|
|
|
|
$scope.clearOutstandings = function() {
|
|
var promises = new Array($scope.accountUser.outstandings.length);
|
|
for (i = 0; i < $scope.accountUser.outstandings.length; i++) {
|
|
if ($scope.accountUser.outstandings[i].category === 'Private Entnahme') {
|
|
// delete withdrawals
|
|
var resource = $resource($scope.accountUser.outstandings[i].href).remove();
|
|
promises[i] = resource.$promise;
|
|
}
|
|
else {
|
|
// remove creditor from expenses
|
|
promises[i] = $http.patch($scope.accountUser.outstandings[i].href, '{ "creditor" : "" }');
|
|
}
|
|
}
|
|
|
|
$q.all(promises).then(function(data) {
|
|
$uibModalInstance.close('cleared outstandings');
|
|
});
|
|
}
|
|
} ]);
|
|
|
|
transactionControllers.controller('ImportCtrl', [ '$scope', '$resource', '$location', 'ImportService', function($scope, $resource, $location, ImportService) {
|
|
|
|
$scope.importCSV = function () {
|
|
ImportService.setAccount($scope.account);
|
|
ImportService.setCategories($scope.categories);
|
|
ImportService.setCSV($scope.csvInput);
|
|
$location.path('importList');
|
|
}
|
|
|
|
$scope.initPage = function () {
|
|
var userinfo = $resource('/user').get();
|
|
userinfo.$promise.then(function(data) {
|
|
$scope.userid = userinfo.name;
|
|
|
|
userinfo = $resource('/api/users/search/findByUsername', { username: $scope.userid }).get();
|
|
userinfo.$promise.then(function(data) {
|
|
$scope.userinfo = userinfo;
|
|
});
|
|
|
|
var accountInfo = $resource('/api/accounts/search/findByUserName', { username: $scope.userid }).get();
|
|
accountInfo.$promise.then(function(data) {
|
|
$scope.accounts = accountInfo._embedded.accounts;
|
|
$scope.account = $scope.accounts[0];
|
|
|
|
var categories = $resource('/api/categories/search/listForAccount', { accountId: $scope.account.id }).get();
|
|
categories.$promise.then(function(data) {
|
|
$scope.categories = categories._embedded.categories;
|
|
|
|
if ($scope.importForm) {
|
|
$scope.importForm.$setPristine();
|
|
$scope.importForm.$setUntouched();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
$scope.initPage();
|
|
|
|
} ]);
|
|
|
|
transactionControllers.controller('ImportListCtrl', [ '$scope', '$resource', '$location', 'ImportService', 'Transaction', function($scope, $resource, $location, ImportService, Transaction) {
|
|
|
|
$scope.processCSV = function () {
|
|
$scope.account = ImportService.getAccount();
|
|
$scope.categories = ImportService.getCategories();
|
|
$scope.csvInput = ImportService.getCSV();
|
|
$scope.csv = Papa.parse(ImportService.getCSV()).data;
|
|
|
|
var matcherData = $resource('/api/matchers/search/listForAccount', { projection: 'full', accountId: $scope.account.id }).get();
|
|
matcherData.$promise.then(function(data) {
|
|
matcherData = matcherData._embedded.matchers;
|
|
$scope.matchers = new Array(matcherData.length);
|
|
|
|
for (i = 0; i < $scope.matchers.length; i++) {
|
|
$scope.matchers[i] = {};
|
|
|
|
$scope.matchers[i].id = matcherData[i].id;
|
|
$scope.matchers[i].position = matcherData[i].position;
|
|
|
|
if (matcherData[i].dateMatcherCode != null) {
|
|
$scope.matchers[i].dateMatcher = new Function('x', matcherData[i].dateMatcherCode);
|
|
$scope.matchers[i].dateMatcherCode = matcherData[i].dateMatcherCode;
|
|
}
|
|
|
|
if (matcherData[i].typeMatcherCode != null) {
|
|
$scope.matchers[i].typeMatcher = new Function('x', matcherData[i].typeMatcherCode);
|
|
$scope.matchers[i].typeMatcherCode = matcherData[i].typeMatcherCode;
|
|
}
|
|
|
|
if (matcherData[i].textMatcherCode != null) {
|
|
$scope.matchers[i].textMatcher = new Function('x', matcherData[i].textMatcherCode);
|
|
$scope.matchers[i].textMatcherCode = matcherData[i].textMatcherCode;
|
|
}
|
|
|
|
if (matcherData[i].amountMatcherCode != null) {
|
|
$scope.matchers[i].amountMatcher = new Function('x', matcherData[i].amountMatcherCode);
|
|
$scope.matchers[i].amountMatcherCode = matcherData[i].amountMatcherCode;
|
|
}
|
|
|
|
$scope.matchers[i].targetDescription = matcherData[i].targetDescription;
|
|
$scope.matchers[i].targetCategory = matcherData[i].targetCategory;
|
|
|
|
}
|
|
|
|
for (i = 0; i < $scope.csv.length; i++) {
|
|
var j = 0;
|
|
|
|
while (j < $scope.matchers.length) {
|
|
var match = true;
|
|
|
|
if ($scope.matchers[j].dateMatcher)
|
|
match = $scope.matchers[j].dateMatcher($scope.csv[i][1]);
|
|
if (match && $scope.matchers[j].typeMatcher)
|
|
match = $scope.matchers[j].typeMatcher($scope.csv[i][2]);
|
|
if (match && $scope.matchers[j].textMatcher)
|
|
match = $scope.matchers[j].textMatcher($scope.csv[i][3]);
|
|
if (match && $scope.matchers[j].amountMatcher)
|
|
match = $scope.matchers[j].amountMatcher($scope.csv[i][4].toString().replace('.', '').replace(',', '.'));
|
|
|
|
if (match) {
|
|
$scope.csv[i].targetDescription = $scope.matchers[j].targetDescription;
|
|
$scope.csv[i].matcherPosition = $scope.matchers[j].position;
|
|
for (k = 0; k < $scope.categories.length; k++) {
|
|
if ($scope.categories[k].name == $scope.matchers[j].targetCategory.name)
|
|
$scope.csv[i].targetCategory = $scope.categories[k];
|
|
}
|
|
break;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
$scope.importTransaction = function(line) {
|
|
if (line.targetCategory) {
|
|
|
|
var newTransaction = new Transaction({
|
|
"account" : $scope.account._links.self.href,
|
|
"amount" : line[4].replace(',', '.'),
|
|
"date" : new Date(line[1].substr(6,4) + "-" + line[1].substr(3,2) + "-" + line[1].substr(0,2)),
|
|
"description" : line.targetDescription != undefined ? line.targetDescription : '',
|
|
"category" : line.targetCategory._links.self.href,
|
|
"creditor" : ""
|
|
});
|
|
|
|
newTransaction.$save(function(transaction) {
|
|
line.submitted = true;
|
|
console.log(transaction);
|
|
line.submittedTransactionLink = transaction._links.self.href;
|
|
line.submittedTransactionId = transaction.id;
|
|
|
|
// delete from CSV
|
|
var descriptionPos = $scope.csvInput.search(line[3]);
|
|
var lineStart = $scope.csvInput.lastIndexOf('\n', descriptionPos);
|
|
var lineEnd = $scope.csvInput.indexOf('\n', descriptionPos);
|
|
if (lineEnd < 0)
|
|
lineEnd = $scope.csvInput.length;
|
|
$scope.csvInput = $scope.csvInput.substring(0, lineStart) + $scope.csvInput.substring(lineEnd, $scope.csvInput.length);
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
} ]);
|
|
|