2 * Checkout items to patrons
5 angular.module('egPatronApp').controller('PatronCheckoutCtrl',
7 ['$scope','$q','$routeParams','egCore','egUser','patronSvc',
8 'egGridDataProvider','$location','$timeout','egCirc','ngToast',
10 function($scope , $q , $routeParams , egCore , egUser , patronSvc ,
11 egGridDataProvider , $location , $timeout , egCirc , ngToast) {
13 $scope.initTab('checkout', $routeParams.id).finally(function(){
14 $scope.focusMe = true;
16 $scope.checkouts = patronSvc.checkouts;
17 $scope.checkoutArgs = {
18 noncat_type : 'barcode',
22 $scope.gridDataProvider = egGridDataProvider.instance({
23 get : function(offset, count) {
24 return this.arrayNotifier($scope.checkouts, offset, count);
28 $scope.disable_checkout = function() {
31 patronSvc.current.active() == 'f' ||
32 patronSvc.current.deleted() == 't' ||
33 patronSvc.current.card().active() == 'f'
37 function setting_value (user, setting) {
39 var list = user.settings().filter(function(s){
40 return s.name() == setting;
43 if (list.length) return list[0].value();
47 $scope.has_email_address = function() {
50 patronSvc.current.email() &&
51 patronSvc.current.email().match(/.*@.*/).length
55 $scope.may_email_receipt = function() {
57 $scope.has_email_address() &&
60 'circ.send_email_checkout_receipts'
65 $scope.using_hatch = egCore.hatch.usingHatch();
67 egCore.hatch.getItem('circ.checkout.strict_barcode')
68 .then(function(sb){ $scope.strict_barcode = sb });
70 // avoid multiple, in-flight attempts on the same barcode
71 var pending_barcodes = {};
73 var printOnComplete = true;
75 'circ.staff_client.do_not_auto_attempt_print'
76 ]).then(function(settings) {
77 printOnComplete = !Boolean(
78 settings['circ.staff_client.do_not_auto_attempt_print']);
81 egCirc.get_noncat_types().then(function(list) {
82 $scope.nonCatTypes = list;
85 $scope.selectedNcType = function() {
86 if (!egCore.env.cnct) return null; // too soon
87 var type = egCore.env.cnct.map[$scope.checkoutArgs.noncat_type];
88 return type ? type.name() : null;
91 $scope.checkout = function(args) {
92 var params = angular.copy(args);
93 params.patron_id = patronSvc.current.id();
95 if (args.sticky_date) {
96 params.due_date = args.due_date.toISOString();
98 delete params.due_date;
100 delete params.sticky_date;
102 if (params.noncat_type == 'barcode') {
103 if (!args.copy_barcode) return;
105 args.copy_barcode = ''; // reset UI input
106 params.noncat_type = ''; // "barcode"
108 if (pending_barcodes[params.copy_barcode]) {
110 "Skipping checkout of redundant barcode "
111 + params.copy_barcode
116 pending_barcodes[params.copy_barcode] = true;
117 send_checkout(params);
120 egCirc.noncat_dialog(params).then(function() {
121 send_checkout(params)
125 $scope.focusMe = true; // return focus to barcode input
128 function send_checkout(params) {
130 params.noncat_type = params.noncat ? params.noncat_type : '';
132 // populate the grid row before we send the request so that the
133 // order of actions is maintained and so the user gets an
134 // immediate reaction to their barcode input action.
136 index : $scope.checkouts.length,
137 copy_barcode : params.copy_barcode,
138 noncat_type : params.noncat_type
141 $scope.checkouts.unshift(row_item);
142 $scope.gridDataProvider.refresh();
144 egCore.hatch.setItem('circ.checkout.strict_barcode', $scope.strict_barcode);
145 var options = {check_barcode : $scope.strict_barcode};
147 egCirc.checkout(params, options).then(
149 // update stats locally so we don't have to fetch them w/
151 patronSvc.patron_stats.checkouts.out++;
152 patronSvc.patron_stats.checkouts.total_out++;
154 // copy the response event into the original grid row item
155 // note: angular.copy clobbers the destination
156 row_item.evt = co_resp.evt;
157 angular.forEach(co_resp.data, function(val, key) {
160 munge_checkout_resp(co_resp, row_item);
163 // Circ was rejected somewhere along the way.
164 // Remove the copy from the grid since there was no action.
165 // note: since checkouts are unshifted onto the array, the
166 // index value does not (generally) match the array position.
168 angular.forEach($scope.checkouts, function(co, idx) {
169 if (co.index == row_item.index) pos = idx;
171 $scope.checkouts.splice(pos, 1);
172 $scope.gridDataProvider.refresh();
175 ).finally(function() {
177 // regardless of the outcome of the circ, remove the
178 // barcode from the pending list.
179 if (params.copy_barcode)
180 delete pending_barcodes[params.copy_barcode];
182 $scope.focusMe = true; // return focus to barcode input
186 // add some checkout-specific additions for display
187 function munge_checkout_resp(co_resp, row_item) {
188 var params = co_resp.params;
190 row_item.title = egCore.env.cnct.map[params.noncat_type].name();
191 row_item.noncat_count = params.noncat_count;
192 row_item.circ = new egCore.idl.circ();
193 row_item.circ.due_date(co_resp.evt.payload.noncat_circ.duedate());
197 $scope.print_receipt = function() {
198 var print_data = {circulations : []}
200 if ($scope.checkouts.length == 0) return $q.when();
202 angular.forEach($scope.checkouts, function(co) {
204 print_data.circulations.push({
205 circ : egCore.idl.toHash(co.circ),
206 copy : egCore.idl.toHash(co.acp),
207 call_number : egCore.idl.toHash(co.acn),
214 return egCore.print.print({
216 template : 'checkout',
218 show_dialog : $scope.show_print_dialog
222 $scope.email_receipt = function() {
223 if ($scope.has_email_address() && $scope.checkouts.length) {
224 return egCore.net.request(
226 'open-ils.circ.checkout.batch_notify.session.atomic',
228 patronSvc.current.id(),
229 $scope.checkouts.map(function (c) { return c.circ.id() })
231 ngToast.create(egCore.strings.EMAILED_CHECKOUT_RECEIPT);
238 $scope.print_or_email_receipt = function() {
239 if ($scope.may_email_receipt()) return $scope.email_receipt();
240 $scope.print_receipt();
243 // set of functions to issue a receipt (if desired), then
245 $scope.done_auto_receipt = function() {
246 if ($scope.may_email_receipt()) {
247 $scope.email_receipt().then(function() {
248 $scope.done_redirect();
251 if (printOnComplete) {
253 $scope.print_receipt().then(function() {
254 $scope.done_redirect();
258 $scope.done_redirect();
262 $scope.done_print_receipt = function() {
263 $scope.print_receipt().then( function () {
264 $scope.done_redirect();
267 $scope.done_email_receipt = function() {
268 $scope.email_receipt().then( function () {
269 $scope.done_redirect();
272 $scope.done_no_receipt = function() {
273 $scope.done_redirect();
276 // Redirect the user to the barcode entry page to load a new patron.
277 $scope.done_redirect = function() {
278 $location.path('/circ/patron/bcsearch');