circ checkin migration; transit slip
authorBill Erickson <berick@esilibrary.com>
Wed, 11 Jun 2014 19:46:39 +0000 (15:46 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 11 Jun 2014 19:46:39 +0000 (15:46 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/admin/workstation/t_print_templates.tt2
Open-ILS/src/templates/staff/circ/checkin/index.tt2
Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2
Open-ILS/src/templates/staff/circ/patron/index.tt2
Open-ILS/src/templates/staff/circ/share/t_transit_dialog.tt2
Open-ILS/src/templates/staff/share/print_templates/t_transit_slip.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/admin/workstation/app.js
Open-ILS/web/js/ui/default/staff/circ/checkin/app.js
Open-ILS/web/js/ui/default/staff/circ/services/circ.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/circ/services/circulate.js [deleted file]
Open-ILS/web/js/ui/default/staff/services/hatch.js

index c25c2bd..5e30af2 100644 (file)
@@ -16,6 +16,7 @@
       <option value="bills_historical">[% l('Bills, Historical') %]</option>
       <option value="bill_payment">[% l('Bills, Payment') %]</option>
       <option value="patron_note">[% l('Patron Note') %]</option>
+      <option value="transit_slip">[% l('Transit Slip') %]</option>
     </select>
   </div>
   <div class="col-md-7">
index ea5d58c..2432bd2 100644 (file)
@@ -9,6 +9,7 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/grid.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/circ.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/checkin/app.js"></script>
 <script>
 angular.module('egCoreMod').run(['egStrings', function(s) {
index b7bb353..0016662 100644 (file)
@@ -1,18 +1,37 @@
 <!-- checkins list -->
 
 <eg-grid
-  id-field="id"
-  features="-display,-sort,-multisort"
+  id-field="index"
+  features="-sort,-multisort"
   main-label="[% l('Items Checked In') %]"
   items-provider="gridDataProvider"
+  grid-controls="gridControls"
   persist-key="circ.checkin">
-  <eg-grid-field label="[% l('Circ ID') %]"      path='payload.circ.id' visible></eg-grid-field>
-  <eg-grid-field label="[% l('Barcode') %]"      path='copy_barcode' visible></eg-grid-field>
-  <eg-grid-field label="[% l('Due Date') %]"    path='payload.circ.due_date' visible></eg-grid-field>
-  <eg-grid-field label="[% l('Response') %]"    path="textcode" visible></eg-grid-field>
-  <eg-grid-field label="[% l('Title') %]"       path="payload.record.title" visible></eg-grid-field>
-  <eg-grid-field label="[% l('Author') %]"      path="payload.record.author" visible></eg-grid-field>
-  <eg-grid-field label="[% l('Call Number') %]" path="payload.copy.call_number.label" visible></eg-grid-field>
-  <eg-grid-field label="[% l('Alert Msg') %]"   path="payload.copy.alert_message" visible></eg-grid-field>
+
+  <eg-grid-field label="[% l('Circ ID') %]"     
+    path='payload.circ.id'></eg-grid-field>
+
+  <eg-grid-field label="[% l('Barcode') %]" path="copy_barcode">
+    <!-- wth... ng-if / ng-disabled not working here.
+      i want to hide / disable the href when there is no copy ID -->
+      <a href="./cat/item/{{item.payload.copy.id()}}/summary" target="_self">
+        {{item.copy_barcode}}
+      </a>
+  </eg-grid-field>
+
+  <eg-grid-field label="[% l('Due Date') %]"    
+    path='payload.circ.due_date' datatype="timestamp"></eg-grid-field>
+  <eg-grid-field label="[% l('Response Code') %]"    
+    path="textcode"></eg-grid-field>
+  <eg-grid-field label="[% l('Title') %]"       
+    path="payload.record.title"></eg-grid-field>
+  <eg-grid-field label="[% l('Author') %]"      
+    path="payload.record.author"></eg-grid-field>
+  <eg-grid-field label="[% l('Call Number') %]" 
+    path="payload.copy.call_number.label"></eg-grid-field>
+  <eg-grid-field label="[% l('Alert Msg') %]"   
+    path="payload.copy.alert_message"></eg-grid-field>
+
+  <!-- TODO: add support for wildcard fields sans idl-class -->
 </eg-grid>
 
index 01bdabf..65dbfd7 100644 (file)
@@ -10,6 +10,7 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/billing.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/services/circ.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/app.js"></script>
 
 <!-- load the rest on demand? -->
index 7d53a83..fd09a2c 100644 (file)
       </div>
     </div>
     <div class="modal-footer">
-      <!--
-      <input type="button" class="btn btn-primary" disabled="disabled"
+      <input type="button" class="btn btn-primary"
         ng-click="print()" value="[% l('Print') %]"/>
-        -->
       <input type="submit" class="btn btn-warning"
         ng-click="ok()" value="[% l('Do Not Print') %]"/>
     </div>
diff --git a/Open-ILS/src/templates/staff/share/print_templates/t_transit_slip.tt2 b/Open-ILS/src/templates/staff/share/print_templates/t_transit_slip.tt2
new file mode 100644 (file)
index 0000000..20d0095
--- /dev/null
@@ -0,0 +1,15 @@
+<div>
+  <div>[% l('This item needs to be routed to [_1]', '<b>{{transit.dest.shortname}}</b>') %]</div>
+  {{transit.dest.name}}<br/>
+  {{transit.dest.holds_address.street1}}
+  {{transit.dest.holds_address.street2}}<br/>
+  {{transit.dest.holds_address.city}},
+  {{transit.dest.holds_address.state}}
+  {{transit.dest.holds_address.post_code}}<br/><br/>
+  [% l('Barcode: [_1]', '{{transit.target_copy.barcode}}') %]<br/>
+  [% l('Title: [_1]', '{{title}}') %]<br/>
+  [% l('Author: [_1]', '{{author}}') %]<br/>
+  [% l('Slip Date: [_1]', '{{today | date:"short"}}') %]<br/>
+  [% l('Printed by [_1] at [_2]', 
+    '{{staff.first_given_name}}', '{{current_location.shortname}}') %]<br/>
+</div>
index 2c52b42..11db1bd 100644 (file)
@@ -313,6 +313,25 @@ function($scope , $q , egCore) {
             barcode : '30393830393'
         }
     }
+    var seed_addr = {
+        street1 : '123 Apple Rd',
+        street2 : 'Suite B',
+        city : 'Anywhere',
+        state : 'XX',
+        country : 'US',
+        post_code : '12345'
+    }
+
+    var seed_record = {
+        title : 'Traveling Pants!!',
+        author : 'Jane Jones',
+        isbn : '1231312123'
+    };
+
+    var seed_copy = {
+        barcode : '33434322323'
+    }
+
     $scope.preview_scope = {
         current_location : egCore.idl.toHash(
             egCore.org.get(egCore.auth.user().ws_ou())),
@@ -358,16 +377,29 @@ function($scope , $q , egCore) {
             title : 'Test Note Title',
             usr : seed_user,
             value : 'This patron is super nice!'
-        }
+        },
+
+        transit : {
+            dest : {
+                name : 'Library X',
+                shortname : 'LX',
+                holds_address : seed_addr
+            },
+            target_copy : seed_copy
+        },
+        title : seed_record.title,
+        author : seed_record.author,
+        staff : egCore.idl.toHash(egCore.auth.user())
     }
+
     $scope.preview_scope.payments = [
         {amount : 1.00, xact : $scope.preview_scope.transactions[0]}, 
         {amount : 1.00, xact : $scope.preview_scope.transactions[1]}
     ]
     $scope.preview_scope.payments[0].xact.title = 'Hali Bote Azikaban de tao fan';
     $scope.preview_scope.payments[0].xact.copy_barcode = '334343434';
-    $scope.preview_scope.payments[1].xact.title = 'Traveling Pants!!';
-    $scope.preview_scope.payments[1].xact.copy_barcode = '334343467';
+    $scope.preview_scope.payments[1].xact.title = seed_record.title;
+    $scope.preview_scope.payments[1].xact.copy_barcode = seed_copy.barcode;
 
     $scope.template_changed = function() {
         egCore.hatch.getPrintTemplate($scope.print.template_name)
index 829a4c8..4568cf2 100644 (file)
@@ -6,49 +6,19 @@ angular.module('egCheckinApp', ['ngRoute', 'ui.bootstrap',
     $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
 })
 
-/**
- * checkin service
- */
 .factory('checkinSvc', [function() {
-
     var service = {};
     service.checkins = [];
     return service;
 }])
 
-/**
- * locally cached org unit addresses -- needed for route slips, etc.
- */
-.factory('orgAddrSvc', ['$q','egCore', function($q,  egCore) {
-    var service = {cache : {}};
-    service.getAddr = function(org_id, addr_type) {
-        if (service.cache[org_id]) {
-            if (service.cache[org_id][addr_type]) {
-                return $q.when(service.cache[org_id][addr_type]);
-            }
-        } else {
-            service.cache[org_id] = {};
-        }
-
-        var deferred = $q.defer();
-        egCore.pcrud.retrieve('aoa', egCore.org.get(org_id).holds_address())
-        .then(function(addr) {
-            service.cache[org_id][addr_type] = addr;
-            deferred.resolve(addr);
-        });
-        return deferred.promise;
-    }
-    return service;
-}])
 
 /**
  * Manages checkin
  */
 .controller('CheckinCtrl',
-       ['$scope','$q','$modal','egCore','checkinSvc','egGridDataProvider',
-        'orgAddrSvc','egAlertDialog','egConfirmDialog',
-function($scope,  $q,  $modal,  egCore,  checkinSvc, egGridDataProvider, 
-         orgAddrSvc,  egAlertDialog,  egConfirmDialog) {
+       ['$scope','$q','egCore','checkinSvc','egGridDataProvider','egCirc',
+function($scope , $q , egCore , checkinSvc , egGridDataProvider , egCirc)  {
 
     // run egCore.startup here since it's not handled via resolver
     egCore.startup.go().then(
@@ -59,142 +29,32 @@ function($scope,  $q,  $modal,  egCore,  checkinSvc, egGridDataProvider,
 
     $scope.focusMe = true;
     $scope.checkins = checkinSvc.checkins;
+    var checkinGrid = $scope.gridControls = {};
 
-    var provider = egGridDataProvider.instance({});
-    provider.get = function(offset, count) {
-        return provider.arrayNotifier(
-            $scope.checkins, offset, count
-        );
-    }
-    $scope.gridDataProvider = provider;
-
-    function addCheckin(evt) {
-        checkinSvc.checkins.push(evt);
-        provider.refresh();
-    }
-
+    $scope.gridDataProvider = egGridDataProvider.instance({
+        get : function(offset, count) {
+            return this.arrayNotifier($scope.checkins, offset, count);
+        }
+    });
 
     $scope.checkin = function(args) {
-        if (args && args.copy_barcode) {
-            performCheckin(angular.copy(args));
-            args.copy_barcode = ''; // reset UI
-        } 
-
-        $scope.focusMe = true;
-    }
-
-    function performCheckin(args, override) {
-        var method = 'open-ils.circ.checkin';
-        if (override) method += '.override';
 
-        egCore.net.request('open-ils.circ', method, egCore.auth.token(), args)
-        .then(function(evt) {
+        if (args && args.copy_barcode) {
 
-            if (!evt) { 
-                console.error('no checkin response received');
-                return;
-            }
+            egCirc.checkin(angular.copy(args))
+            .then(function(final_resp) {
+                final_resp.evt.index = checkinSvc.checkins.length;
+                checkinSvc.checkins.unshift(final_resp.evt);
+                checkinGrid.refresh();
 
-            if (angular.isArray(evt)) evt = evt[0];
-            evt.id = checkinSvc.checkins.length;
-            evt.copy_barcode = args.copy_barcode;
-            handleCheckinResponse(evt, args, override);
-        });
-    }
+                // in case we lost focus to a dialog
+                $scope.focusMe = true;
+            });
 
-    function handleCheckinResponse(evt, args, override) {
-        var copy, hold, transit;
-        if (evt.payload) {
-            copy = evt.payload.copy;
-            hold = evt.payload.hold;
-            transit = evt.payload.transit;
-        }
-
-        switch (evt.textcode) {
-            case 'SUCCESS':
-            case 'NO_CHANGE':
-                addCheckin(evt);
-                if (copy.status() == 8) { // on holds shelf 
-                    if (hold && 
-                        hold.pickup_lib() == egCore.auth.user().ws_ou()) {
-                        // item should be on our holds shelf.  
-                        // display the holds slip
-                        openRouteDialog(
-                            './circ/checkin/t_hold_shelf_dialog', evt, args);
-                    }
-                }
-                break;
-                
-            case 'ROUTE_ITEM':
-                addCheckin(evt);
-                openRouteDialog('./circ/checkin/t_transit_dialog', evt, args);
-                break;
-            case 'ASSET_COPY_NOT_FOUND':
-                $scope.blurMe = true;
-                egAlertDialog.open(egCore.strings.UNCAT_ALERT_DIALOG, args)
-                    .result.then(function() {$scope.focusMe = true});
-                break;
-            case 'COPY_ALERT_MESSAGE':
-                $scope.blurMe = true;
-                egConfirmDialog.open(
-                    egCore.strings.COPY_ALERT_MSG_DIALOG_TITLE, 
-                    evt.payload,  // payload == alert message text
-                    {   copy_barcode : args.copy_barcode,
-                        ok : function() {
-                            // on confirm, redo checkout w/ override
-                            performCheckin(args, true)
-                        },
-                        cancel : function() { 
-                            // on cancel, push the event on the list
-                            // to show that it happened
-                            addCheckin(evt);
-                        }
-                    }
-                ).result.then(function() {$scope.focusMe = true})
-                break;
-            default:
-                console.warn('unhandled checkin response : ' + evt.textcode);
-                console.debug('checkin: ' + js2JSON(evt));
-                // push it on the list so the user can at least see 
-                // something happened.
-                addCheckin(evt);
-        }
-    }
+            args.copy_barcode = ''; // reset UI for next scan
+        } 
 
-    function openRouteDialog(tmpl, evt, args) {
-        // avoid unintended checkins while the dialog is open
-        $scope.blurMe = true;
-        $modal.open({
-            templateUrl: tmpl,
-            controller: [
-                '$scope', '$modalInstance', 'destAddr', 'holdUser',
-                function($scope, $modalInstance, destAddr, holdUser) {
-                $scope.destAddr = destAddr;
-                $scope.holdUser = holdUser;
-                $scope.dest = egCore.org.get(evt.org);
-                $scope.evt = evt;
-                $scope.now = new Date();
-                $scope.ok = function() {$modalInstance.close()}
-            }],
-            resolve : {
-                destAddr : function() {
-                    if (!evt.org) return $q.when();
-                    // TODO SERVER: response payload should flesh dest addr
-                    return orgAddrSvc.getAddr(evt.org, 'holds_address');
-                },
-                holdUser : function() {
-                    // TODO SERVER: response payload should flesh hold recipient
-                    if (!evt.payload.hold) return $q.when();
-                    return egCore.pcrud.retrieve('au', 
-                        evt.payload.hold.usr(), {
-                            flesh : 1,
-                            flesh_fields : {'au' : ['card']}
-                        }
-                    );
-                }
-            }
-        }).result.then(function() {$scope.focusMe = true});
+        $scope.focusMe = true;
     }
-
 }])
 
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/circ.js b/Open-ILS/web/js/ui/default/staff/circ/services/circ.js
new file mode 100644 (file)
index 0000000..bab34b6
--- /dev/null
@@ -0,0 +1,400 @@
+/**
+ * Checkin, checkout, and renew
+ */
+
+angular.module('egCoreMod')
+
+.factory('egCirc',
+
+       ['$modal','$q','egCore','egAlertDialog','egConfirmDialog',
+function($modal , $q , egCore , egAlertDialog , egConfirmDialog) {
+
+    var service = {
+        // auto-override these events after the first override
+        checkout_overrides : {},
+        org_addr_cache : {}
+    };
+
+    service.reset = function() {
+        service.checkout_overrides = {};
+    }
+
+    // Performs a checkout.
+    // Returns a promise resolved with the original params and options
+    // and the final checkout event (e.g. in the case of override).
+    // Rejected if the checkout cannot be completed.
+    service.checkout = function(params, options) {
+        if (!options) options = {};
+
+        console.debug('egCirc.checkout() : ' + js2JSON(params));
+
+        var method = 'open-ils.circ.checkout.full';
+        if (options.override) method += '.override';
+
+        return egCore.net.request(
+            'open-ils.circ', method, egCore.auth.token(), params
+
+        ).then(function(evt) {
+
+            if (angular.isArray(evt)) evt = evt[0];
+            return service.handle_checkout_resp(evt, args, override);
+        });
+    }
+
+    // Performs a renewal.
+    // Returns a promise resolved with the original params and options
+    // and the final checkout event (e.g. in the case of override)
+    // Rejected if the renewal cannot be completed.
+    service.renew = function(params, options) {
+        if (!options) options = {};
+
+        console.debug('egCirc.renew() : ' + js2JSON(params));
+
+        var method = 'open-ils.circ.renew';
+        if (options.override) method += '.override';
+
+        return egCore.net.request(
+            'open-ils.circ', method, egCore.auth.token(), params
+
+        ).then(function(evt) {
+
+            if (angular.isArray(evt)) evt = evt[0];
+            return service.handle_checkout_resp(evt, args, options);
+        });
+    }
+
+    // Performs a checkin
+    // Returns a promise resolved with the original params and options,
+    // plus the final checkin event (e.g. in the case of override).
+    // Rejected if the checkin cannot be completed.
+    service.checkin = function(params, options) {
+        if (!options) options = {};
+
+        var method = 'open-ils.circ.checkin';
+        if (options.override) method += '.override';
+
+        return egCore.net.request(
+            'open-ils.circ', method, egCore.auth.token(), params
+
+        ).then(function(evt) {
+
+            if (angular.isArray(evt)) evt = evt[0];
+            return service.handle_checkin_response(evt, params, options);
+        });
+    }
+
+    service.handle_checkout_resp = function(evt, params, options) {
+
+        var final_resp = {evt : evt, params : params, options : options};
+
+        // track the barcode regardless of whether it refers to a copy
+        evt.copy_barcode = params.copy_barcode;
+
+        switch (evt.textcode) {
+            case 'SUCCESS':
+                return $q.when(final_resp);
+
+            case 'ITEM_NOT_CATALOGED':
+                return service.precat_dialog(params, options);
+
+            case 'PATRON_EXCEEDS_OVERDUE_COUNT':
+            case 'PATRON_EXCEEDS_FINES':
+            case 'PATRON_EXCEEDS_CHECKOUT_COUNT':
+            case 'PATRON_EXCEEDS_LOST_COUNT':
+                if (options.override) {
+                    // NOTE: I don't think we'll ever get here, since the
+                    // override attempt should produce a perm failure...
+                    console.debug('override failed: ' + evt.textcode);
+
+                } else {
+                    if (service.checkout_overrides[evt.textcode]) {
+                        // user has already opted to override this type
+                        // of event.  Re-run the checkout w/ override.
+                        options.override = true;
+                        return service.checkout(params, options);
+                    } else {
+                        // ask the user if they would like to override this
+                        // event type.
+                        return service.override_dialog(evt, params, options);
+                    }
+                }
+                break;
+
+            case 'OPEN_CIRCULATION_EXISTS':
+                return service.circ_exists_dialog(evt, params, options);
+
+            /* stuff to consider 
+            PERM_FAILURE
+            PATRON_BARRED
+            CIRC_EXCEEDS_COPY_RANGE
+            PATRON_ACCOUNT_EXPIRED
+            ITEM_DEPOSIT_REQUIRED
+            ITEM_RENTAL_FEE_REQUIRED
+            ITEM_DEPOSIT_PAID
+            ACTION_CIRCULATION_NOT_FOUND
+            PATRON_EXCEEDS_CHECKOUT_COUNT
+            COPY_CIRC_NOT_ALLOWED
+            COPY_NOT_AVAILABLE
+            COPY_IS_REFERENCE
+            COPY_NEEDED_FOR_HOLD
+            MAX_RENEWALS_REACHED
+            CIRC_CLAIMS_RETURNED
+            COPY_ALERT_MESSAGE
+            */
+
+            default:
+                console.warn('unhandled circ response : ' + evt.textcode);
+                return $q.when(final_resp);
+        }
+    }
+
+    // fetch the list of circ modifiers, from cache if available
+    service.get_circ_mods = function() {
+        if (egCore.env.ccm) {
+            return $q.when(egCore.env.ccm.list);
+        } else {
+            return egCore.pcrud.retrieveAll('ccm', null, {atomic : true})
+            .then(function(list) { 
+                egCore.env.absorbList(list, 'ccm');
+                return list;
+            });
+        }
+    };
+
+    // fetch/cache for org unit addresses
+    service.get_org_addr = function(org_id, addr_type) {
+        if (service.org_addr_cache[org_id]) {
+            if (service.org_addr_cache[org_id][addr_type]) 
+                return $q.when(service.org_addr_cache[org_id][addr_type]);
+        } else {
+            service.org_addr_cache[org_id] = {};
+        }
+
+        return egCore.pcrud.retrieve('aoa', 
+            egCore.org.get(org_id)[addr_type]()
+        ).then(function(addr) {
+            return service.org_addr_cache[org_id][addr_type] = addr;
+        });
+    }
+
+    // opens a dialog asking the user if they would like to override
+    // the returned event.
+    service.override_dialog = function(evt, params, options) {
+        return $modal.open({
+            templateUrl: './circ/share/t_event_override_dialog',
+            controller: 
+                ['$scope', '$modalInstance', 
+                function($scope, $modalInstance) {
+                $scope.evt = evt;
+                $scope.ok = function() { $modalInstance.close() }
+                $scope.cancel = function () { $modalInstance.dismiss() }
+            }]
+        }).result.then(
+            function() {
+                service.checkout_overrides[evt.textcode] = true;
+                options.override = true;
+                return service.checkout(params, options);
+            }
+        );
+    }
+
+
+    // opens a dialog allowing the user to fill in pre-cat copy info
+    service.precat_dialog = function(params, options) {
+
+        return $modal.open({
+            templateUrl: './circ/share/t_precat_dialog',
+            controller: 
+                ['$scope', '$modalInstance', 'circMods',
+                function($scope, $modalInstance, circMods) {
+                $scope.focusMe = true;
+                $scope.precatArgs = {
+                    copy_barcode : params.copy_barcode,
+                    circ_modifier : circMods.length ? circMods[0].code() : null
+                };
+                $scope.circModifiers = circMods;
+                $scope.ok = function(args) { $modalInstance.close(args) }
+                $scope.cancel = function () { $modalInstance.dismiss() }
+            }],
+            resolve : {
+                circMods : function() { 
+                    return service.get_circ_mods();
+                }
+            }
+        }).result.then(
+            function(args) {
+                if (!args || !args.dummy_title) return $q.reject();
+                angular.forEach(args, function(val, key) {params[key] = val});
+                params.precat = true;
+                return service.checkout(params, options);
+            }
+        );
+    }
+
+    service.circ_exists_dialog = function(evt, params, options) {
+        $modal.open({
+            templateUrl: './circ/share/t_circ_exists_dialog',
+            controller: 
+                       ['$scope','$modalInstance','openCirc',
+                function($scope , $modalInstance , openCirc) {
+                $scope.circDate = openCirc.xact_start();
+                $scope.ok = function() { $modalInstance.close() }
+                $scope.cancel = function() { $modalInstance.dismiss() }
+            }],
+            resolve : {
+                // fetch the conflicting open circulation
+                openCirc : function() {
+                    return egCore.pcrud.search('circ', 
+                        {target_copy : evt.payload.copy.id()},
+                        {order_by : {circ : 'xact_start desc' }, limit : 1}
+                    );
+                }
+            }
+        }).result.then(
+            function() {
+                
+                return service.checkin(
+                    {barcode : params.copy_barcode, noop : true}
+                ).then(function(checkin_resp) {
+                    if (checkin_resp.evt.textcode == 'SUCCESS') {
+                        return service.checkout(params, options);
+                    } else {
+                        alert(egCore.evt.parse(evt));
+                        return $q.reject();
+                    }
+                });
+            }
+        );
+    }
+
+    service.handle_checkin_response = function(evt, params, options) {
+
+        var final_resp = {evt : evt, params : params, options : options};
+
+        var copy, hold, transit;
+        if (evt.payload) {
+            copy = evt.payload.copy;
+            hold = evt.payload.hold;
+            transit = evt.payload.transit;
+        }
+
+        // track the barcode regardless of whether it refers to a copy
+        evt.copy_barcode = params.copy_barcode;
+
+        switch (evt.textcode) {
+            case 'SUCCESS':
+            case 'NO_CHANGE':
+
+                // inform user if the item is on the local holds shelf
+                if (copy.status() == 8 // on holds shelf
+                    && hold 
+                    && hold.pickup_lib() == egCore.auth.user().ws_ou()) {
+                    return service.route_dialog(
+                        './circ/share/t_hold_shelf_dialog', 
+                        evt, params, options
+                    ).then(function() { return final_resp });
+
+                } else {
+                    return $q.when(final_resp);
+                }
+                
+            // show the route dialog
+            case 'ROUTE_ITEM':
+                return service.route_dialog(
+                    './circ/share/t_transit_dialog', 
+                    evt, params, options
+                ).then(function() { return final_resp });
+
+
+            // show the copy not found alert dialog
+            case 'ASSET_COPY_NOT_FOUND':
+                // FIXME: where can we put strings that don't live within
+                // a specific page?
+                return egAlertDialog.open(
+                    egCore.strings.UNCAT_ALERT_DIALOG, params)
+                    .result.then(function() {return final_resp});
+
+            case 'COPY_ALERT_MESSAGE':
+                // FIXME: where can we put strings that don't live within
+                // a specific page?
+
+                return egConfirmDialog.open(
+                    egCore.strings.COPY_ALERT_MSG_DIALOG_TITLE, 
+                    evt.payload,  // payload == alert message text
+                    {   copy_barcode : params.copy_barcode,
+                        ok : function() {},
+                        cancel : function() { 
+                            // TODO: do we return the final_resp so
+                            // the user can display the copy even though
+                            // the checkin did not take place?
+                        }
+                    }
+                ).result.then(function() {
+                    options.override = true;
+                    return service.checkin(params, options);
+                });
+
+            default:
+                console.warn('unhandled checkin response : ' + evt.textcode);
+                return $q.when(final_resp);
+        }
+    }
+
+    service.route_dialog = function(tmpl, evt, params, options) {
+        return $modal.open({
+            templateUrl: tmpl,
+            controller: [
+                '$scope', '$modalInstance', 'destAddr', 'holdUser',
+                function($scope, $modalInstance, destAddr, holdUser) {
+                $scope.destAddr = destAddr;
+                $scope.holdUser = holdUser;
+                $scope.dest = egCore.org.get(evt.org);
+                $scope.evt = evt;
+                $scope.now = new Date();
+                $scope.ok = function() {$modalInstance.close()}
+                $scope.print = function() {
+                    $modalInstance.close();
+
+                    var transit = evt.payload.transit;
+
+                    // flesh data into the transit to match the print template
+                    transit.target_copy(evt.payload.copy);
+                    transit.dest(egCore.org.get(transit.dest()));
+                    transit.dest().holds_address(destAddr);
+
+                    egCore.hatch.printFromTemplate('default', 'transit_slip', 
+                        {   transit : egCore.idl.toHash(transit),
+                            title : evt.payload.record.title(),
+                            author : evt.payload.record.author(),
+                            staff : egCore.idl.toHash(egCore.auth.user()),
+                            current_location : egCore.idl.toHash(
+                                egCore.org.get(egCore.auth.user().ws_ou()))
+                        }
+                    );
+
+                }
+            }],
+            resolve : {
+                destAddr : function() {
+                    if (!evt.org) return $q.when();
+                    return service.get_org_addr(evt.org, 'holds_address');
+                },
+                holdUser : function() {
+                    if (!evt.payload.hold) return $q.when();
+                    return egCore.pcrud.retrieve('au', 
+                        evt.payload.hold.usr(), {
+                            flesh : 1,
+                            flesh_fields : {'au' : ['card']}
+                        }
+                    );
+                }
+            }
+        }).result;
+    }
+
+
+    return service;
+
+}]);
+
+
diff --git a/Open-ILS/web/js/ui/default/staff/circ/services/circulate.js b/Open-ILS/web/js/ui/default/staff/circ/services/circulate.js
deleted file mode 100644 (file)
index e0d728d..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * Checkin, checkout, and renew
- */
-
-angular.module('egCoreMod')
-
-.factory('egCirc',
-
-       ['$modal','$q','egCore',
-function($modal , $q , egCore) {
-
-    var service = {
-        // auto-override these events after the first override
-        checkout_overrides : {},
-        org_addr_cache : {}
-    };
-
-    service.reset = function() {
-        service.checkout_overrides = {};
-    }
-
-    // Performs a checkout.
-    // Returns a promise resolved with the original params and options
-    // and the final checkout event (e.g. in the case of override).
-    // Rejected if the checkout cannot be completed.
-    service.checkout = function(params, options) {
-        if (!options) options = {};
-
-        console.debug('egCirc.checkout() : ' + js2JSON(params));
-
-        var method = 'open-ils.circ.checkout.full';
-        if (options.override) method += '.override';
-
-        return egCore.net.request(
-            'open-ils.circ', method, egCore.auth.token(), params
-
-        ).then(function(evt) {
-
-            if (angular.isArray(evt)) evt = evt[0];
-            return service.handle_checkout_resp(evt, args, override);
-        });
-    }
-
-    // Performs a renewal.
-    // Returns a promise resolved with the original params and options
-    // and the final checkout event (e.g. in the case of override)
-    // Rejected if the renewal cannot be completed.
-    service.renew = function(params, options) {
-        if (!options) options = {};
-
-        console.debug('egCirc.renew() : ' + js2JSON(params));
-
-        var method = 'open-ils.circ.renew';
-        if (options.override) method += '.override';
-
-        return egCore.net.request(
-            'open-ils.circ', method, egCore.auth.token(), params
-
-        ).then(function(evt) {
-
-            if (angular.isArray(evt)) evt = evt[0];
-            return service.handle_checkout_resp(evt, args, options);
-        });
-    }
-
-    // Performs a checkin
-    // Returns a promise resolved with the original params and options,
-    // plus the final checkin event (e.g. in the case of override).
-    // Rejected if the checkin cannot be completed.
-    service.checkin = function(params, options) {
-        if (!options) options = {};
-
-        var method = 'open-ils.circ.checkin';
-        if (options.override) method += '.override';
-
-        egCore.net.request(
-            'open-ils.circ', method, egCore.auth.token(), params
-
-        ).then(function(evt) {
-
-            if (angular.isArray(evt)) evt = evt[0];
-            return service.handle_checkin_response(evt, params, options);
-        });
-    }
-
-    service.handle_checkout_resp = function(evt, params, options) {
-
-        var final_resp = {evt : evt, params : params, options : options};
-
-        switch (evt.textcode) {
-            case 'SUCCESS':
-                return $q.when(final_resp);
-
-            case 'ITEM_NOT_CATALOGED':
-                return service.precat_dialog(params, options);
-
-            case 'PATRON_EXCEEDS_OVERDUE_COUNT':
-            case 'PATRON_EXCEEDS_FINES':
-            case 'PATRON_EXCEEDS_CHECKOUT_COUNT':
-            case 'PATRON_EXCEEDS_LOST_COUNT':
-                if (options.override) {
-                    // NOTE: I don't think we'll ever get here, since the
-                    // override attempt should produce a perm failure...
-                    console.debug('override failed: ' + evt.textcode);
-
-                } else {
-                    if (service.checkout_overrides[evt.textcode]) {
-                        // user has already opted to override this type
-                        // of event.  Re-run the checkout w/ override.
-                        options.override = true;
-                        return service.checkout(params, options);
-                    } else {
-                        // ask the user if they would like to override this
-                        // event type.
-                        return service.override_dialog(evt, params, options);
-                    }
-                }
-                break;
-
-            case 'OPEN_CIRCULATION_EXISTS':
-                return service.circ_exists_dialog(evt, params, options);
-
-            /* stuff to consider 
-            PERM_FAILURE
-            PATRON_BARRED
-            CIRC_EXCEEDS_COPY_RANGE
-            PATRON_ACCOUNT_EXPIRED
-            ITEM_DEPOSIT_REQUIRED
-            ITEM_RENTAL_FEE_REQUIRED
-            ITEM_DEPOSIT_PAID
-            ACTION_CIRCULATION_NOT_FOUND
-            PATRON_EXCEEDS_CHECKOUT_COUNT
-            COPY_CIRC_NOT_ALLOWED
-            COPY_NOT_AVAILABLE
-            COPY_IS_REFERENCE
-            COPY_NEEDED_FOR_HOLD
-            MAX_RENEWALS_REACHED
-            CIRC_CLAIMS_RETURNED
-            COPY_ALERT_MESSAGE
-            */
-
-            default:
-                console.warn('unhandled circ response : ' + evt.textcode);
-                return $q.when(final_resp);
-        }
-    }
-
-    // fetch the list of circ modifiers, from cache if available
-    service.get_circ_mods = function() {
-        if (egCore.env.ccm) {
-            return $q.when(egCore.env.ccm.list);
-        } else {
-            return egCore.pcrud.retrieveAll('ccm', null, {atomic : true})
-            .then(function(list) { 
-                egCore.env.absorbList(list, 'ccm');
-                return list;
-            });
-        }
-    };
-
-    // fetch/cache for org unit addresses
-    service.get_org_address = function(org_id, addr_type) {
-        if (service.org_addr_cache[org_id]) {
-            if (service.org_addr_cache[org_id][addr_type]) 
-                return $q.when(service.org_addr_cache[org_id][addr_type]);
-        } else {
-            service.org_addr_cache[org_id] = {};
-        }
-
-        return egCore.pcrud.retrieve('aoa', 
-            egCore.org.get(org_id)[addr_type]()
-        ).then(function(addr) {
-            return service.org_addr_cache[org_id][addr_type] = addr;
-        });
-    }
-
-    // opens a dialog asking the user if they would like to override
-    // the returned event.
-    service.override_dialog = function(evt, params, options) {
-        return $modal.open({
-            templateUrl: './circ/share/t_event_override_dialog',
-            controller: 
-                ['$scope', '$modalInstance', 
-                function($scope, $modalInstance) {
-                $scope.evt = evt;
-                $scope.ok = function() { $modalInstance.close() }
-                $scope.cancel = function () { $modalInstance.dismiss() }
-            }]
-        }).result.then(
-            function() {
-                service.checkout_overrides[evt.textcode] = true;
-                options.override = true;
-                return service.checkout(params, options);
-            }
-        );
-    }
-
-
-    // opens a dialog allowing the user to fill in pre-cat copy info
-    service.precat_dialog = function(params, options) {
-
-        return $modal.open({
-            templateUrl: './circ/share/t_precat_dialog',
-            controller: 
-                ['$scope', '$modalInstance', 'circMods',
-                function($scope, $modalInstance, circMods) {
-                $scope.focusMe = true;
-                $scope.precatArgs = {
-                    copy_barcode : params.copy_barcode,
-                    circ_modifier : circMods.length ? circMods[0].code() : null
-                };
-                $scope.circModifiers = circMods;
-                $scope.ok = function(args) { $modalInstance.close(args) }
-                $scope.cancel = function () { $modalInstance.dismiss() }
-            }],
-            resolve : {
-                circMods : function() { 
-                    return service.get_circ_mods();
-                }
-            }
-        }).result.then(
-            function(args) {
-                if (!args || !args.dummy_title) return $q.reject();
-                angular.forEach(args, function(val, key) {params[key] = val});
-                params.precat = true;
-                return service.checkout(params, options);
-            }
-        );
-    }
-
-    service.circ_exists_dialog = function(evt, params, options) {
-        $modal.open({
-            templateUrl: './circ/share/t_circ_exists_dialog',
-            controller: 
-                       ['$scope','$modalInstance','openCirc',
-                function($scope , $modalInstance , openCirc) {
-                $scope.circDate = openCirc.xact_start();
-                $scope.ok = function() { $modalInstance.close() }
-                $scope.cancel = function() { $modalInstance.dismiss() }
-            }],
-            resolve : {
-                // fetch the conflicting open circulation
-                openCirc : function() {
-                    return egCore.pcrud.search('circ', 
-                        {target_copy : evt.payload.copy.id()},
-                        {order_by : {circ : 'xact_start desc' }, limit : 1}
-                    );
-                }
-            }
-        }).result.then(
-            function() {
-                
-                return service.checkin(
-                    {barcode : params.copy_barcode, noop : true}
-                ).then(function(checkin_resp) {
-                    if (checkin_resp.evt.textcode == 'SUCCESS') {
-                        return service.checkout(params, options);
-                    } else {
-                        alert(egCore.evt.parse(evt));
-                        return $q.reject();
-                    }
-                });
-            }
-        );
-    }
-
-    service.handle_checkin_response = function(evt, params, options) {
-
-        var final_resp = {evt : evt, params : params, options : options};
-
-        var copy, hold, transit;
-        if (evt.payload) {
-            copy = evt.payload.copy;
-            hold = evt.payload.hold;
-            transit = evt.payload.transit;
-        }
-
-        switch (evt.textcode) {
-            case 'SUCCESS':
-            case 'NO_CHANGE':
-                if (copy.status() == 8) { // on holds shelf 
-                    if (hold && 
-                        hold.pickup_lib() == egCore.auth.user().ws_ou()) {
-                        // show dialog telling user the item is on the
-                        // local holds shelf
-                        return service.route_dialog(
-                            './circ/share/t_hold_shelf_dialog', 
-                            evt, params, options
-                        ).then(function() { return final_resp });
-                    } else {
-                        return $q.when(final_resp);
-                    }
-                }
-                
-            // show the route dialog
-            case 'ROUTE_ITEM':
-                return service.route_dialog(
-                    './circ/share/t_hold_shelf_dialog', 
-                    evt, params, options
-                ).then(function() { return final_resp });
-
-
-            // show the copy not found alert dialog
-            case 'ASSET_COPY_NOT_FOUND':
-                // FIXME: where can we put strings that don't live within
-                // a specific page?
-                return egAlertDialog.open(
-                    egCore.strings.UNCAT_ALERT_DIALOG, params)
-                    .result.then(function() {return final_resp});
-
-            case 'COPY_ALERT_MESSAGE':
-                // FIXME: where can we put strings that don't live within
-                // a specific page?
-
-                return egConfirmDialog.open(
-                    egCore.strings.COPY_ALERT_MSG_DIALOG_TITLE, 
-                    evt.payload,  // payload == alert message text
-                    {   copy_barcode : params.copy_barcode,
-                        ok : function() {},
-                        cancel : function() { 
-                            // TODO: do we return the final_resp so
-                            // the user can display the copy even though
-                            // the checkin did not take place?
-                        }
-                    }
-                ).result.then(function() {
-                    options.override = true;
-                    return service.checkin(params, options);
-                });
-
-            default:
-                console.warn('unhandled checkin response : ' + evt.textcode);
-                return $q.when(final_resp);
-        }
-    }
-
-}]);
-
-
index e673b5b..099aa0d 100644 (file)
@@ -237,6 +237,8 @@ angular.module('egCoreMod')
                         service.ingestPrintContent(contentType, content, {})
                         .then(function() { $window.print() });
                     } else {
+                        // HTML content is already ingested and accessible
+                        // within the page to the printer.  
                         $window.print();
                     }
                 }