]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/circ/patron/checkout.js
LP#1350042 Browser client templates/scripts (phase 1)
[working/Evergreen.git] / Open-ILS / web / js / ui / default / staff / circ / patron / checkout.js
1 /**
2  * Checkout items to patrons
3  */
4
5 angular.module('egPatronApp').controller('PatronCheckoutCtrl',
6
7        ['$scope','$q','$modal','$routeParams','egCore','egUser','patronSvc',
8         'egGridDataProvider','$location','$timeout','egCirc',
9
10 function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc , 
11          egGridDataProvider , $location , $timeout , egCirc) {
12
13     $scope.initTab('checkout', $routeParams.id);
14     $scope.focusMe = true;
15     $scope.checkouts = patronSvc.checkouts;
16     $scope.checkoutArgs = {
17         noncat_type : 'barcode',
18         due_date : new Date()
19     };
20
21     $scope.gridDataProvider = egGridDataProvider.instance({
22         get : function(offset, count) {
23             return this.arrayNotifier($scope.checkouts, offset, count);
24         }
25     });
26
27     $scope.disable_checkout = function() {
28         return (
29             !patronSvc.current ||
30             patronSvc.current.active() == 'f' ||
31             patronSvc.current.deleted() == 't' ||
32             patronSvc.current.card().active() == 'f'
33         );
34     }
35
36     $scope.using_hatch = egCore.hatch.usingHatch();
37
38     // avoid multiple, in-flight attempts on the same barcode
39     var pending_barcodes = {};
40
41     var printOnComplete = true;
42     egCore.org.settings([
43         'circ.staff_client.do_not_auto_attempt_print'
44     ]).then(function(settings) { 
45         printOnComplete = !Boolean(
46             settings['circ.staff_client.do_not_auto_attempt_print']);
47     });
48
49     egCirc.get_noncat_types().then(function(list) {
50         $scope.nonCatTypes = list;
51     });
52
53     $scope.selectedNcType = function() {
54         if (!egCore.env.cnct) return null; // too soon
55         var type = egCore.env.cnct.map[$scope.checkoutArgs.noncat_type];
56         return type ? type.name() : null;
57     }
58
59     $scope.checkout = function(args) {
60         var params = angular.copy(args);
61         params.patron_id = patronSvc.current.id();
62
63         if (args.sticky_date) {
64             params.due_date = args.due_date.toISOString();
65         } else {
66             delete params.due_date;
67         }
68         delete params.sticky_date;
69
70         if (params.noncat_type == 'barcode') {
71             if (!args.copy_barcode) return;
72
73             args.copy_barcode = ''; // reset UI input
74             params.noncat_type = ''; // "barcode"
75
76             if (pending_barcodes[params.copy_barcode]) {
77                 console.log(
78                     "Skipping checkout of redundant barcode " 
79                     + params.copy_barcode
80                 );
81                 return;
82             }
83
84             pending_barcodes[params.copy_barcode] = true;
85             send_checkout(params);
86
87         } else {
88             egCirc.noncat_dialog(params).then(function() {
89                 send_checkout(params)
90             });
91         }
92
93         $scope.focusMe; // return focus to barcode input
94     }
95
96     function send_checkout(params) {
97
98         params.noncat_type = params.noncat ? params.noncat_type : '';
99
100         // populate the grid row before we send the request so that the
101         // order of actions is maintained and so the user gets an 
102         // immediate reaction to their barcode input action.
103         var row_item = {
104             index : $scope.checkouts.length,
105             copy_barcode : params.copy_barcode,
106             noncat_type : params.noncat_type
107         };
108
109         $scope.checkouts.unshift(row_item);
110         $scope.gridDataProvider.refresh();
111
112         var options = {check_barcode : $scope.strict_barcode};
113
114         egCirc.checkout(params, options).then(
115             function(co_resp) {
116                 // update stats locally so we don't have to fetch them w/
117                 // each checkout.
118                 patronSvc.patron_stats.checkouts.out++;
119                 patronSvc.patron_stats.checkouts.total_out++;
120
121                 // copy the response event into the original grid row item
122                 // note: angular.copy clobbers the destination
123                 row_item.evt = co_resp.evt;
124                 angular.forEach(co_resp.data, function(val, key) {
125                     row_item[key] = val;
126                 });
127                 munge_checkout_resp(co_resp, row_item);
128             },
129             function() {
130                 // Circ was rejected somewhere along the way.
131                 // Remove the copy from the grid since there was no action.
132                 // note: since checkouts are unshifted onto the array, the
133                 // index value does not (generally) match the array position.
134                 var pos = -1;
135                 angular.forEach($scope.checkouts, function(co, idx) {
136                     if (co.index == row_item.index) pos = idx;
137                 });
138                 $scope.checkouts.splice(pos, 1);
139                 $scope.gridDataProvider.refresh();
140             }
141
142         )['finally'](function() {
143
144             // regardless of the outcome of the circ, remove the 
145             // barcode from the pending list.
146             if (params.copy_barcode)
147                 delete pending_barcodes[params.copy_barcode];
148         });
149     }
150
151     // add some checkout-specific additions for display
152     function munge_checkout_resp(co_resp, row_item) {
153         var params = co_resp.params;
154         if (params.noncat) {
155             row_item.title = egCore.env.cnct.map[params.noncat_type].name();
156             row_item.noncat_count = params.noncat_count;
157             row_item.circ = new egCore.idl.circ();
158             row_item.circ.due_date(co_resp.evt.payload.noncat_circ.duedate());
159         }
160     }
161
162     $scope.print_receipt = function() {
163         var print_data = {circulations : []}
164
165         if ($scope.checkouts.length == 0) return $q.when();
166
167         angular.forEach($scope.checkouts, function(co) {
168             if (co.circ) {
169                 print_data.circulations.push({
170                     circ : egCore.idl.toHash(co.circ),
171                     copy : egCore.idl.toHash(co.acp),
172                     call_number : egCore.idl.toHash(co.acn),
173                     title : co.title,
174                     author : co.author
175                 })
176             };
177         });
178
179         return egCore.print.print({
180             context : 'default', 
181             template : 'checkout', 
182             scope : print_data,
183             show_dialog : $scope.show_print_dialog
184         });
185     }
186
187     // Redirect the user to the barcode entry page to load a new patron.
188     // If configured to do so, print the receipt first
189     $scope.done = function() {
190         if (printOnComplete) {
191
192             $scope.print_receipt().then(function() {
193                 $location.path('/circ/patron/bcsearch');
194             });
195
196         } else {
197             $location.path('/circ/patron/bcsearch');
198         }
199     }
200 }])
201