diff --git a/.jscsrc b/.jscsrc
new file mode 100644
index 0000000..a0f419d
--- /dev/null
+++ b/.jscsrc
@@ -0,0 +1,35 @@
+{
+ "preset": "google",
+ "fileExtensions": [".js", "jscs"],
+
+ "requireSemicolons": true,
+ "requireParenthesesAroundIIFE": true,
+ "maximumLineLength": 120,
+ "validateLineBreaks": "LF",
+ "validateIndentation": 4,
+ "disallowTrailingComma": true,
+ "disallowUnusedParams": true,
+
+ "disallowSpacesInsideObjectBrackets": null,
+ "disallowImplicitTypeConversion": ["string"],
+
+ "safeContextKeyword": "_this",
+
+ "jsDoc": {
+ "checkAnnotations": "closurecompiler",
+ "checkParamNames": true,
+ "requireParamTypes": true,
+ "checkRedundantParams": true,
+ "checkReturnTypes": true,
+ "checkRedundantReturns": true,
+ "requireReturnTypes": true,
+ "checkTypes": "capitalizedNativeCase",
+ "checkRedundantAccess": true,
+ "requireNewlineAfterDescription": true
+ },
+
+ "excludeFiles": [
+ "test/data/**",
+ "patterns/*"
+ ]
+}
diff --git a/accountant-ui/js/accounts.js b/accountant-ui/js/accounts.js
index e7b758a..a9e38b8 100644
--- a/accountant-ui/js/accounts.js
+++ b/accountant-ui/js/accounts.js
@@ -1,3 +1,4 @@
+// vim: set tw=80 ts=4 sw=4 sts=4:
/*
This file is part of Accountant.
@@ -14,7 +15,6 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see .
*/
-// vim: set tw=80 ts=2 sw=2 sts=2:
'use strict';
angular.module('accountant.accounts', [
@@ -66,92 +66,100 @@ angular.module('accountant.accounts', [
* overdraft.
*/
$scope.rowClass = function(account) {
- if(!account || !account.authorized_overdraft || !account.current) {
- return;
- }
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ if (!account || !account.authorized_overdraft || !account.current) {
+ return;
+ }
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
- if(account.current < account.authorized_overdraft) {
- return 'danger';
- } else if(account.current < 0) {
- return 'warning';
- }
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ if (account.current < account.authorized_overdraft) {
+ return 'danger';
+ } else if (account.current < 0) {
+ return 'warning';
+ }
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
};
/*
* Return the class for a value compared to account authorized overdraft.
*/
$scope.valueClass = function(account, value) {
- if(!account || !value) {
+ if (!account || !value) {
return;
}
- if(value < account.authorized_overdraft) {
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ if (value < account.authorized_overdraft) {
return 'text-danger';
- } else if(value < 0) {
+ } else if (value < 0) {
return 'text-warning';
}
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
};
/*
* Add an empty account.
*/
$scope.add = function() {
- var account = new Account({
- authorized_overdraft: 0
- });
+ var account = new Account({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ authorized_overdraft: 0
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ });
- // Insert account at the begining of the array.
- $scope.accounts.splice(0, 0, account);
+ // Insert account at the begining of the array.
+ $scope.accounts.splice(0, 0, account);
};
/*
* Cancel account edition. Remove it from array if a new one.
*/
$scope.cancelEdit = function(rowform, account, $index) {
- if(!account.id) {
- // Account not saved, just remove it from array.
- $scope.accounts.splice($index, 1);
- } else {
- rowform.$cancel();
- }
+ if (!account.id) {
+ // Account not saved, just remove it from array.
+ $scope.accounts.splice($index, 1);
+ } else {
+ rowform.$cancel();
+ }
};
/*
* Save account.
*/
$scope.save = function(account) {
- //var account = $scope.accounts[$index];
+ //var account = $scope.accounts[$index];
- //account = angular.merge(account, $data);
+ //account = angular.merge(account, $data);
- return account.$save().then(function(data) {
- Notification.success('Account #' + data.id + ' saved.');
+ return account.$save().then(function(data) {
+ Notification.success('Account #' + data.id + ' saved.');
- // TODO Alexis Lahouze 2016-03-08 Update solds
+ // TODO Alexis Lahouze 2016-03-08 Update solds
- return data;
- });
+ return data;
+ });
};
/*
* Delete an account.
*/
$scope.delete = function(account, $index) {
- var id = account.id;
+ var id = account.id;
- $ngBootbox.confirm(
- 'Voulez-vous supprimer le compte \'' + account.name + '\' ?',
- function(result) {
- if(result) {
- account.$delete().then(function() {
- Notification.success('Account #' + id + ' deleted.');
+ $ngBootbox.confirm(
+ 'Voulez-vous supprimer le compte \'' + account.name + '\' ?',
+ function(result) {
+ if (result) {
+ account.$delete().then(function() {
+ Notification.success('Account #' + id + ' deleted.');
- // Remove account from array.
- $scope.accounts.splice($index, 1);
- });
- }
- }
- );
+ // Remove account from array.
+ $scope.accounts.splice($index, 1);
+ });
+ }
+ }
+ );
};
// Load accounts.
@@ -169,46 +177,50 @@ angular.module('accountant.accounts', [
link: function(scope, element) {
var title = 'Account';
- if(scope.account && scope.account.id) {
+ if (scope.account && scope.account.id) {
title = title + ' #' + scope.account.id;
}
scope.form = {};
scope.submitForm = function() {
- // check to make sure the form is completely valid
- if (!scope.form.$valid) {
- return false;
- }
-
- // Authorized overdraft is a positive integer but data is a negative integer.
- scope.data.authorized_overdraft = -scope.data.authorized_overdraft
-
- angular.copy(scope.data, scope.account);
-
- // Save account
- console.log(scope.account);
- return scope.account.$save().then(
- function(data) {
- Notification.success('Account #' + data.id + ' saved.');
-
- scope.account.getSolds();
-
- return data;
- }, function(data) {
- Notification.error('Error while saving account #' + data.id);
- scope.account.getSolds();
- console.log(data);
+ // check to make sure the form is completely valid
+ if (!scope.form.$valid) {
return false;
}
- );
+
+ // Authorized overdraft is a positive integer but data is a negative integer.
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ scope.data.authorized_overdraft = -scope.data.authorized_overdraft;
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+
+ angular.copy(scope.data, scope.account);
+
+ // Save account
+ console.log(scope.account);
+ return scope.account.$save().then(
+ function(data) {
+ Notification.success('Account #' + data.id + ' saved.');
+
+ scope.account.getSolds();
+
+ return data;
+ }, function(data) {
+ Notification.error('Error while saving account #' + data.id);
+ scope.account.getSolds();
+ console.log(data);
+ return false;
+ }
+ );
};
element.on('click', function() {
// Create new account if not passed in ng-model.
- if(!scope.account) {
+ if (!scope.account) {
scope.account = new Account({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
authorized_overdraft: 0
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
});
}
@@ -216,7 +228,9 @@ angular.module('accountant.accounts', [
angular.copy(scope.account, scope.data);
// Authorized overdraft must be positive in form.
- scope.data.authorized_overdraft = -scope.data.authorized_overdraft
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ scope.data.authorized_overdraft = -scope.data.authorized_overdraft;
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
// Open dialog with form.
$ngBootbox.customDialog({
@@ -240,4 +254,5 @@ angular.module('accountant.accounts', [
});
}
};
-});
+ }
+);
diff --git a/accountant-ui/js/app.js b/accountant-ui/js/app.js
index 628d9f2..077b7a2 100644
--- a/accountant-ui/js/app.js
+++ b/accountant-ui/js/app.js
@@ -1,3 +1,4 @@
+// vim: set tw=80 ts=4 sw=4 sts=4:
/*
This file is part of Accountant.
@@ -14,7 +15,6 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see .
*/
-// vim: set tw=80 ts=2 sw=2 sts=2:
'use strict';
angular.module('accountant', [
@@ -29,12 +29,12 @@ angular.module('accountant', [
.factory('sessionInjector', ['$storage', function($storage) {
var sessionInjector = {
- request : function(config) {
+ request: function(config) {
var token = $storage.get('token');
- if(token) {
- var token_type = $storage.get('token_type');
- var authorization = token_type + ' ' + token;
+ if (token) {
+ var tokenType = $storage.get('token_type');
+ var authorization = tokenType + ' ' + token;
config.headers.Authorization = authorization;
}
@@ -53,30 +53,29 @@ angular.module('accountant', [
.config(['$routeProvider', function($routeProvider) {
// Defining template and controller in function of route.
$routeProvider
- .when('/account/:accountId/operations', {
- templateUrl: 'views/operations.html',
- controller: 'OperationController',
- controllerAs: 'operationsCtrl'
- })
- .when('/account/:accountId/scheduler', {
- templateUrl: 'views/scheduler.html',
- controller: 'SchedulerController',
- controllerAs: 'schedulerCtrl'
- })
- .when('/accounts', {
- templateUrl: 'views/accounts.html',
- controller: 'AccountController',
- controllerAs: 'accountsCtrl'
- })
- .otherwise({
- redirectTo: '/accounts'
- });
-
+ .when('/account/:accountId/operations', {
+ templateUrl: 'views/operations.html',
+ controller: 'OperationController',
+ controllerAs: 'operationsCtrl'
+ })
+ .when('/account/:accountId/scheduler', {
+ templateUrl: 'views/scheduler.html',
+ controller: 'SchedulerController',
+ controllerAs: 'schedulerCtrl'
+ })
+ .when('/accounts', {
+ templateUrl: 'views/accounts.html',
+ controller: 'AccountController',
+ controllerAs: 'accountsCtrl'
+ })
+ .otherwise({
+ redirectTo: '/accounts'
+ });
}])
.config(['$storageProvider', function($storageProvider) {
// Configure storage
- // Set global prefix for stored keys
+ // Set global prefix for stored keys
$storageProvider.setPrefix('accountant');
// Change the default storage engine
@@ -98,54 +97,58 @@ angular.module('accountant', [
$scope.dialogShown = false;
$scope.showLoginForm = function() {
- // First, if there are registered credentials, use them
- if($scope.dialogShown) {
- return;
- }
-
- $scope.dialogShown = true;
-
- $storage.clear();
-
- $ngBootbox.customDialog({
- title: 'Authentification requise',
- templateUrl: 'views/login.tmpl.html',
- buttons: {
- login: {
- label: 'Login',
- className: 'btn-primary',
- callback: function() {
- $scope.dialogShown = false;
-
- var email = $('#email').val();
- var password = $('#password').val();
- $http.post(
- '/api/user/login',
- {
- 'email': email,
- 'password': password
- }
- ).success(function(result) {
- // TODO Alexis Lahouze 2015-08-28 Handle callback.
- // Call to /api/login to retrieve the token
- $storage.set('token_type', result.token_type);
- $storage.set('token', result.token);
- $storage.set('expiration_date', result.expiration_date);
-
- authService.loginConfirmed();
- });
- }
- },
- cancel: {
- label: 'Annuler',
- className: 'btn-default',
- callback: function() {
- authService.loginCancelled(null, 'Login cancelled by user action.');
- $scope.dialogShown = false;
- }
- }
+ // First, if there are registered credentials, use them
+ if ($scope.dialogShown) {
+ return;
}
- });
+
+ $scope.dialogShown = true;
+
+ $storage.clear();
+
+ $ngBootbox.customDialog({
+ title: 'Authentification requise',
+ templateUrl: 'views/login.tmpl.html',
+ buttons: {
+ login: {
+ label: 'Login',
+ className: 'btn-primary',
+ callback: function() {
+ $scope.dialogShown = false;
+
+ var email = $('#email').val();
+ var password = $('#password').val();
+ $http.post(
+ '/api/user/login',
+ {
+ 'email': email,
+ 'password': password
+ }
+ ).success(function(result) {
+ // TODO Alexis Lahouze 2015-08-28 Handle callback.
+ // Call to /api/login to retrieve the token
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ $storage.set('token_type', result.token_type);
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ $storage.set('token', result.token);
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ $storage.set('expiration_date', result.expiration_date);
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+
+ authService.loginConfirmed();
+ });
+ }
+ },
+ cancel: {
+ label: 'Annuler',
+ className: 'btn-default',
+ callback: function() {
+ authService.loginCancelled(null, 'Login cancelled by user action.');
+ $scope.dialogShown = false;
+ }
+ }
+ }
+ });
};
$rootScope.$on('event:auth-loginRequired', $scope.showLoginForm);
diff --git a/accountant-ui/js/operations.js b/accountant-ui/js/operations.js
index 66304ed..3508f5a 100644
--- a/accountant-ui/js/operations.js
+++ b/accountant-ui/js/operations.js
@@ -1,3 +1,4 @@
+// vim: set tw=80 ts=4 sw=4 sts=4:
/*
This file is part of Accountant.
@@ -14,7 +15,6 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see .
*/
-// vim: set tw=80 ts=2 sw=2 sts=2:
'use strict';
angular.module('accountant.operations', [
@@ -24,7 +24,7 @@ angular.module('accountant.operations', [
'ngBootbox',
'ui-notification',
'mgcrea.ngStrap',
- 'highcharts-ng',
+ 'highcharts-ng'
])
.config(['$resourceProvider', function($resourceProvider) {
@@ -32,7 +32,7 @@ angular.module('accountant.operations', [
$resourceProvider.defaults.stripTrailingSlashes = false;
}])
-.factory('Operation', [ '$resource', function($resource) {
+.factory('Operation', ['$resource', function($resource) {
return $resource(
'/api/operation/:id', {
id: '@id'
@@ -40,29 +40,35 @@ angular.module('accountant.operations', [
);
}])
-.factory('OHLC', [ '$resource', '$routeParams',
+.factory('OHLC', ['$resource', '$routeParams',
function($resource, $routeParams) {
return $resource(
'/api/account/:account_id/ohlc', {
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
}
);
}])
-.factory('Category', [ '$resource', '$routeParams',
+.factory('Category', ['$resource', '$routeParams',
function($resource, $routeParams) {
return $resource(
'/api/account/:account_id/category', {
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
}
);
}])
-.factory('Balance', [ '$resource', '$routeParams',
+.factory('Balance', ['$resource', '$routeParams',
function($resource, $routeParams) {
return $resource(
'/api/account/:account_id/balance', {
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
}
);
}])
@@ -70,450 +76,457 @@ angular.module('accountant.operations', [
/*
* Controller for category chart.
*/
-.controller(
- 'CategoryChartController', [
+.controller('CategoryChartController', [
'$rootScope', '$scope', '$http', 'Category', 'Balance',
function($rootScope, $scope, $http, Category, Balance) {
+ var colors = Highcharts.getOptions().colors;
+ $scope.revenueColor = colors[2];
+ $scope.expenseColor = colors[3];
- var colors = Highcharts.getOptions().colors;
- $scope.revenueColor = colors[2];
- $scope.expenseColor = colors[3];
+ // Configure pie chart for categories.
+ $scope.config = {
+ options: {
+ chart: {
+ type: 'pie',
+ animation: {
+ duration: 500
+ }
+ },
+ plotOptions: {
+ pie: {
+ startAngle: -90
+ },
+ series: {
+ allowPointSelect: 0
+ }
+ },
+ tooltip: {
+ valueDecimals: 2,
+ valueSuffix: '€'
+ }
+ },
+ yAxis: {
+ title: {
+ text: 'Categories'
+ }
+ },
+ title: {
+ text: 'Répartition dépenses/recettes'
+ },
+ series: [{
+ name: 'Value',
+ data: [],
+ innerSize: '33%',
+ size: '60%',
+ dataLabels: {
+ formatter: function() {
+ return this.point.name;
+ },
+ distance: -40
+ }
+ }, {
+ name: 'Value',
+ data: [],
+ innerSize: '66%',
+ size: '60%',
+ dataLabels: {
+ formatter: function() {
+ return this.point.name !== null && this.percentage >= 2.5 ? this.point.name : null;
+ }
+ }
+ }]
+ };
- // Configure pie chart for categories.
- $scope.config = {
- options: {
- chart: {
- type: 'pie',
- animation: {
- duration: 500
- }
- },
- plotOptions: {
- pie: {
- startAngle: -90
- },
- series: {
- allowPointSelect: 0
- }
- },
- tooltip: {
- valueDecimals: 2,
- valueSuffix: '€'
- }
- },
- yAxis: {
- title: {
- text: 'Categories'
- }
- },
- title: {
- text: 'Répartition dépenses/recettes'
- },
- series: [{
- name: 'Value',
- data: [],
- innerSize: '33%',
- size: '60%',
- dataLabels: {
- formatter: function() {
- return this.point.name;
- },
- distance: -40
- }
- }, {
- name: 'Value',
- data: [],
- innerSize: '66%',
- size: '60%',
- dataLabels: {
- formatter: function() {
- return this.point.name !== null && this.percentage >= 2.5 ? this.point.name : null;
- },
- }
- }]
- };
+ $scope.brightenColor = function(color) {
+ var brightness = 0.2;
- $scope.brightenColor = function(color) {
- var brightness = 0.2;
+ return Highcharts.Color(color).brighten(brightness).get();
+ };
- return Highcharts.Color(color).brighten(brightness).get();
- };
+ // Load categories, mainly to populate the pie chart.
+ $scope.load = function(begin, end) {
+ $scope.config.loading = true;
- // Load categories, mainly to populate the pie chart.
- $scope.load = function(begin, end) {
- $scope.config.loading = true;
+ Category.query({
+ begin: begin.format('YYYY-MM-DD'),
+ end: end.format('YYYY-MM-DD')
+ }, function(data) {
+ var expenses = [];
+ var revenues = [];
- Category.query({
- begin: begin.format('YYYY-MM-DD'),
- end: end.format('YYYY-MM-DD')
- }, function(data) {
- var expenses = [], revenues = [];
+ var expenseColor = $scope.brightenColor($scope.expenseColor);
+ var revenueColor = $scope.brightenColor($scope.revenueColor);
- var expenseColor = $scope.brightenColor($scope.expenseColor);
- var revenueColor = $scope.brightenColor($scope.revenueColor);
+ angular.forEach(angular.fromJson(data), function(category) {
+ expenses.push({
+ name: category.category,
+ y: -category.expenses,
+ color: expenseColor
+ });
- angular.forEach(angular.fromJson(data), function(category) {
- expenses.push({
- name: category.category,
- y: -category.expenses,
- color: expenseColor
+ revenues.push({
+ name: category.category,
+ y: category.revenues,
+ color: revenueColor
+ });
+ });
+
+ // Note: expenses and revenues must be in the same order than in series[0].
+ $scope.config.series[1].data = revenues.concat(expenses);
+
+ $scope.config.loading = false;
+ });
+ };
+
+ /*
+ * Get account balance.
+ */
+ $scope.getBalance = function(begin, end) {
+ Balance.get({
+ begin: begin.format('YYYY-MM-DD'),
+ end: end.format('YYYY-MM-DD')
+ }, function(balance) {
+ // Update pie chart subtitle with Balance.
+ $scope.config.subtitle = {
+ text: 'Balance: ' + balance.balance
+ };
+
+ $scope.config.series[0].data = [{
+ name: 'Revenues',
+ y: balance.revenues,
+ color: $scope.revenueColor
+ }, {
+ name: 'Expenses',
+ y: -balance.expenses,
+ color: $scope.expenseColor
+ }];
+ });
+ };
+
+ // Reload categories and account status on range selection.
+ $rootScope.$on('rangeSelectedEvent', function(e, args) {
+ $scope.load(args.begin, args.end);
+ $scope.getBalance(args.begin, args.end);
});
-
- revenues.push({
- name: category.category,
- y: category.revenues,
- color: revenueColor
- });
- });
-
- // Note: expenses and revenues must be in the same order than in series[0].
- $scope.config.series[1].data = revenues.concat(expenses);
-
- $scope.config.loading = false;
- });
- };
-
- /*
- * Get account balance.
- */
- $scope.getBalance = function(begin, end) {
- Balance.get({
- begin: begin.format('YYYY-MM-DD'),
- end: end.format('YYYY-MM-DD')
- }, function(balance) {
- // Update pie chart subtitle with Balance.
- $scope.config.subtitle = {
- text: 'Balance: ' + balance.balance
- };
-
- $scope.config.series[0].data = [{
- name: 'Revenues',
- y: balance.revenues,
- color: $scope.revenueColor
- }, {
- name: 'Expenses',
- y: -balance.expenses,
- color: $scope.expenseColor,
- }];
- });
- };
-
- // Reload categories and account status on range selection.
- $rootScope.$on('rangeSelectedEvent', function(e, args) {
- $scope.load(args.begin, args.end);
- $scope.getBalance(args.begin, args.end);
- });
-}])
+ }
+])
/*
* Controller for the sold chart.
*/
-.controller(
- 'SoldChartController', [
+.controller('SoldChartController', [
'$rootScope', '$scope', '$http', 'OHLC',
function($rootScope, $scope, $http, OHLC) {
- // Configure chart for operations.
- $scope.config = {
- options: {
- chart: {
- zoomType: 'x'
- },
- rangeSelector: {
- buttons: [{
- type: 'month',
- count: 1,
- text: '1m'
- }, {
- type: 'month',
- count: 3,
- text: '3m'
- }, {
- type: 'month',
- count: 6,
- text: '6m'
- }, {
- type: 'year',
- count: 1,
- text: '1y'
- }, {
- type: 'all',
- text: 'All'
- }],
- selected: 0,
- },
- navigator: {
- enabled: true
- },
- tooltip: {
- crosshairs: true,
- shared: true,
- valueDecimals: 2,
- valueSuffix: '€'
- },
- scrollbar: {
- liveRedraw: false
- }
- },
- series: [{
- type: 'ohlc',
- name: 'Sold',
- data: [],
- dataGrouping : {
- units : [[
- 'week', // unit name
- [1] // allowed multiples
- ], [
- 'month',
- [1, 2, 3, 4, 6]
- ]]
- }
- }],
- title: {
- text: 'Sold evolution'
- },
- xAxis: {
- type: 'datetime',
- dateTimeLabelFormats: {
- month: '%e. %b',
- year: '%Y'
- },
- minRange: 3600 * 1000 * 24 * 14, // 2 weeks
- events: {
- afterSetExtremes: function(e) {
- $scope.$emit('rangeSelectedEvent', {
- begin: moment.utc(e.min), end: moment.utc(e.max)
- });
- }
- },
- currentMin: moment.utc().startOf('month'),
- currentMax: moment.utc().endOf('month')
- },
- yAxis: {
- plotLines: [{
- color: 'orange',
- width: 2,
- value: 0.0
- }, {
- color: 'red',
- width: 2,
- value: 0.0
- }]
- },
- useHighStocks: true
- };
+ // Configure chart for operations.
+ $scope.config = {
+ options: {
+ chart: {
+ zoomType: 'x'
+ },
+ rangeSelector: {
+ buttons: [{
+ type: 'month',
+ count: 1,
+ text: '1m'
+ }, {
+ type: 'month',
+ count: 3,
+ text: '3m'
+ }, {
+ type: 'month',
+ count: 6,
+ text: '6m'
+ }, {
+ type: 'year',
+ count: 1,
+ text: '1y'
+ }, {
+ type: 'all',
+ text: 'All'
+ }],
+ selected: 0
+ },
+ navigator: {
+ enabled: true
+ },
+ tooltip: {
+ crosshairs: true,
+ shared: true,
+ valueDecimals: 2,
+ valueSuffix: '€'
+ },
+ scrollbar: {
+ liveRedraw: false
+ }
+ },
+ series: [{
+ type: 'ohlc',
+ name: 'Sold',
+ data: [],
+ dataGrouping: {
+ units: [[
+ 'week', // unit name
+ [1] // allowed multiples
+ ], [
+ 'month',
+ [1, 2, 3, 4, 6]
+ ]]
+ }
+ }],
+ title: {
+ text: 'Sold evolution'
+ },
+ xAxis: {
+ type: 'datetime',
+ dateTimeLabelFormats: {
+ month: '%e. %b',
+ year: '%Y'
+ },
+ minRange: 3600 * 1000 * 24 * 14, // 2 weeks
+ events: {
+ afterSetExtremes: function(e) {
+ $scope.$emit('rangeSelectedEvent', {
+ begin: moment.utc(e.min), end: moment.utc(e.max)
+ });
+ }
+ },
+ currentMin: moment.utc().startOf('month'),
+ currentMax: moment.utc().endOf('month')
+ },
+ yAxis: {
+ plotLines: [{
+ color: 'orange',
+ width: 2,
+ value: 0.0
+ }, {
+ color: 'red',
+ width: 2,
+ value: 0.0
+ }]
+ },
+ useHighStocks: true
+ };
- $scope.loadSolds = function() {
- $scope.config.loading = true;
+ $scope.loadSolds = function() {
+ $scope.config.loading = true;
- OHLC.query({}, function(data) {
- $scope.config.series[0].data = [];
+ OHLC.query({}, function(data) {
+ $scope.config.series[0].data = [];
- angular.forEach(data, function(operation) {
- $scope.config.series[0].data.push([
- moment.utc(operation.operation_date).valueOf(),
- operation.open, operation.high, operation.low, operation.close
- ]);
- });
+ angular.forEach(data, function(operation) {
+ $scope.config.series[0].data.push([
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ moment.utc(operation.operation_date).valueOf(),
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ operation.open, operation.high, operation.low, operation.close
+ ]);
+ });
- $scope.$emit('rangeSelectedEvent', {
- begin: $scope.config.xAxis.currentMin,
- end: $scope.config.xAxis.currentMax
- });
+ $scope.$emit('rangeSelectedEvent', {
+ begin: $scope.config.xAxis.currentMin,
+ end: $scope.config.xAxis.currentMax
+ });
- $scope.config.loading = false;
- });
- };
+ $scope.config.loading = false;
+ });
+ };
- // Reload solds when an operation is saved.
- $rootScope.$on('operationSavedEvent', function() {
- $scope.loadSolds();
- });
+ // Reload solds when an operation is saved.
+ $rootScope.$on('operationSavedEvent', function() {
+ $scope.loadSolds();
+ });
- // Reload solds when an operation is deleted.
- $rootScope.$on('operationDeletedEvent', function() {
- $scope.loadSolds();
- });
+ // Reload solds when an operation is deleted.
+ $rootScope.$on('operationDeletedEvent', function() {
+ $scope.loadSolds();
+ });
- // Update authorized overdraft on account loading.
- $rootScope.$on('accountLoadedEvent', function(e, account) {
- $scope.config.yAxis.plotLines[1].value = account.authorized_overdraft;
- });
+ // Update authorized overdraft on account loading.
+ $rootScope.$on('accountLoadedEvent', function(e, account) {
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ $scope.config.yAxis.plotLines[1].value = account.authorized_overdraft;
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ });
- // Select beginning and end of month.
- $scope.loadSolds();
-}])
+ // Select beginning and end of month.
+ $scope.loadSolds();
+ }
+])
/*
* Controller for the operations.
*/
-.controller(
- 'OperationController', [
- '$scope', '$rootScope', '$routeParams', '$ngBootbox', 'Notification', 'Account', 'Operation',
- function($scope, $rootScope, $routeParams, $ngBootbox, Notification, Account, Operation) {
- // List of operations.
- $scope.operations = [];
+.controller('OperationController', [
+ '$scope', '$rootScope', '$routeParams', '$ngBootbox', 'Notification', 'Account', 'Operation',
+ function($scope, $rootScope, $routeParams, $ngBootbox, Notification, Account, Operation) {
+ // List of operations.
+ $scope.operations = [];
- /*
- * Add an empty operation.
- */
- $scope.add = function() {
- var operation = new Operation({
- account_id: $routeParams.accountId
- });
+ /*
+ * Add an empty operation.
+ */
+ $scope.add = function() {
+ var operation = new Operation({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ });
- $scope.operations.splice(0, 0, operation);
- };
+ $scope.operations.splice(0, 0, operation);
+ };
- /*
- * Load operations.
- */
- $scope.load = function(begin, end) {
- $scope.operations = Operation.query({
- account_id: $routeParams.accountId,
- begin: begin.format('YYYY-MM-DD'),
- end: end.format('YYYY-MM-DD')
- });
- };
+ /*
+ * Load operations.
+ */
+ $scope.load = function(begin, end) {
+ $scope.operations = Operation.query({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ account_id: $routeParams.accountId,
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ begin: begin.format('YYYY-MM-DD'),
+ end: end.format('YYYY-MM-DD')
+ });
+ };
- /*
- * Cancel edition.
- */
- $scope.cancelEdit = function(operation, rowform, $index) {
- if(!operation.id) {
- $scope.operations.splice($index, 1);
- } else {
- rowform.$cancel();
- }
- };
-
- /*
- * Toggle pointed indicator for an operation.
- */
- $scope.togglePointed = function(operation, rowform) {
- operation.pointed = !operation.pointed;
-
- // Save operation if not editing it.
- if(!rowform.$visible) {
- $scope.save(operation);
- }
- };
-
- /*
- * Toggle cancel indicator for an operation.
- */
- $scope.toggleCanceled = function(operation) {
- operation.canceled = !operation.canceled;
-
- $scope.save(operation);
- };
-
- /*
- * Save an operation and emit operationSavedEvent.
- */
- $scope.save = function($data, $index) {
- // Check if $data is already a resource.
- var operation;
-
- if($data.$save) {
- operation = $data;
- } else {
- operation = $scope.operations[$index];
- operation = angular.merge(operation, $data);
- }
-
- operation.confirmed = true;
-
- return operation.$save().then(function(data) {
- Notification.success('Operation #' + data.id + ' saved.');
-
- $scope.$emit('operationSavedEvent', data);
- });
- };
-
- /*
- * Delete an operation and emit operationDeletedEvent.
- */
- $scope.delete = function(operation, $index) {
- var id = operation.id;
-
- $ngBootbox.confirm(
- 'Voulez-vous supprimer l\'opération \\\'' + operation.label + '\\\' ?',
- function(result) {
- if(result) {
- operation.$delete().then(function() {
- Notification.success('Operation #' + id + ' deleted.');
-
- // Remove operation from array.
- $scope.operation.splice($index, 1);
-
- $scope.$emit('operationDeletedEvent', operation);
- });
- }
- }
- );
- };
-
- $scope.account = Account.get({
- id: $routeParams.accountId
- });
-
- /*
- * Reload operations on rangeSelectedEvent.
- */
- $rootScope.$on('rangeSelectedEvent', function(e, args) {
- $scope.load(args.begin, args.end);
- });
-}])
-
-.directive(
- 'operationFormDialog', function($ngBootbox) {
- return {
- restrict: 'A',
- scope: {
- operation: '=ngModel'
- },
- link: function(scope, element) {
- var title = 'Operation';
-
- if(scope.operation && scope.operation.id) {
- title = title + ' #' + scope.operation.id;
- }
-
- scope.form = {};
-
- element.on('click', function() {
- scope.data = {};
- angular.copy(scope.operation, scope.data);
-
- // Open dialog with form.
- $ngBootbox.customDialog({
- scope: scope,
- title: title,
- templateUrl: 'views/operation.form.tmpl.html',
- onEscape: true,
- buttons: {
- save: {
- label: 'Save',
- className: 'btn-success',
- callback: function() {
- // Validate form
- console.log(scope.form);
-
- // Save operation
- console.log(scope.operation);
-
- // TODO Alexis Lahouze 2016-05-24 Save operation, handle return.
- return false;
- }
- },
- cancel: {
- label: 'Cancel',
- className: 'btn-default',
- callback: true
- }
- }
- });
- });
+ /*
+ * Cancel edition.
+ */
+ $scope.cancelEdit = function(operation, rowform, $index) {
+ if (!operation.id) {
+ $scope.operations.splice($index, 1);
+ } else {
+ rowform.$cancel();
}
};
+
+ /*
+ * Toggle pointed indicator for an operation.
+ */
+ $scope.togglePointed = function(operation, rowform) {
+ operation.pointed = !operation.pointed;
+
+ // Save operation if not editing it.
+ if (!rowform.$visible) {
+ $scope.save(operation);
+ }
+ };
+
+ /*
+ * Toggle cancel indicator for an operation.
+ */
+ $scope.toggleCanceled = function(operation) {
+ operation.canceled = !operation.canceled;
+
+ $scope.save(operation);
+ };
+
+ /*
+ * Save an operation and emit operationSavedEvent.
+ */
+ $scope.save = function($data, $index) {
+ // Check if $data is already a resource.
+ var operation;
+
+ if ($data.$save) {
+ operation = $data;
+ } else {
+ operation = $scope.operations[$index];
+ operation = angular.merge(operation, $data);
+ }
+
+ operation.confirmed = true;
+
+ return operation.$save().then(function(data) {
+ Notification.success('Operation #' + data.id + ' saved.');
+
+ $scope.$emit('operationSavedEvent', data);
+ });
+ };
+
+ /*
+ * Delete an operation and emit operationDeletedEvent.
+ */
+ $scope.delete = function(operation, $index) {
+ var id = operation.id;
+
+ $ngBootbox.confirm(
+ 'Voulez-vous supprimer l\'opération \\\'' + operation.label + '\\\' ?',
+ function(result) {
+ if (result) {
+ operation.$delete().then(function() {
+ Notification.success('Operation #' + id + ' deleted.');
+
+ // Remove operation from array.
+ $scope.operation.splice($index, 1);
+
+ $scope.$emit('operationDeletedEvent', operation);
+ });
+ }
+ }
+ );
+ };
+
+ $scope.account = Account.get({
+ id: $routeParams.accountId
+ });
+
+ /*
+ * Reload operations on rangeSelectedEvent.
+ */
+ $rootScope.$on('rangeSelectedEvent', function(e, args) {
+ $scope.load(args.begin, args.end);
+ });
+ }
+])
+
+.directive('operationFormDialog', function($ngBootbox) {
+ return {
+ restrict: 'A',
+ scope: {
+ operation: '=ngModel'
+ },
+ link: function(scope, element) {
+ var title = 'Operation';
+
+ if (scope.operation && scope.operation.id) {
+ title = title + ' #' + scope.operation.id;
+ }
+
+ scope.form = {};
+
+ element.on('click', function() {
+ scope.data = {};
+ angular.copy(scope.operation, scope.data);
+
+ // Open dialog with form.
+ $ngBootbox.customDialog({
+ scope: scope,
+ title: title,
+ templateUrl: 'views/operation.form.tmpl.html',
+ onEscape: true,
+ buttons: {
+ save: {
+ label: 'Save',
+ className: 'btn-success',
+ callback: function() {
+ // Validate form
+ console.log(scope.form);
+
+ // Save operation
+ console.log(scope.operation);
+
+ // TODO Alexis Lahouze 2016-05-24 Save operation, handle return.
+ return false;
+ }
+ },
+ cancel: {
+ label: 'Cancel',
+ className: 'btn-default',
+ callback: true
+ }
+ }
+ });
+ });
+ }
+ };
});
diff --git a/accountant-ui/js/scheduler.js b/accountant-ui/js/scheduler.js
index 75aed46..03b49e7 100644
--- a/accountant-ui/js/scheduler.js
+++ b/accountant-ui/js/scheduler.js
@@ -1,3 +1,4 @@
+// vim: set tw=80 ts=4 sw=4 sts=4:
/*
This file is part of Accountant.
@@ -14,7 +15,6 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see .
*/
-// vim: set tw=80 ts=2 sw=2 sts=2:
'use strict';
angular.module('accountant.scheduler', [
@@ -38,84 +38,88 @@ angular.module('accountant.scheduler', [
);
}])
-.controller(
- 'SchedulerController', [
- '$scope', '$rootScope', '$routeParams', '$ngBootbox', 'Notification', 'ScheduledOperation',
- function($scope, $rootScope, $routeParams, $ngBootbox, Notification, ScheduledOperation) {
- // Operation store.
- $scope.operations = [];
+.controller('SchedulerController', [
+ '$scope', '$rootScope', '$routeParams', '$ngBootbox', 'Notification', 'ScheduledOperation',
+ function($scope, $rootScope, $routeParams, $ngBootbox, Notification, ScheduledOperation) {
+ // Operation store.
+ $scope.operations = [];
- /*
- * Add a new operation at the beginning of th array.
- */
- $scope.add = function() {
- var operation = new ScheduledOperation({
- account_id: $routeParams.accountId
- });
-
- // Insert new operation at the beginning of the array.
- $scope.operations.splice(0, 0, operation);
- };
-
- /*
- * Load operations.
- */
- $scope.load = function() {
- $scope.operations = ScheduledOperation.query({
- account_id: $routeParams.accountId
- });
- };
-
- /*
- * Save operation.
- */
- $scope.save = function($data, $index) {
- var operation;
-
- if($data.$save) {
- operation = $data;
- } else {
- operation = $scope.operations[$index];
- operation = angular.merge(operation, $data);
- }
-
- return operation.$save().then(function(data) {
- Notification.success('Operation #' + data.id + ' saved.');
- });
- };
-
- /*
- * Cancel operation edition. Delete if new.
- */
- $scope.cancelEdit = function(operation, rowform, $index) {
- if(!operation.id) {
- $scope.operations.splice($index, 1);
- } else {
- rowform.$cancel();
- }
- };
-
- /*
- * Delete operation.
- */
- $scope.delete = function(operation, $index) {
- var id = operation.id;
-
- $ngBootbox.confirm(
- 'Voulez-vous supprimer l\'operation planifiée \\\'' + operation.label + '\\\' ?',
- function(result) {
- if(result) {
- operation.$delete().then(function() {
- Notification.success('Operation #' + id + ' deleted.');
-
- // Remove account from array.
- $scope.operations.splice($index, 1);
+ /*
+ * Add a new operation at the beginning of th array.
+ */
+ $scope.add = function() {
+ var operation = new ScheduledOperation({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
});
- }
- }
- );
- };
- // Load operations on controller initialization.
- $scope.load();
-}]);
+ // Insert new operation at the beginning of the array.
+ $scope.operations.splice(0, 0, operation);
+ };
+
+ /*
+ * Load operations.
+ */
+ $scope.load = function() {
+ $scope.operations = ScheduledOperation.query({
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ account_id: $routeParams.accountId
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ });
+ };
+
+ /*
+ * Save operation.
+ */
+ $scope.save = function($data, $index) {
+ var operation;
+
+ if ($data.$save) {
+ operation = $data;
+ } else {
+ operation = $scope.operations[$index];
+ operation = angular.merge(operation, $data);
+ }
+
+ return operation.$save().then(function(data) {
+ Notification.success('Operation #' + data.id + ' saved.');
+ });
+ };
+
+ /*
+ * Cancel operation edition. Delete if new.
+ */
+ $scope.cancelEdit = function(operation, rowform, $index) {
+ if (!operation.id) {
+ $scope.operations.splice($index, 1);
+ } else {
+ rowform.$cancel();
+ }
+ };
+
+ /*
+ * Delete operation.
+ */
+ $scope.delete = function(operation, $index) {
+ var id = operation.id;
+
+ $ngBootbox.confirm(
+ 'Voulez-vous supprimer l\'operation planifiée \\\'' + operation.label + '\\\' ?',
+ function(result) {
+ if (result) {
+ operation.$delete().then(function() {
+ Notification.success('Operation #' + id + ' deleted.');
+
+ // Remove account from array.
+ $scope.operations.splice($index, 1);
+ });
+ }
+ }
+ );
+ };
+
+ // Load operations on controller initialization.
+ $scope.load();
+ }
+]);
diff --git a/grunt-config/jscs.js b/grunt-config/jscs.js
index 403e9b4..35961e9 100644
--- a/grunt-config/jscs.js
+++ b/grunt-config/jscs.js
@@ -1,7 +1,6 @@
module.exports = {
options: {
- config: '.jscsrc',
- verbose: true
+ config: '.jscsrc'
},
frontend_js: [
'<%= accountant.frontend.src %>/js/*.js'