Improve entries app using resources and events.

This commit is contained in:
Alexis Lahouze 2015-07-10 11:48:53 +02:00
parent 714cd28742
commit 38e5154536
2 changed files with 125 additions and 153 deletions

View File

@ -98,7 +98,7 @@ class EntryResource(Resource):
@session_aware @session_aware
@marshal_with_field(Object(resource_fields)) @marshal_with_field(Object(resource_fields))
def put(self, entry_id, session): def post(self, entry_id, session):
kwargs = parser.parse_args() kwargs = parser.parse_args()
assert (id not in kwargs or kwargs.id is None assert (id not in kwargs or kwargs.id is None

View File

@ -14,13 +14,29 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
*/ */
accountantApp.controller( accountantApp
"EntryController", function($scope, $http, $rootScope, $filter) {
.factory("Entries", [ "$resource", function($resource) {
return $resource(
"/api/entries/:id", {
id: "@id"
}
);
}])
.controller(
"EntryController", [
"$scope", "$http", "$rootScope", "$filter", "Entries",
function($scope, $http, $rootScope, $filter, Entries) {
// Range for entries.
$scope.begin = moment.utc().startOf('month');
$scope.end = moment.utc().endOf('month');
// Entry store and selection // Entry store and selection
$scope.entries = []; $scope.entries = [];
$scope.categories = []; $scope.categories = [];
$scope.chartValues = [];
$scope.pieChartValues = [];
$scope.selectedItem = null; $scope.selectedItem = null;
$scope.account = null; $scope.account = null;
@ -28,9 +44,11 @@ accountantApp.controller(
// Placeholder for saved value to cancel entry edition // Placeholder for saved value to cancel entry edition
$scope.savedItem = null; $scope.savedItem = null;
// Range for entries. // Function to reset the new entry.
$scope.begin = moment.utc().startOf('month'); $scope.resetNewEntry = function() {
$scope.end = moment.utc().endOf('month'); // The new entry.
$scope.newEntry = new Entries({});
};
$scope.setExtremes = function(e) { $scope.setExtremes = function(e) {
begin = moment.utc(e.min); begin = moment.utc(e.min);
@ -58,6 +76,9 @@ accountantApp.controller(
plotOptions: { plotOptions: {
pie: { pie: {
startAngle: -90 startAngle: -90
},
series: {
allowPointSelect: 0
} }
}, },
tooltip: { tooltip: {
@ -183,6 +204,8 @@ accountantApp.controller(
// Load categories, mainly to populate the pie chart. // Load categories, mainly to populate the pie chart.
$scope.loadCategories = function() { $scope.loadCategories = function() {
$scope.categoriesChartConfig.loading = true;
$http.get("/api/categories", { $http.get("/api/categories", {
params: { params: {
account: $scope.account.id, account: $scope.account.id,
@ -214,14 +237,14 @@ accountantApp.controller(
// Note: expenses and revenues must be in the same order than in series[0]. // Note: expenses and revenues must be in the same order than in series[0].
config.series[1].data = revenues.concat(expenses); config.series[1].data = revenues.concat(expenses);
$scope.categoriesChartConfig.loaded = true; $scope.categoriesChartConfig.loading = false;
$scope.loadSolds(); $scope.loadSolds();
}); });
}; };
$scope.loadSolds = function() { $scope.loadSolds = function() {
$scope.soldChartConfig.loaded = true; $scope.soldChartConfig.loading = true;
$http.get("/api/solds", { $http.get("/api/solds", {
params: { params: {
@ -239,10 +262,15 @@ accountantApp.controller(
]); ]);
}); });
$scope.soldChartConfig.loading = false;
$scope.loadEntries(); $scope.loadEntries();
}); });
}; };
/*
* Hook on account selected event to display account status.
*/
$rootScope.$on("accountSelectedEvent", function(event, args) { $rootScope.$on("accountSelectedEvent", function(event, args) {
$scope.account = args.account; $scope.account = args.account;
@ -253,43 +281,45 @@ accountantApp.controller(
$scope.getAccountStatus(); $scope.getAccountStatus();
}); });
$rootScope.$on("entriesLoadedEvent", function(event, args) {
//$scope.loadCategories();
});
$scope.getAccountStatus = function() { $scope.getAccountStatus = function() {
$scope.categoriesChartConfig.loaded = true; $scope.categoriesChartConfig.loading = true;
$http.get("/api/accounts/" + $scope.account.id, { $http.get("/api/accounts/" + $scope.account.id, {
params: { params: {
begin: $scope.begin.format('YYYY-MM-DD'), begin: $scope.begin.format('YYYY-MM-DD'),
end: $scope.end.format('YYYY-MM-DD') end: $scope.end.format('YYYY-MM-DD')
} }
}).success(function(status) { }).success(function(account) {
$scope.categoriesChartConfig.loading = false;
$scope.$emit("accountLoadedEvent", account);
});
};
$rootScope.$on("accountLoadedEvent", $scope.loadCategories);
$rootScope.$on("accountLoadedEvent", function(e, account) {
var colors = Highcharts.getOptions().colors; var colors = Highcharts.getOptions().colors;
var config = $scope.categoriesChartConfig; var config = $scope.categoriesChartConfig;
// Update pie chart subtitle with Balance. // Update pie chart subtitle with Balance.
config.subtitle = { config.subtitle = {
text: "Balance: " + status.balance text: "Balance: " + account.balance
}; };
config.series[0].data = [{ config.series[0].data = [{
name: "Revenues", name: "Revenues",
y: status.revenues, y: account.revenues,
color: colors[2] color: colors[2]
}, { }, {
name: "Expenses", name: "Expenses",
y: -status.expenses, y: -account.expenses,
color: colors[3], color: colors[3],
}]; }];
$scope.soldChartConfig.yAxis.plotLines[1].value = status.authorized_overdraft; $scope.soldChartConfig.yAxis.plotLines[1].value = account.authorized_overdraft;
$scope.loadCategories();
}); });
};
// Function to load entries from server for a specific account and month. // Function to load entries from server for a specific account and month.
$scope.loadEntries = function() { $scope.loadEntries = function() {
@ -297,49 +327,13 @@ accountantApp.controller(
$scope.selectedItem = null; $scope.selectedItem = null;
$scope.savedItem = null; $scope.savedItem = null;
if(!$scope.entriesLoading) { $scope.entries = Entries.query({
$scope.entriesLoading = true;
$http.get("/api/entries", {
params: {
account: $scope.account.id, account: $scope.account.id,
begin: $scope.begin.format('YYYY-MM-DD'), begin: $scope.begin.format('YYYY-MM-DD'),
end: $scope.end.format('YYYY-MM-DD') end: $scope.end.format('YYYY-MM-DD')
} }, function(data) {
}).success(function(data) { $scope.$emit("entriesLoadedEvent", {entries: data});
var entries = [{
id: null,
pointed: false,
operation_date: null,
label: null,
value: null,
sold: null,
pointedsold: null,
category: null,
account_id: null,
state: 'new',
canceled: false,
scheduled_operation_id: null
}];
if(data) {
entries = entries.concat(angular.fromJson(data));
}
$scope.entries = entries;
$scope.entriesLoading = false;
$scope.$emit("entriesLoadedEvent", {entries: entries});
}); });
}
};
// Returns the CSS class for a pointed entry.
$scope.pointedEntryClass = function(entry) {
if(entry.pointed) {
return "active";
}
}; };
// Returns the CSS class for an entry row. // Returns the CSS class for an entry row.
@ -380,21 +374,18 @@ accountantApp.controller(
} }
// Save current entry values. // Save current entry values.
if(!entry.id) {
$scope.savedItem = angular.copy(entry); $scope.savedItem = angular.copy(entry);
$scope.selectedItem = entry; $scope.selectedItem = entry;
}
// Enter edit state. // Enter edit state.
entry.state='edit'; entry.state='edit';
}; };
// Returns true if the entry is a new one.
$scope.isNew = function(entry) {
return !$scope.isSaved(entry) && (entry.state === 'edit' || entry.state === 'new');
};
// Returns true if the entry is in editing state. // Returns true if the entry is in editing state.
$scope.isEditing = function(entry) { $scope.isEditing = function(entry) {
return entry.state === 'edit' || entry.state === 'new'; return entry.state === 'edit';
}; };
// Returns true if the entry is in displaying state. // Returns true if the entry is in displaying state.
@ -407,38 +398,10 @@ accountantApp.controller(
return entry.id !== null; return entry.id !== null;
}; };
$scope.iconSaveClass = function(entry) {
if(!$scope.isSaved(entry)) {
return "fa fa-plus";
} else if ($scope.isEditing(entry)) {
return "fa fa-floppy-o";
}
};
$scope.iconCancelClass = function(entry) {
if($scope.isNew(entry)) {
return "fa fa-times";
} else if ($scope.isEditing(entry)) {
return "fa fa-ban";
}
};
// Cancel current editing entry or clears field if a new one. // Cancel current editing entry or clears field if a new one.
$scope.cancelEditEntry = function(entry) { $scope.cancelEditEntry = function(entry) {
if ($scope.savedItem === null) { if (entry.id) {
// We are cancelling the new entry, just reset it. entry.$get();
entry.id = null; // id should not change, but just in case...
entry.pointed = false;
entry.operation_date = null;
entry.label = null;
entry.value = null;
entry.account_id = $scope.account.id; // account_id should not change, but just in case...
entry.category = null;
entry.canceled = false;
entry.scheduled_operation_id = null;
// Reset state to new.
entry.state = 'new';
} else { } else {
// Reset selected item fields to saved item ones. // Reset selected item fields to saved item ones.
entry.id = $scope.savedItem.id; // id should not change, but just in case... entry.id = $scope.savedItem.id; // id should not change, but just in case...
@ -462,48 +425,55 @@ accountantApp.controller(
// Points an entry. // Points an entry.
$scope.pointEntry = function(entry) { $scope.pointEntry = function(entry) {
if(entry.pointed) { entry.pointed = !entry.pointed;
entry.pointed = false;
} else {
entry.pointed = true;
}
// Save the entry if not new.
if(!$scope.isNew(entry)) {
$scope.saveEntry(entry); $scope.saveEntry(entry);
}
}; };
// Saves an entry. // Create an new entry.
$scope.createEntry = function(entry) {
entry.account_id = $scope.account.id;
// Ajax call to create an entry
$scope.newEntry.$save(function(data) {
$scope.resetNewEntry();
// Send the "entry saved" event.
$scope.$emit("entryCreatedEvent", entry);
});
};
$rootScope.$on("entryCreatedEvent", function(e, entry) {
new PNotify({
type: "success",
title: "Save",
text: "Entry #" + entry.id + " created."
});
});
// Saves an existing entry.
$scope.saveEntry = function(entry) { $scope.saveEntry = function(entry) {
// Affects the account ID if not (should never happen)
if(!entry.account_id) { if(!entry.account_id) {
entry.account_id = $scope.account.id; entry.account_id = $scope.account.id;
} }
// Prepare the Ajax call to save the entry.
var type;
var url = "/api/entries";
if($scope.isSaved(entry)) {
url += "/" + entry.id;
}
// Ajax call to save an entry // Ajax call to save an entry
$http.put(url, angular.toJson(entry)).success(function(data) { entry.$save(function(data) {
$.pnotify({
type: "success",
title: "Save",
text: data
});
// $scope.savedItem = null;
// Send the "entry saved" event. // Send the "entry saved" event.
$scope.$emit("entrySavedEvent", entry); $scope.$emit("entrySavedEvent", entry);
}); });
}; };
$rootScope.$on("entrySavedEvent", function(e, entry) {
new PNotify({
type: "success",
title: "Save",
text: "Entry #" + entry.id + " saved."
});
});
$scope.removeEntry = function(entry) { $scope.removeEntry = function(entry) {
$scope.removingEntry = entry; $scope.removingEntry = entry;
$("#remove_entry").modal({ $("#remove_entry").modal({
@ -520,13 +490,7 @@ accountantApp.controller(
$scope.confirmRemoveEntry = function() { $scope.confirmRemoveEntry = function() {
// Cancel current editing. // Cancel current editing.
if ($scope.removingEntry) { if ($scope.removingEntry) {
$http.delete("/api/entries/" + $scope.removingEntry.id).success(function (result) { $scope.removingEntry.$delete(function (result) {
$.pnotify({
type: "success",
title: "Delete",
text: result
});
// Send the "entry removed" event. // Send the "entry removed" event.
$scope.$emit("entryRemovedEvent", $scope.removingEntry); $scope.$emit("entryRemovedEvent", $scope.removingEntry);
@ -535,10 +499,18 @@ accountantApp.controller(
} }
}; };
$rootScope.$on("entryRemovedEvent", function(e, entry) {
new PNotify({
type: "success",
title: "Delete",
text: "Entry #" + entry.id + " deleted."
});
});
$scope.closeModal = function(modalScope) { $scope.closeModal = function(modalScope) {
// Close the modal dialog // Close the modal dialog
if(modalScope && modalScope.dismiss) { if(modalScope && modalScope.dismiss) {
modalScope.dismiss(); modalScope.dismiss();
} }
}; };
}); }]);