LP#1842940: add perm to permit staff to edit their own accounts in the client
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / circ / renew / app.js
1 /**
2  * Renewal
3  */
4
5 angular.module('egRenewApp', 
6     ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod'])
7
8 .config(function($routeProvider, $locationProvider, $compileProvider) {
9     $locationProvider.html5Mode(true);
10     $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|blob):/); // grid export    
11         
12         var resolver = {delay : function(egStartup) {return egStartup.go()}};
13
14     $routeProvider.when('/circ/renew/renew', {
15         templateUrl: './circ/renew/t_renew',
16         controller: 'RenewCtrl',
17         resolve : resolver
18     });
19
20     $routeProvider.when('/circ/renew/renew', {
21         templateUrl: './circ/renew/t_renew',
22         controller: 'RenewCtrl',
23         resolve : resolver
24     });
25     
26     $routeProvider.otherwise({redirectTo : '/circ/renew/renew'});
27 })
28
29
30
31
32 .controller('RenewCtrl',
33        ['$scope','$window','$location','egCore','egGridDataProvider','egCirc',
34 function($scope , $window , $location , egCore , egGridDataProvider , egCirc) {
35
36     egCore.hatch.getItem('circ.renew.strict_barcode')
37         .then(function(sb){ $scope.strict_barcode = sb });
38     $scope.focusBarcode = true;
39     $scope.outOfRange = false;
40     $scope.minDate = new Date();
41     $scope.renewals = [];
42
43     var today = new Date();
44     $scope.renewalArgs = {due_date : today};
45
46     $scope.sort_money = function (a,b) {
47         var ma = parseFloat(a);
48         var mb = parseFloat(b);
49         if (ma < mb) return -1;
50         if (ma > mb) return 1;
51         return 0
52     }
53
54     $scope.gridDataProvider = egGridDataProvider.instance({
55         get : function(offset, count) {
56             return this.arrayNotifier($scope.renewals, offset, count);
57         }
58     });
59
60     // avoid multiple, in-flight attempts on the same barcode
61     var pending_barcodes = {};
62
63     $scope.renew = function(args) {
64         var params = angular.copy(args);
65
66         if (args.sticky_date) {
67             params.due_date = args.due_date.toISOString();
68         } else {
69             delete params.due_date;
70         }
71         delete params.sticky_date;
72          if (!args.copy_barcode) return;
73
74         args.copy_barcode = ''; // reset UI input
75
76         if (pending_barcodes[params.copy_barcode]) {
77             console.log(
78                 "Skipping renewals of redundant barcode " 
79                 + params.copy_barcode
80             );
81             return;
82         }
83
84         pending_barcodes[params.copy_barcode] = true;
85         send_renewal(params);
86
87         $scope.focusBarcode = true; // return focus to barcode input
88     }
89
90     function send_renewal(params) {
91
92         params.noncat_type = params.noncat ? params.noncat_type : '';
93
94         // populate the grid row before we send the request so that the
95         // order of actions is maintained and so the user gets an 
96         // immediate reaction to their barcode input action.
97         var row_item = {
98             index : $scope.renewals.length,
99             input_barcode : params.copy_barcode,
100             noncat_type : params.noncat_type
101         };
102
103         $scope.renewals.unshift(row_item);
104         $scope.gridDataProvider.refresh();
105
106         egCore.hatch.setItem('circ.renew.strict_barcode', $scope.strict_barcode);
107         var options = {check_barcode : $scope.strict_barcode};
108
109         egCirc.renew(params, options).then(
110             function(final_resp) {
111
112                 row_item.evt = final_resp.evt;
113                 angular.forEach(final_resp.data, function(val, key) {
114                     row_item[key] = val;
115                 });
116
117                 row_item['copy_barcode'] = row_item.acp.barcode();
118
119                 if (row_item.mbts) {
120                     var amt = Number(row_item.mbts.balance_owed());
121                     if (amt != 0) {
122                         $scope.billable_barcode = row_item.copy_barcode;
123                         $scope.billable_amount = amt;
124                         $scope.fine_total = 
125                             ($scope.fine_total * 100 + amt * 100) / 100;
126                     }
127                 }
128
129                 if ($scope.trim_list && checkinSvc.checkins.length > 20)
130                     checkinSvc.checkins = checkinSvc.checkins.splice(0, 20);
131
132             },
133             function() {
134                 // Circ was rejected somewhere along the way.
135                 // Remove the copy from the grid since there was no action.
136                 // note: since renewals are unshifted onto the array, the
137                 // index value does not (generally) match the array position.
138                 var pos = -1;
139                 angular.forEach($scope.renewals, function(co, idx) {
140                     if (co.index == row_item.index) pos = idx;
141                 });
142                 $scope.renewals.splice(pos, 1);
143                 $scope.gridDataProvider.refresh();
144             }
145
146         )['finally'](function() {
147
148             // regardless of the outcome of the circ, remove the 
149             // barcode from the pending list.
150             if (params.copy_barcode)
151                 delete pending_barcodes[params.copy_barcode];
152         });
153     }
154
155     $scope.fetchLastCircPatron = function(items) {
156         var renewal = items[0];
157         if (!renewal || !renewal.acp) return;
158
159         egCirc.last_copy_circ(renewal.acp.id())
160         .then(function(circ) {
161
162             if (circ) {
163                 // jump to the patron UI (separate app)
164                 $window.location.href = $location
165                     .path('/circ/patron/' + circ.usr() + '/checkout')
166                     .absUrl();
167                 return;
168             }
169
170             $scope.alert = {item_never_circed : renewal.acp.barcode()};
171         });
172     }
173
174     $scope.showMarkDamaged = function(items) {
175         var copy_ids = [];
176         angular.forEach(items, function(item) {
177             if (item.acp) copy_ids.push(item.acp.id());
178         });
179
180         if (copy_ids.length) {
181             egCirc.mark_damaged(copy_ids).then(function() {
182                 // update grid items?
183             });
184         }
185     }
186
187     $scope.showMarkDiscard = function(items) {
188         var copies = [];
189         angular.forEach(items, function(item) {
190             if (item.acp) copies.push(egCore.idl.toHash(item.acp));
191         });
192
193         if (copies.length) {
194             egCirc.mark_discard(copies).then(function() {
195                 // update grid items?
196             });
197         }
198     }
199
200     $scope.showLastFewCircs = function(items) {
201         if (items.length && (copy = items[0].acp)) {
202             var url = $location.path(
203                 '/cat/item/' + copy.id() + '/circ_list').absUrl();
204             $window.open(url, '_blank').focus();
205         }
206     }
207
208     $scope.abortTransit = function(items) {
209         var transit_ids = [];
210         angular.forEach(items, function(item) {
211             if (item.transit) transit_ids.push(item.transit.id());
212         });
213
214         egCirc.abort_transits(transit_ids).then(function() {
215             // update grid items?
216         });
217     }
218
219     $scope.addCopyAlerts = function(items) {
220         var copy_ids = [];
221         angular.forEach(items, function(item) {
222             if (item.acp) copy_ids.push(item.acp.id());
223         });
224         egCirc.add_copy_alerts(copy_ids).then(function() {
225             // update grid items?
226         });
227     }
228
229     $scope.manageCopyAlerts = function(items) {
230         var copy_ids = [];
231         angular.forEach(items, function(item) {
232             if (item.acp) copy_ids.push(item.acp.id());
233         });
234         egCirc.manage_copy_alerts(copy_ids).then(function() {
235             // update grid items?
236         });
237     }
238
239     $scope.print_receipt = function() {
240         var print_data = {circulations : []}
241
242         if ($scope.renewals.length == 0) return $q.when();
243
244         angular.forEach($scope.renewals, function(renewal) {
245             if (renewal.circ) {
246                 print_data.circulations.push({
247                     circ : egCore.idl.toHash(renewal.circ),
248                     copy : egCore.idl.toHash(renewal.acp),
249                     title : egCore.idl.toHash(renewal.title),
250                     author : egCore.idl.toHash(renewal.author)
251                 });
252             }
253         });
254
255         return egCore.print.print({
256             context : 'default', 
257             template : 'renew', 
258             scope : print_data,
259         });
260     }
261 }])
262