Improve entries app using resources and events.
This commit is contained in:
parent
714cd28742
commit
38e5154536
@ -98,7 +98,7 @@ class EntryResource(Resource):
|
||||
|
||||
@session_aware
|
||||
@marshal_with_field(Object(resource_fields))
|
||||
def put(self, entry_id, session):
|
||||
def post(self, entry_id, session):
|
||||
kwargs = parser.parse_args()
|
||||
|
||||
assert (id not in kwargs or kwargs.id is None
|
||||
|
@ -14,13 +14,29 @@
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
accountantApp.controller(
|
||||
"EntryController", function($scope, $http, $rootScope, $filter) {
|
||||
accountantApp
|
||||
|
||||
.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
|
||||
$scope.entries = [];
|
||||
|
||||
$scope.categories = [];
|
||||
$scope.chartValues = [];
|
||||
$scope.pieChartValues = [];
|
||||
|
||||
$scope.selectedItem = null;
|
||||
|
||||
$scope.account = null;
|
||||
@ -28,9 +44,11 @@ accountantApp.controller(
|
||||
// Placeholder for saved value to cancel entry edition
|
||||
$scope.savedItem = null;
|
||||
|
||||
// Range for entries.
|
||||
$scope.begin = moment.utc().startOf('month');
|
||||
$scope.end = moment.utc().endOf('month');
|
||||
// Function to reset the new entry.
|
||||
$scope.resetNewEntry = function() {
|
||||
// The new entry.
|
||||
$scope.newEntry = new Entries({});
|
||||
};
|
||||
|
||||
$scope.setExtremes = function(e) {
|
||||
begin = moment.utc(e.min);
|
||||
@ -58,6 +76,9 @@ accountantApp.controller(
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: -90
|
||||
},
|
||||
series: {
|
||||
allowPointSelect: 0
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
@ -183,6 +204,8 @@ accountantApp.controller(
|
||||
|
||||
// Load categories, mainly to populate the pie chart.
|
||||
$scope.loadCategories = function() {
|
||||
$scope.categoriesChartConfig.loading = true;
|
||||
|
||||
$http.get("/api/categories", {
|
||||
params: {
|
||||
account: $scope.account.id,
|
||||
@ -214,14 +237,14 @@ accountantApp.controller(
|
||||
// Note: expenses and revenues must be in the same order than in series[0].
|
||||
config.series[1].data = revenues.concat(expenses);
|
||||
|
||||
$scope.categoriesChartConfig.loaded = true;
|
||||
$scope.categoriesChartConfig.loading = false;
|
||||
|
||||
$scope.loadSolds();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.loadSolds = function() {
|
||||
$scope.soldChartConfig.loaded = true;
|
||||
$scope.soldChartConfig.loading = true;
|
||||
|
||||
$http.get("/api/solds", {
|
||||
params: {
|
||||
@ -239,10 +262,15 @@ accountantApp.controller(
|
||||
]);
|
||||
});
|
||||
|
||||
$scope.soldChartConfig.loading = false;
|
||||
|
||||
$scope.loadEntries();
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Hook on account selected event to display account status.
|
||||
*/
|
||||
$rootScope.$on("accountSelectedEvent", function(event, args) {
|
||||
$scope.account = args.account;
|
||||
|
||||
@ -253,43 +281,45 @@ accountantApp.controller(
|
||||
$scope.getAccountStatus();
|
||||
});
|
||||
|
||||
$rootScope.$on("entriesLoadedEvent", function(event, args) {
|
||||
//$scope.loadCategories();
|
||||
});
|
||||
|
||||
$scope.getAccountStatus = function() {
|
||||
$scope.categoriesChartConfig.loaded = true;
|
||||
$scope.categoriesChartConfig.loading = true;
|
||||
|
||||
$http.get("/api/accounts/" + $scope.account.id, {
|
||||
params: {
|
||||
begin: $scope.begin.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 config = $scope.categoriesChartConfig;
|
||||
|
||||
// Update pie chart subtitle with Balance.
|
||||
config.subtitle = {
|
||||
text: "Balance: " + status.balance
|
||||
text: "Balance: " + account.balance
|
||||
};
|
||||
|
||||
config.series[0].data = [{
|
||||
name: "Revenues",
|
||||
y: status.revenues,
|
||||
y: account.revenues,
|
||||
color: colors[2]
|
||||
}, {
|
||||
name: "Expenses",
|
||||
y: -status.expenses,
|
||||
y: -account.expenses,
|
||||
color: colors[3],
|
||||
}];
|
||||
|
||||
$scope.soldChartConfig.yAxis.plotLines[1].value = status.authorized_overdraft;
|
||||
|
||||
$scope.loadCategories();
|
||||
$scope.soldChartConfig.yAxis.plotLines[1].value = account.authorized_overdraft;
|
||||
});
|
||||
};
|
||||
|
||||
// Function to load entries from server for a specific account and month.
|
||||
$scope.loadEntries = function() {
|
||||
@ -297,49 +327,13 @@ accountantApp.controller(
|
||||
$scope.selectedItem = null;
|
||||
$scope.savedItem = null;
|
||||
|
||||
if(!$scope.entriesLoading) {
|
||||
$scope.entriesLoading = true;
|
||||
|
||||
$http.get("/api/entries", {
|
||||
params: {
|
||||
$scope.entries = Entries.query({
|
||||
account: $scope.account.id,
|
||||
begin: $scope.begin.format('YYYY-MM-DD'),
|
||||
end: $scope.end.format('YYYY-MM-DD')
|
||||
}
|
||||
}).success(function(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});
|
||||
}, function(data) {
|
||||
$scope.$emit("entriesLoadedEvent", {entries: data});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 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.
|
||||
@ -380,21 +374,18 @@ accountantApp.controller(
|
||||
}
|
||||
|
||||
// Save current entry values.
|
||||
if(!entry.id) {
|
||||
$scope.savedItem = angular.copy(entry);
|
||||
$scope.selectedItem = entry;
|
||||
}
|
||||
|
||||
// Enter edit state.
|
||||
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.
|
||||
$scope.isEditing = function(entry) {
|
||||
return entry.state === 'edit' || entry.state === 'new';
|
||||
return entry.state === 'edit';
|
||||
};
|
||||
|
||||
// Returns true if the entry is in displaying state.
|
||||
@ -407,38 +398,10 @@ accountantApp.controller(
|
||||
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.
|
||||
$scope.cancelEditEntry = function(entry) {
|
||||
if ($scope.savedItem === null) {
|
||||
// We are cancelling the new entry, just reset it.
|
||||
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';
|
||||
if (entry.id) {
|
||||
entry.$get();
|
||||
} else {
|
||||
// Reset selected item fields to saved item ones.
|
||||
entry.id = $scope.savedItem.id; // id should not change, but just in case...
|
||||
@ -462,48 +425,55 @@ accountantApp.controller(
|
||||
|
||||
// Points an entry.
|
||||
$scope.pointEntry = function(entry) {
|
||||
if(entry.pointed) {
|
||||
entry.pointed = false;
|
||||
} else {
|
||||
entry.pointed = true;
|
||||
}
|
||||
entry.pointed = !entry.pointed;
|
||||
|
||||
// Save the entry if not new.
|
||||
if(!$scope.isNew(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) {
|
||||
// Affects the account ID if not (should never happen)
|
||||
|
||||
if(!entry.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
|
||||
$http.put(url, angular.toJson(entry)).success(function(data) {
|
||||
$.pnotify({
|
||||
type: "success",
|
||||
title: "Save",
|
||||
text: data
|
||||
});
|
||||
|
||||
// $scope.savedItem = null;
|
||||
|
||||
entry.$save(function(data) {
|
||||
// Send the "entry saved" event.
|
||||
$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.removingEntry = entry;
|
||||
$("#remove_entry").modal({
|
||||
@ -520,13 +490,7 @@ accountantApp.controller(
|
||||
$scope.confirmRemoveEntry = function() {
|
||||
// Cancel current editing.
|
||||
if ($scope.removingEntry) {
|
||||
$http.delete("/api/entries/" + $scope.removingEntry.id).success(function (result) {
|
||||
$.pnotify({
|
||||
type: "success",
|
||||
title: "Delete",
|
||||
text: result
|
||||
});
|
||||
|
||||
$scope.removingEntry.$delete(function (result) {
|
||||
// Send the "entry removed" event.
|
||||
$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) {
|
||||
// Close the modal dialog
|
||||
if(modalScope && modalScope.dismiss) {
|
||||
modalScope.dismiss();
|
||||
}
|
||||
};
|
||||
});
|
||||
}]);
|
||||
|
Loading…
Reference in New Issue
Block a user