initial steps to moving circ actions into service
authorBill Erickson <berick@esilibrary.com>
Wed, 11 Jun 2014 15:46:37 +0000 (11:46 -0400)
committerBill Erickson <berick@esilibrary.com>
Wed, 11 Jun 2014 15:46:37 +0000 (11:46 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/circ/checkin/t_hold_shelf_dialog.tt2 [deleted file]
Open-ILS/src/templates/staff/circ/checkin/t_transit_dialog.tt2 [deleted file]
Open-ILS/src/templates/staff/circ/patron/t_circ_exists_dialog.tt2 [deleted file]
Open-ILS/src/templates/staff/circ/patron/t_event_override_dialog.tt2 [deleted file]
Open-ILS/src/templates/staff/circ/patron/t_precat_dialog.tt2 [deleted file]
Open-ILS/src/templates/staff/circ/share/t_circ_exists_dialog.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/share/t_event_override_dialog.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/share/t_hold_shelf_dialog.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/share/t_precat_dialog.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/share/t_transit_dialog.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/circ/services/circulate.js [new file with mode: 0644]

diff --git a/Open-ILS/src/templates/staff/circ/checkin/t_hold_shelf_dialog.tt2 b/Open-ILS/src/templates/staff/circ/checkin/t_hold_shelf_dialog.tt2
deleted file mode 100644 (file)
index bcea59d..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<div class="">
-  <div class="modal-header">
-    <button type="button" class="close" 
-      ng-click="ok()" aria-hidden="true">&times;</button>
-    <h4 class="modal-title">[% l('Hold Slip') %]</h4>
-  </div>
-  <div class="modal-body">
-    <!-- TODO: pub / priv shelf -->
-    <div ng-switch on="evt.payload.hold.behind_desk()">
-      <div ng-switch-when="t">
-        [% l('This item should be routed to the Private Holds Shelf') %]
-      </div>
-      <div ng-switch-when="f">
-        [% l('This item should be routed to the Public Holds Shelf') %]
-      </div>
-    </div>
-    <br/>
-    <div>
-      <span>[% l('Item Barcode:') %]</span>
-      <span>{{evt.payload.copy.barcode()}}</span>
-    </div>
-    <div>
-      <span>[% l('Title:') %]</span>
-      <span>{{evt.payload.record.title()}}</span>
-    </div>
-    <div>
-      <span>[% l('Author:') %]</span>
-      <span>{{evt.payload.record.author()}}</span>
-    </div>
-    <br/>
-    <div>
-    
-    <div ng-show="holdUser.alias()">
-      [% l('Hold for patron {{holdUser.alias()}}') %]
-    </div>
-    <div ng-hide="holdUser.alias()">
-      [% |l %]
-      Hold for patron {{holdUser.family_name()}}, 
-      {{holdUser.first_given_name()}} {{holdUser.second_given_name()}}
-      [% END %]
-    </div>
-    <div>
-      <span>[% l('Patron Barcode:') %]</span>
-      <span>{{holdUser.card().barcode()}}</span>
-    </div>
-    <br/>
-    <div>
-      <span>[% l('Request Date:') %]</span>
-      <span>{{evt.payload.hold.request_time() | date:'shortDate'}}</span>
-    </div>
-    <div>
-      <span>[% l('Slip Date:') %]</span>
-      <span>{{now | date:'shortDate'}}</span>
-    </div>
-  </div>
-  <div class="modal-footer">
-    <!--
-    <input type="button" class="btn btn-primary" disabled="disabled"
-      ng-click="print()" value="[% l('Print') %]"/>
-    -->
-    <input type="submit" class="btn btn-warning"
-      ng-click="ok()" value="[% l('Do Not Print') %]"/>
-  </div>
-</div>
diff --git a/Open-ILS/src/templates/staff/circ/checkin/t_transit_dialog.tt2 b/Open-ILS/src/templates/staff/circ/checkin/t_transit_dialog.tt2
deleted file mode 100644 (file)
index 7d53a83..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-<div class="">
-  <div class="">
-    <div class="modal-header">
-      <button type="button" class="close" 
-        ng-click="ok()" aria-hidden="true">&times;</button>
-      <h4 class="modal-title">[% l('Transit Slip') %]</h4>
-    </div>
-    <div class="modal-body">
-      <div>
-        <span>[% l('Destination') %]</span>
-        <strong>{{dest.shortname()}}</strong>
-      </div>
-      <br/>
-      <div>
-        <address>
-          <strong>{{dest.name()}}</strong><br>
-          {{destAddr.street1()}} {{destAddr.street2()}}<br/>
-          {{destAddr.city()}}, {{destAddr.state()}} {{destAddr.post_code()}}<br/>
-          <abbr title="[% l('Phone') %]">P:</abbr> {{dest.phone()}}
-        </address>
-      </div>
-      <div>
-        <span>[% l('Item Barcode:') %]</span>
-        <span>{{evt.payload.copy.barcode()}}</span>
-      </div>
-      <div>
-        <span>[% l('Title:') %]</span>
-        <span>{{evt.payload.record.title()}}</span>
-      </div>
-      <div>
-        <span>[% l('Author:') %]</span>
-        <span>{{evt.payload.record.author()}}</span>
-      </div>
-      <div ng-if="holdUser">
-        <br/>
-        <div>[% |l %]
-          Hold for patron {{holdUser.family_name()}}, 
-          {{holdUser.first_given_name()}} {{holdUser.second_given_name()}}
-          [% END %]
-        </div>
-        <div>
-          <span>[% l('Patron Barcode:') %]</span>
-          <span>{{holdUser.card().barcode()}}</span>
-        </div>
-        <br/>
-        <div>
-          <span>[% l('Request Date:') %]</span>
-          <span>{{evt.payload.hold.request_time() | date:'shortDate'}}</span>
-        </div>
-        <div>
-          <span>[% l('Slip Date:') %]</span>
-          <span>{{now | date:'shortDate'}}</span>
-        </div>
-      </div>
-    </div>
-    <div class="modal-footer">
-      <!--
-      <input type="button" class="btn btn-primary" disabled="disabled"
-        ng-click="print()" value="[% l('Print') %]"/>
-        -->
-      <input type="submit" class="btn btn-warning"
-        ng-click="ok()" value="[% l('Do Not Print') %]"/>
-    </div>
-  </div>
-</div>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_circ_exists_dialog.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_circ_exists_dialog.tt2
deleted file mode 100644 (file)
index b1a3023..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<form class="form-validated" novalidate ng-submit="ok()" name="form">
-  <div>
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" 
-          ng-click="cancel()" aria-hidden="true">&times;</button>
-        <h4 class="modal-title">[% l('Open Circulation') %]</h4>
-      </div>
-      <div class="modal-body">
-[% |l("{{circDate | date:'shortDate'}}") %]
-There is an open circulation on the requested item.  
-This copy was checked out by another patron on [_1].
-[% END %]
-      </div>
-      <div class="modal-footer">
-        <button class="btn btn-warning" 
-            ng-click="cancel($event)">[% l('Cancel') %]</button>
-        <input type="submit" class="btn btn-primary" 
-            value="[% l('Normal Checkin then Checkout') %]"/>
-      </div>
-    </div> <!-- modal-content -->
-  </div> <!-- modal-dialog -->
-</form>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_event_override_dialog.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_event_override_dialog.tt2
deleted file mode 100644 (file)
index 7ff0a79..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<form class="form-validated" novalidate ng-submit="ok()" name="form">
-  <div class="modal-dialog">
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" 
-          ng-click="cancel()" aria-hidden="true">&times;</button>
-        <h4 class="modal-title">
-          [% l('Exceptions occurred during checkout.') %]
-        </h4>
-      </div>
-      <div class="modal-body">
-        <div class="panel panel-danger">
-          <div class="panel-heading">{{evt.textcode}}</div>
-          <div class="panel-body">{{evt.desc}}</div>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <i>[% |l %]
-If overridden, subsequent checkouts during this patron's session will
-auto-override this event[% END %]</i><!--'vim-->
-        <br/><br/>
-        <input type="submit" class="btn btn-primary" 
-            value="[% l('Force Checkout?') %]"/>
-        <button class="btn btn-warning" 
-            ng-click="cancel()">[% l('Cancel') %]</button>
-      </div>
-    </div> <!-- modal-content -->
-  </div> <!-- modal-dialog -->
-</form>
diff --git a/Open-ILS/src/templates/staff/circ/patron/t_precat_dialog.tt2 b/Open-ILS/src/templates/staff/circ/patron/t_precat_dialog.tt2
deleted file mode 100644 (file)
index 8676bf7..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<!-- edit bucket dialog -->
-<form class="form-validated" novalidate ng-submit="ok(precatArgs)" name="form">
-  <div class="">
-    <div class="modal-content">
-      <div class="modal-header">
-        <button type="button" class="close" 
-          ng-click="cancel()" aria-hidden="true">&times;</button>
-        <h4 class="modal-title">
-          [% l('Barcode "{{precatArgs.copy_barcode}}" was mis-scanned or is a non-cataloged item.') %]
-        </h4>
-      </div>
-      <div class="modal-body">
-        <div class="form-group">
-          <label for="precat-title">[% l('Title') %]</label>
-          <input type="text" class="form-control" focus-me='focusMe' required
-            id="precat-title" ng-model="precatArgs.dummy_title" placeholder="[% l('Title...') %]"/>
-        </div>
-        <div class="form-group">
-          <label for="precat-author">[% l('Author') %]</label>
-          <input type="text" class="form-control" id="precat-author"
-            ng-model="precatArgs.dummy_author" placeholder="[% l('Author...') %]"/>
-        </div>
-        <div class="form-group">
-          <label for="precat-isbn">[% l('ISBN') %]</label>
-          <input type="text" class="form-control" id="precat-isbn"
-            ng-model="precatArgs.dummy_isbn" placeholder="[% l('ISBN...') %]"/>
-        </div>
-        <div class="form-group">
-          <label for="precat-circmod">[% l('Circulation Modifier') %]</label>
-          <select class="form-control" id="precat-circmod" 
-            ng-model="precatArgs.circ_modifier">
-            <option ng-repeat="mod in circModifiers" 
-              value="{{mod.code()}}">{{mod.name()}}</option>
-          </select>
-        </div>
-      </div>
-      <div class="modal-footer">
-        <input type="submit" class="btn btn-primary" 
-            ng-disabled="form.$invalid" value="[% l('Precat Checkout') %]"/>
-        <button class="btn btn-warning" ng-click="cancel()"
-            ng-class="{disabled : actionPending}">[% l('Cancel') %]</button>
-      </div>
-    </div> <!-- modal-content -->
-  </div> <!-- modal-dialog -->
-</form>
diff --git a/Open-ILS/src/templates/staff/circ/share/t_circ_exists_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_circ_exists_dialog.tt2
new file mode 100644 (file)
index 0000000..f7516f0
--- /dev/null
@@ -0,0 +1,23 @@
+<form class="form-validated" novalidate ng-submit="ok()" name="form">
+  <div>
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" 
+          ng-click="cancel()" aria-hidden="true">&times;</button>
+        <h4 class="modal-title">[% l('Open Circulation') %]</h4>
+      </div>
+      <div class="modal-body">
+[% |l("{{circDate | date:'shortDate'}}") %]
+There is an open circulation on the requested item.  
+This copy was checked out by another patron on [_1].
+[% END %]
+      </div>
+      <div class="modal-footer">
+        <input type="submit" class="btn btn-primary" 
+            value="[% l('Normal Checkin then Checkout') %]"/>
+        <button class="btn btn-warning" 
+            ng-click="cancel($event)">[% l('Cancel') %]</button>
+      </div>
+    </div> <!-- modal-content -->
+  </div> <!-- modal-dialog -->
+</form>
diff --git a/Open-ILS/src/templates/staff/circ/share/t_event_override_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_event_override_dialog.tt2
new file mode 100644 (file)
index 0000000..7ff0a79
--- /dev/null
@@ -0,0 +1,29 @@
+<form class="form-validated" novalidate ng-submit="ok()" name="form">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" 
+          ng-click="cancel()" aria-hidden="true">&times;</button>
+        <h4 class="modal-title">
+          [% l('Exceptions occurred during checkout.') %]
+        </h4>
+      </div>
+      <div class="modal-body">
+        <div class="panel panel-danger">
+          <div class="panel-heading">{{evt.textcode}}</div>
+          <div class="panel-body">{{evt.desc}}</div>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <i>[% |l %]
+If overridden, subsequent checkouts during this patron's session will
+auto-override this event[% END %]</i><!--'vim-->
+        <br/><br/>
+        <input type="submit" class="btn btn-primary" 
+            value="[% l('Force Checkout?') %]"/>
+        <button class="btn btn-warning" 
+            ng-click="cancel()">[% l('Cancel') %]</button>
+      </div>
+    </div> <!-- modal-content -->
+  </div> <!-- modal-dialog -->
+</form>
diff --git a/Open-ILS/src/templates/staff/circ/share/t_hold_shelf_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_hold_shelf_dialog.tt2
new file mode 100644 (file)
index 0000000..bcea59d
--- /dev/null
@@ -0,0 +1,64 @@
+<div class="">
+  <div class="modal-header">
+    <button type="button" class="close" 
+      ng-click="ok()" aria-hidden="true">&times;</button>
+    <h4 class="modal-title">[% l('Hold Slip') %]</h4>
+  </div>
+  <div class="modal-body">
+    <!-- TODO: pub / priv shelf -->
+    <div ng-switch on="evt.payload.hold.behind_desk()">
+      <div ng-switch-when="t">
+        [% l('This item should be routed to the Private Holds Shelf') %]
+      </div>
+      <div ng-switch-when="f">
+        [% l('This item should be routed to the Public Holds Shelf') %]
+      </div>
+    </div>
+    <br/>
+    <div>
+      <span>[% l('Item Barcode:') %]</span>
+      <span>{{evt.payload.copy.barcode()}}</span>
+    </div>
+    <div>
+      <span>[% l('Title:') %]</span>
+      <span>{{evt.payload.record.title()}}</span>
+    </div>
+    <div>
+      <span>[% l('Author:') %]</span>
+      <span>{{evt.payload.record.author()}}</span>
+    </div>
+    <br/>
+    <div>
+    
+    <div ng-show="holdUser.alias()">
+      [% l('Hold for patron {{holdUser.alias()}}') %]
+    </div>
+    <div ng-hide="holdUser.alias()">
+      [% |l %]
+      Hold for patron {{holdUser.family_name()}}, 
+      {{holdUser.first_given_name()}} {{holdUser.second_given_name()}}
+      [% END %]
+    </div>
+    <div>
+      <span>[% l('Patron Barcode:') %]</span>
+      <span>{{holdUser.card().barcode()}}</span>
+    </div>
+    <br/>
+    <div>
+      <span>[% l('Request Date:') %]</span>
+      <span>{{evt.payload.hold.request_time() | date:'shortDate'}}</span>
+    </div>
+    <div>
+      <span>[% l('Slip Date:') %]</span>
+      <span>{{now | date:'shortDate'}}</span>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <!--
+    <input type="button" class="btn btn-primary" disabled="disabled"
+      ng-click="print()" value="[% l('Print') %]"/>
+    -->
+    <input type="submit" class="btn btn-warning"
+      ng-click="ok()" value="[% l('Do Not Print') %]"/>
+  </div>
+</div>
diff --git a/Open-ILS/src/templates/staff/circ/share/t_precat_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_precat_dialog.tt2
new file mode 100644 (file)
index 0000000..fc14ec3
--- /dev/null
@@ -0,0 +1,44 @@
+<!-- edit bucket dialog -->
+<form ng-submit="ok(precatArgs)" role="form">
+  <div class="">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" 
+          ng-click="cancel()" aria-hidden="true">&times;</button>
+        <h4 class="modal-title">
+          [% l('Barcode "{{precatArgs.copy_barcode}}" was mis-scanned or is a non-cataloged item.') %]
+        </h4>
+      </div>
+      <div class="modal-body">
+        <div class="form-group">
+          <label for="precat-title">[% l('Title') %]</label>
+          <input type="text" class="form-control" focus-me='focusMe' required
+            id="precat-title" ng-model="precatArgs.dummy_title" placeholder="[% l('Title...') %]"/>
+        </div>
+        <div class="form-group">
+          <label for="precat-author">[% l('Author') %]</label>
+          <input type="text" class="form-control" id="precat-author"
+            ng-model="precatArgs.dummy_author" placeholder="[% l('Author...') %]"/>
+        </div>
+        <div class="form-group">
+          <label for="precat-isbn">[% l('ISBN') %]</label>
+          <input type="text" class="form-control" id="precat-isbn"
+            ng-model="precatArgs.dummy_isbn" placeholder="[% l('ISBN...') %]"/>
+        </div>
+        <div class="form-group">
+          <label for="precat-circmod">[% l('Circulation Modifier') %]</label>
+          <select class="form-control" id="precat-circmod" 
+            ng-model="precatArgs.circ_modifier">
+            <option ng-repeat="mod in circModifiers" 
+              value="{{mod.code()}}">{{mod.name()}}</option>
+          </select>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <input type="submit" class="btn btn-primary" value="[% l('Precat Checkout') %]"/>
+        <button class="btn btn-warning" ng-click="cancel()"
+            ng-class="{disabled : actionPending}">[% l('Cancel') %]</button>
+      </div>
+    </div> <!-- modal-content -->
+  </div> <!-- modal-dialog -->
+</form>
diff --git a/Open-ILS/src/templates/staff/circ/share/t_transit_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_transit_dialog.tt2
new file mode 100644 (file)
index 0000000..7d53a83
--- /dev/null
@@ -0,0 +1,65 @@
+<div class="">
+  <div class="">
+    <div class="modal-header">
+      <button type="button" class="close" 
+        ng-click="ok()" aria-hidden="true">&times;</button>
+      <h4 class="modal-title">[% l('Transit Slip') %]</h4>
+    </div>
+    <div class="modal-body">
+      <div>
+        <span>[% l('Destination') %]</span>
+        <strong>{{dest.shortname()}}</strong>
+      </div>
+      <br/>
+      <div>
+        <address>
+          <strong>{{dest.name()}}</strong><br>
+          {{destAddr.street1()}} {{destAddr.street2()}}<br/>
+          {{destAddr.city()}}, {{destAddr.state()}} {{destAddr.post_code()}}<br/>
+          <abbr title="[% l('Phone') %]">P:</abbr> {{dest.phone()}}
+        </address>
+      </div>
+      <div>
+        <span>[% l('Item Barcode:') %]</span>
+        <span>{{evt.payload.copy.barcode()}}</span>
+      </div>
+      <div>
+        <span>[% l('Title:') %]</span>
+        <span>{{evt.payload.record.title()}}</span>
+      </div>
+      <div>
+        <span>[% l('Author:') %]</span>
+        <span>{{evt.payload.record.author()}}</span>
+      </div>
+      <div ng-if="holdUser">
+        <br/>
+        <div>[% |l %]
+          Hold for patron {{holdUser.family_name()}}, 
+          {{holdUser.first_given_name()}} {{holdUser.second_given_name()}}
+          [% END %]
+        </div>
+        <div>
+          <span>[% l('Patron Barcode:') %]</span>
+          <span>{{holdUser.card().barcode()}}</span>
+        </div>
+        <br/>
+        <div>
+          <span>[% l('Request Date:') %]</span>
+          <span>{{evt.payload.hold.request_time() | date:'shortDate'}}</span>
+        </div>
+        <div>
+          <span>[% l('Slip Date:') %]</span>
+          <span>{{now | date:'shortDate'}}</span>
+        </div>
+      </div>
+    </div>
+    <div class="modal-footer">
+      <!--
+      <input type="button" class="btn btn-primary" disabled="disabled"
+        ng-click="print()" value="[% l('Print') %]"/>
+        -->
+      <input type="submit" class="btn btn-warning"
+        ng-click="ok()" value="[% l('Do Not Print') %]"/>
+    </div>
+  </div>
+</div>
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
new file mode 100644 (file)
index 0000000..e0d728d
--- /dev/null
@@ -0,0 +1,339 @@
+/**
+ * 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);
+        }
+    }
+
+}]);
+
+