Explorar el Código

Feature: add account entries listing

febbweiss hace 10 años
padre
commit
4080080cb3

+ 172 - 0
public/account/account.controller.js

@@ -0,0 +1,172 @@
+(function(){
+    'use strict';
+    
+    angular
+        .module('cloudbudget')
+        .filter('category', CategoryFilter)
+        .filter('sub_category', SubcategoryFilter)
+        .controller('AccountController', AccountController);
+        
+    function CategoryFilter() {
+        return function(input, categories) {
+              if( !input ) {
+                  return '';
+              }
+            var category = categories.filter(function(elt, idx) {
+                    return elt._id === input;
+                });
+            if( category.length > 0 ) {
+                return category[0].label;
+            } 
+            return '';
+          };
+    }
+    
+    function SubcategoryFilter() {
+        return function(input, category_id, categories) {
+            if( !input || !category_id) {
+                return '';
+            }
+            
+            var category = categories.filter(function(elt, idx) {
+                return elt._id === category_id;
+            })[0];
+            
+            if( !category ) {
+                return ''; 
+            }
+
+            var res = category.sub_categories.filter( function(elt, idx) {
+                            return elt._id === input;
+                        });        
+            if( res.length === 1 ) {
+                return res[0].label;
+            } else {
+                return '';
+            }
+          };
+    }
+        
+    AccountController.$inject = ['$scope', '$location', '$routeParams', 'FlashService', 'AccountService'];
+    
+    function AccountController($scope, $location, $routeParams, FlashService, AccountService) {
+        var vm = this;
+        
+        $scope.calendar = {
+            opened: {},
+            dateFormat: 'dd/MM/yyyy',
+            dateOptions: {},
+            open: function($event, which) {
+                $event.preventDefault();
+                $event.stopPropagation();
+                $scope.calendar.opened[which] = true;
+            } 
+        };
+
+        vm.dataLoading = false;
+        vm.entries = [];
+        vm.categories = [];
+        vm.sub_categories = [];
+        vm.account = undefined;
+        vm.create = create;
+        vm.drop = drop;
+        vm.edit = edit;
+        vm.updateSubCategory = updateSubCategory;
+        vm.updateSubCategoryEditForm = updateSubCategoryEditForm;
+        vm.disabledSubCategories = false;
+        vm.edit_sub_categories = [];
+        
+        (function init() {
+            vm.dataLoading = true;
+            AccountService.details($routeParams.account_id)
+                .then(function(response) {
+                    if( response.success ) {
+                        vm.account = response.account;
+                        vm.categories = angular.copy(vm.account.categories);
+                        vm.categories.unshift({_id: '', label: ''});
+                    } else {
+                        FlashService.error(response.message);
+                    }
+                    vm.dataLoading = false;
+                });
+            AccountService.list($routeParams.account_id)
+                .then(function(response) {
+                   if( response.success ) {
+                       vm.entries = response.data.entries;
+                   } else {
+                       FlashService.error(response.message);
+                   }
+                });
+        })();
+        
+        function create() {
+            vm.dataLoading = true;
+            AccountService.create(vm.account, vm.entry)
+                .then( function(response) {
+                    if( response.success) {
+                        vm.entries = response.data.entries;
+                    } else {
+                        FlashService.error(response.message);
+                    }
+                    
+                    vm.dataLoading = false;
+                });
+            vm.entry = angular.copy({});
+            $scope.form.$setPristine();
+        };
+        
+        function drop(entry) {
+            vm.dataLoading = true;
+            AccountService.drop(vm.account, entry)
+                .then(function(response) {
+                    if( response.success ) {
+                       vm.entries = response.data.entries;
+                    } else {
+                        FlashService.error( response.message );
+                    }
+                    vm.dataLoading = false;
+                });
+        };
+        
+        function edit(altered, origin) {
+            vm.dataLoading = true;
+            return AccountService.edit(vm.account, origin._id, altered)
+                .then( function(response) {
+                    vm.dataLoading = false;
+                    if( response.success ) {
+                        var index = vm.entries.map(function (item) {
+                                return item._id;
+                            }).indexOf(origin._id);
+                        vm.entries[index] = response.data.entries[index];
+                    } else {
+                        var index = vm.entries.map(function (item) {
+                                return item._id;
+                            }).indexOf(origin._id);
+                        vm.entries[index] = origin;
+                        FlashService.error( response.message );
+                        return false;
+                    }
+                })
+        };
+        
+        function updateSubCategory() {
+            vm.sub_categories = getSubCategories(vm.entry.category);
+        };
+        
+        function updateSubCategoryEditForm(category_id) {
+            vm.edit_sub_categories = getSubCategories(category_id);
+            vm.disabledSubCategories = !vm.edit_sub_categories || vm.edit_sub_categories.length === 0;
+        };
+        
+        function getSubCategories(category_id) {
+            var categories = vm.categories.filter(function(elt, idx) {
+                return elt._id === category_id;
+            });
+            if( categories.length === 0 ) {
+                return [];
+            } else {
+                return categories[0].sub_categories;
+            }
+        }
+    }
+})();

+ 96 - 0
public/account/account.view.html

@@ -0,0 +1,96 @@
+<div class="container-fluid div-striped">
+    <div class="row">
+        <form name="form" ng-submit="vm.create()" role="form">
+            <div class="col-sm-2">
+                <div class="form-group" ng-class="{'has-error': form.date.$dirty && form.date.$error.required}">
+                    <input  type="date" class="form-control input-sm" name="date" id="date" 
+                            ng-model="vm.entry.date" 
+                            placeholder="Date" 
+                            required/>
+                    <span ng-show="form.date.$dirty && form.date.$error.required" class="help-block">Date is required</span>
+                </div>
+            </div>
+            <div class="col-sm-2">
+                <div class="form-group">
+                    <select name="category" class="form-control input-sm" ng-change="vm.updateSubCategory()" ng-model="vm.entry.category">
+                        <option ng-repeat="category in vm.categories" value="{{category._id}}">{{category.label}}</option>
+                    </select>
+                </div>
+            </div>
+            <div class="col-sm-2">
+                <div class="form-group">
+                    <select name="sub_category" class="form-control input-sm" ng-hide="!vm.entry.category || vm.sub_categories.length === 0" ng-model="vm.entry.sub_category">
+                        <option value=""></option>
+                        <option ng-repeat="sub_category in vm.sub_categories" value="{{sub_category._id}}">{{sub_category.label}}</option>
+                    </select>
+                </div>
+            </div>
+            <div class="col-sm-2">
+                <div class="form-group">
+                    <input name="label" id="label" class="form-control input-sm" ng-model="vm.entry.label" placeholder="Label" />                                    
+                </div>
+            </div>
+            <div class="col-sm-2">
+                <div class="form-group" ng-class="{'has-error': form.amount.$dirty && form.amout.$error.required}">
+                    <input type="number" name="amount" id="amount" class="form-control input-sm" ng-model="vm.entry.amount" placeholder="Amount" required/>                                    
+                    <span ng-show="form.amount.$dirty && form.amount.$error.required" class="help-block">Amount is required</span>
+                </div>
+            </div>
+            <div class="col-sm-2">
+                <button type="submit" class="btn btn-primary" ng-disabled="form.$invalid || vm.dataLoading">
+                    <i class="fa fa-fw fa-floppy-o"></i>
+                </button>
+                <img ng-if="vm.dataLoading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" />
+            </div>
+        </form>
+    </div>
+    <div class="row" ng-repeat="entry in vm.entries">
+        <div class="col-sm-2 small">
+            <span   e-form="editEntryForm" e-name="date" 
+                    editable-date="entry.date"
+                    e-required>{{entry.date | date: "dd/MM/yyyy" }}</span>
+        </div>
+        <div class="col-sm-2 small">
+            <span   e-form="editEntryForm" 
+                    e-name="category" 
+                    editable-select="entry.category" 
+                    e-ng-change="vm.updateSubCategoryEditForm($data)" 
+                    e-ng-options="category._id as category.label for category in vm.categories">{{entry.category | category:vm.categories}}</span>
+        </div>
+        <div class="col-sm-2 small">
+            <span   e-form="editEntryForm" 
+                    e-name="sub_category" 
+                    editable-select="entry.sub_category" 
+                    e-ng-options="category._id as category.label for category in vm.edit_sub_categories"
+                    e-ng-hide="vm.disabledSubCategories">{{entry.sub_category | sub_category:entry.category:vm.categories}}</span>
+        </div>
+        <div class="col-sm-2 small">
+            <span e-form="editEntryForm" e-name="label" editable-text="entry.label">{{entry.label}}</span>
+        </div>
+        <div class="col-sm-2 text-right small">
+            <span   e-form="editEntryForm" 
+                    e-name="amount" 
+                    editable-number="entry.amount" 
+                    ng-class="{'text-danger': entry.type === 'BILL'}" 
+                    e-required>
+                {{entry.amount | currency }}
+            </span>
+        </div>
+        <div class="col-sm-2">
+            <form editable-form name="editEntryForm" onbeforesave="vm.edit($data, entry)" ng-show="editEntryForm.$visible" shown="inserted == entry">
+                <button type="submit" ng-disabled="editEntryForm.$invalid || editEntryForm.$waiting" title="Edit" class="btn btn-success">
+                    <i class="fa fa-fw fa-floppy-o"></i>
+                </button>
+                <button type="button" ng-disabled="editEntryForm.$waiting" title="Cancel" ng-click="editEntryForm.$cancel()" class="btn btn-default">
+                    <i class="fa fa-fw fa-ban"></i>
+                </button>
+                <a class="btn btn-danger" title="Delete" ng-disabled="editEntryForm.$waiting" ng-click="vm.drop(entry)">
+                    <i class="fa fa-fw fa-trash"></i>
+                </a>
+            </form>
+            <a class="btn btn-success" ng-click="editEntryForm.$show()" ng-show="!editEntryForm.$visible">
+                <i class="fa fa-fw fa-pencil"></i>
+            </a>
+        </div>
+    </div>
+</div>

+ 6 - 0
public/css/cloudbudget.css

@@ -0,0 +1,6 @@
+div.div-striped div.row:nth-of-type(odd) {
+    background: #e0e0e0;
+}
+div.div-striped div.row:nth-of-type(even) {
+    background: #FFFFFF;
+}

+ 58 - 0
public/js/services/account.service.js

@@ -0,0 +1,58 @@
+(function() {
+    'use strict';
+    
+    angular
+        .module('cloudbudget')
+        .factory('AccountService', AccountService);
+        
+    AccountService.$inject =['$http', 'apiRoutes'];
+    
+    function AccountService($http, apiRoute) {
+        
+        var service = {};
+        service.details = details;
+        service.list = list;
+        service.create = create;
+        service.drop = drop;
+        service.edit = edit;
+        
+        return service;
+        
+        function details(account_id) {
+            return $http.get( apiRoute.accounts + account_id)
+                .then(function handleSuccess(response) {
+                    return {success: true, account: response.data};
+                }, handleError('Error during accounts listing'));
+        }
+        
+        function list(account_id) {
+            return $http.get( apiRoute.accounts + account_id + '/entries')
+                    .then(handleSuccess, handleError('Error listing account entries'));
+        }
+        
+        function create(account, entry) {
+            return $http.post( apiRoute.accounts + account._id + '/entries', entry)
+                    .then(handleSuccess, handleError('Error creating entry'));
+        }
+        
+        function drop(account, entry) {
+            return $http.delete(apiRoute.accounts + account._id + '/entries/' + entry._id)
+                    .then(handleSuccess, handleError('Error deleting entry'));
+        }
+        
+        function edit(account, id, entry) {
+            return $http.put(apiRoute.accounts + account._id + '/entries/' + id, entry)
+                    .then(handleSuccess, handleError('Error updating entry'));
+        }
+        
+        function handleSuccess(response) {
+            return {success: true, data: response.data};
+        }
+        
+        function handleError(error) {
+            return function() {
+                return {success: false, message: error};
+            };
+        }
+    }
+})();

+ 287 - 0
test/account.controller.spec.js

@@ -0,0 +1,287 @@
+describe('AccountController', function() {
+    
+    var $location,
+        $rootScope,
+        $scope,
+        $timeout,
+        $httpBackend,
+        AccountService,
+        FlashService,
+        createController,
+        apiRoutes,
+        shouldPass,
+        DEFAULT_ACCOUNT = {
+            "name": "test",
+            "reference": "1234567890",
+            "user_id": "55b78934d2a706265ea28e9c",
+            "_id": "560aa0e79633cd7c1495ff21",
+             "categories": [{
+                "key": "alimony_payments",
+                "label": "Alimony Payments",
+                "_id": "560a84058812ad8d0ff200ef",
+                "sub_categories": []
+            }, {
+                "key": "automobile_expenses",
+                "label": "Automobile Expenses",
+                "_id": "560a84058812ad8d0ff200f0",
+                "sub_categories": [{
+                    "label": "Car Payment",
+                    "key": "car_payment",
+                    "_id": "560a84058812ad8d0ff200f3"
+                }, {
+                    "label": "Gasoline",
+                    "key": "gasoline",
+                    "_id": "560a84058812ad8d0ff200f2"
+                }, {
+                    "label": "Maintenance",
+                    "key": "maintenance",
+                    "_id": "560a84058812ad8d0ff200f1"
+                }]
+            }]
+        },
+        DEFAULT_ENTRY = {
+            "_id": "561280789f3c83904adcf41b",
+            "account_id": "560a84058812ad8d0ff200ee",
+            "amount": 100,
+            "date": "2015-09-29T22:00:00.000Z",
+            "type": "DEPOSIT",
+            "category": "560a84058812ad8d0ff200f0",
+            "sub_category": "560a84058812ad8d0ff200f3"
+        };
+        
+    beforeEach(module('cloudbudget'));
+    
+    beforeEach(inject(function ( _$rootScope_, _$httpBackend_,  $controller, _$location_, $routeParams, _$timeout_, _AccountService_, _FlashService_, _apiRoutes_) {
+        $location = _$location_;
+        $httpBackend = $httpBackend;
+        $rootScope = _$rootScope_.$new();
+        $scope = _$rootScope_.$new();
+        $scope.form = {
+          $valid: true,
+          $setPristine: function() {}
+        };
+        $timeout = _$timeout_;
+        AccountService = _AccountService_;
+        FlashService = _FlashService_;
+        apiRoutes = _apiRoutes_;
+        
+        createController = function() {
+            return $controller('AccountController', {
+                '$scope': $scope,
+                '$location': $location,
+                '$rootScope': $rootScope,
+                '$routeParams': {account_id: DEFAULT_ACCOUNT._id},
+                FlashService: _FlashService_,
+                AccountService: _AccountService_,
+            });
+        };
+    }));
+    
+    describe('init()', function() {
+        it('should init successfully', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts +  DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[DEFAULT_ENTRY], balance: 100});
+            
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            should.exist(accountController.account);
+            accountController.account._id.should.be.equal(DEFAULT_ACCOUNT._id);
+            accountController.entries.should.be.instanceof(Array).and.have.lengthOf(1);
+        }));
+        
+        it('should fail to init', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(400);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond(400);
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            should.not.exist(accountController.account);
+            accountController.entries.should.be.instanceof(Array).and.have.lengthOf(0);
+        }));
+    });
+    
+    describe('* create()', function() {
+        it('should create successfully', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[], balance: 0});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            $httpBackend.expect('POST', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: DEFAULT_ENTRY, entries:[DEFAULT_ENTRY], balance: 100});
+
+            accountController.entry = DEFAULT_ENTRY;
+            
+            accountController.create();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            var entry = accountController.entries[0];
+            entry.amount.should.be.equal(DEFAULT_ENTRY.amount);
+            entry.category.should.be.equal(DEFAULT_ENTRY.category);
+            entry.sub_category.should.be.equal(DEFAULT_ENTRY.sub_category);
+            entry.type.should.be.equal(DEFAULT_ENTRY.type);
+            should.exist(entry._id);
+        }));
+        
+        it('should fail to create entry', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[], balance: 0});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            $httpBackend.expect('POST', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond(400, [{"field":"amount","rule":"required","message":"Path `amount` is required."}]);
+
+            
+            accountController.entry = {
+                date: DEFAULT_ENTRY.date
+            };
+            
+            accountController.create();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            accountController.entries.should.be.instanceof(Array).and.have.lengthOf(0);
+        }));
+    });
+    
+    describe('* delete()', function() {
+        it('should delete successfully', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[DEFAULT_ENTRY], balance: 100});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            $httpBackend.expect('DELETE', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries/' + DEFAULT_ENTRY._id)
+                .respond(204, {entry: null, entries:[], balance: 0});
+
+            accountController.drop( accountController.entries[0] );
+            
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            accountController.entries.should.be.instanceof(Array).and.have.lengthOf(0);
+        }));
+        
+        it('should fail to delete unknown entry', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[DEFAULT_ACCOUNT], balance: 100});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            $httpBackend.expect('DELETE', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries/fake_id')
+                .respond(200, {entry: null, entries:[DEFAULT_ENTRY], balance: 100});
+
+            accountController.drop({_id: 'fake_id'});
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            accountController.entries.should.be.instanceof(Array).and.have.lengthOf(1);
+            accountController.entries[0]._id.should.be.equal(DEFAULT_ENTRY._id);
+        }));
+    });
+
+    describe('* edit()', function() {
+        it('should edit successfully', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[DEFAULT_ENTRY], balance: 100});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            var altered_entry = {
+                "_id": "561280789f3c83904adcf41b",
+                "account_id": "560a84058812ad8d0ff200ee",
+                "amount": 120,
+                "date": "2015-09-29T22:00:00.000Z",
+                "type": "DEPOSIT",
+                "category": "560a84058812ad8d0ff200f0",
+                "sub_category": "560a84058812ad8d0ff200f3"
+            };
+        
+            $httpBackend.expect('PUT', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries/' + DEFAULT_ENTRY._id)
+                .respond({entry: altered_entry, entries:[altered_entry], balance: 120});
+
+            accountController.edit(altered_entry, DEFAULT_ENTRY);
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            var entry = accountController.entries[0];
+            entry.amount.should.be.equal(altered_entry.amount);
+            entry.category.should.be.equal(DEFAULT_ENTRY.category);
+            entry.sub_category.should.be.equal(DEFAULT_ENTRY.sub_category);
+            entry.type.should.be.equal(DEFAULT_ENTRY.type);
+        }));
+        
+        it('should fail to edit unknown entry', inject(function($httpBackend) {
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id)
+                .respond(DEFAULT_ACCOUNT);
+    
+            $httpBackend.expect('GET', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries')
+                .respond({entry: null, entries:[DEFAULT_ENTRY], balance: 100});
+                
+            var accountController = createController();
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            var altered_entry = {
+                "_id": "561280789f3c83904adcf41b",
+                "account_id": "560a84058812ad8d0ff200ee",
+                "amount": 120,
+                "date": "2015-09-29T22:00:00.000Z",
+                "type": "DEPOSIT",
+                "category": "560a84058812ad8d0ff200f0",
+                "sub_category": "560a84058812ad8d0ff200f3"
+            };
+        
+            $httpBackend.expect('PUT', apiRoutes.accounts + DEFAULT_ACCOUNT._id + '/entries/' + DEFAULT_ENTRY._id)
+                .respond(400, {entry: DEFAULT_ENTRY, entries:[DEFAULT_ENTRY], balance: 100});
+
+            accountController.edit(altered_entry, DEFAULT_ENTRY);
+            $httpBackend.flush();
+            $timeout.flush();
+            
+            var entry = accountController.entries[0];
+            entry.amount.should.be.equal(DEFAULT_ENTRY.amount);
+            entry.category.should.be.equal(DEFAULT_ENTRY.category);
+            entry.sub_category.should.be.equal(DEFAULT_ENTRY.sub_category);
+            entry.type.should.be.equal(DEFAULT_ENTRY.type);
+        }));
+    });
+
+});