web staff: initial checkin; egOrg.settings()
authorBill Erickson <berick@esilibrary.com>
Tue, 26 Nov 2013 22:13:32 +0000 (17:13 -0500)
committerBill Erickson <berick@esilibrary.com>
Tue, 26 Nov 2013 22:13:32 +0000 (17:13 -0500)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/circ/checkin/index.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/t_navbar.tt2
Open-ILS/src/templates/staff/t_splash.tt2
Open-ILS/web/js/ui/default/staff/circ/checkin/app.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/services/org.js

diff --git a/Open-ILS/src/templates/staff/circ/checkin/index.tt2 b/Open-ILS/src/templates/staff/circ/checkin/index.tt2
new file mode 100644 (file)
index 0000000..135a96e
--- /dev/null
@@ -0,0 +1,44 @@
+[%
+  WRAPPER "staff/t_base.tt2";
+  ctx.page_title = l("Check In"); 
+  ctx.page_app = "egCheckinApp";
+  ctx.page_ctrl = "CheckinCtrl";
+%]
+
+[% BLOCK APP_JS %]
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/list.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/checkin/app.js"></script>
+[% END %]
+
+<style>
+    /* MOVE ME */
+    .pad-horiz {padding : 0px 10px 0px 10px; }
+    .pad-vert {padding : 20px 0px 10px 0px;}
+    #patron-checkin-barcode { width: 18em; }
+</style>
+
+<!-- checkin form -->
+<div class="row pad-vert">
+  <div class="col-lg-10">
+    <div class="pad-horiz">
+      <form ng-submit="checkin(checkinArgs)">
+        <input focus-me="focusMe" ng-model="checkinArgs.copy_barcode" 
+          id="patron-checkin-barcode" type="text"/> 
+        <span class="pad-horiz"></span>
+        <input type="submit" value="[% l('Submit') %]"/>
+      </form>
+    </div>
+  </div>
+  <div class="col-lg-2 text-right">
+    <div class="btn-group text-left">
+      [% INCLUDE 'staff/parts/column_picker.tt2' listname='checkins' %]
+    </div>
+  </div>
+</div>
+
+[% INCLUDE 'staff/circ/checkin/t_checkin_table.tt2' %]
+
+
+[% END %]
diff --git a/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2 b/Open-ILS/src/templates/staff/circ/checkin/t_checkin_table.tt2
new file mode 100644 (file)
index 0000000..37c31f7
--- /dev/null
@@ -0,0 +1,50 @@
+
+[%
+# checkin table columns
+COLUMNS = [
+{label => l('Barcode'),    name => 'copy_barcode' display => 1},
+{label => l('Circ ID'),    name => 'payload.circ.id', display => 1},
+{label => l('Due Date'),   name => 'payload.circ.due_date' display => 1},
+# once we are handling all response types, we probably don't need to show 
+# Response.  Or, at least, make it more friendly / localizable
+{label => l('Response'),   name => 'textcode', display => 1},
+{label => l('Title'),      name => 'payload.record.title', display => 1},
+{label => l('Author'),     name => 'payload.record.author', display => 1},
+{label => l('Call Number'),name => 'payload.copy.call_number.label', display => 1},
+{label => l('Alert Msg'),  name => 'payload.copy.alert_message' display => 1},
+]
+%]
+
+<!-- tell JS about our columns so they can be dynamically managed -->
+<div ng-init="
+checkins.setColumns([
+[%- FOR col IN COLUMNS %]
+{label:'[% col.label %]',name:'[% col.name %]'[% IF col.display %],display:true[% END %]}[% IF !loop.last; ','; END -%]
+[% END %]
+])">
+</div>
+
+<div class="row">
+  <div class="col-lg-12">
+    <table class="table table-hover table-condensed table-striped">
+      <thead>
+        <tr>
+          <th>#</th>
+          <th ng-repeat="col in checkins.allColumns" 
+            ng-show="checkins.displayColumns[col.name]">
+            {{col.label}}
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr ng-repeat="checkin in checkins.items | reverse track by $index">
+          <td>{{checkins.count() - $index}}</td>
+          <td ng-repeat="col in checkins.allColumns" 
+            ng-show="checkins.displayColumns[col.name]">
+            {{checkins.fieldValue(checkin, col.name)}}
+          </td>
+        </tr>
+      </tbody>
+    </table>
+  </div>
+</div>
index c894220..f00855d 100644 (file)
@@ -9,7 +9,7 @@
   For icons, see http://getbootstrap.com/components/#glyphicons
 -->
 
-<div class="navbar navbar-default navbar-static-top" 
+<div id="top-navbar" class="navbar navbar-default navbar-static-top" 
     role="navigation" ng-controller="NavCtrl">
 
   <!-- navbar-header here needed for supporting angular-ui-bootstrap -->
               [% l('Patron Search') %]
             </a>
           </li>
+          <li>
+            <a href="./circ/checkin/index" target="_self">
+              <span class="glyphicon glyphicon-save"></span>
+              [% l('Check In') %]
+            </a>
+          </li>
           <li class="divider"></li>
           <li class="dropdown-header">Sub Menu Test</li>
           <li><a href="javascript:;">Test Item</a></li>
           data-toggle="dropdown"></a>
         <ul class="dropdown-menu">
           <li class="disabled"><a href="" ng-click="" target="_self">
+            <span class="glyphicon glyphicon-random"></span>
             [% l('Change Operator') %]</a></li>
-          <li><a href="./login" ng-click="logout()" 
-            target="_self">[% l('Log Out') %]</a></li>
+          <li>
+            <a href="./login" ng-click="logout()" target="_self">
+              <span class="glyphicon glyphicon-log-out"></span>
+              [% l('Log Out') %]
+            </a>
+          </li>
         </ul>
       </li>
     </ul>
index b1e3e19..bf8a7b7 100644 (file)
@@ -1,3 +1,10 @@
+<style>
+  /* TODO: move me */
+  #splash-nav .panel-body div {
+    padding-bottom: 10px;
+  }
+</style>
+
 <div class="container">
   <div class="row">
     <div class="col-lg-12 text-center">
@@ -5,7 +12,7 @@
     </div>
   </div>
   <br/>
-  <div class="row">
+  <div class="row" id="splash-nav">
 
     <div class="col-lg-4">
       <div class="panel panel-success">
         </div>
         <div class="panel-body">
           <div>
-            <img src="/xul/server/skin/media/images/portal/forward.png"/>
-            <a target="_self" href="./circ/patron/search">[% l('Check Out') %]</a>
+            <img src="/xul/server/skin/media/images/portal/retreivepatron.png"/>
+            <a target="_self" href="./circ/patron/search">[% l('Find Patrons') %]</a>
+          </div>
+          <div>
+            <img src="/xul/server/skin/media/images/portal/back.png"/>
+            <a target="_self" href="./circ/checkin/index">[% l('Check In Items') %]</a>
           </div>
         </div>
       </div>
diff --git a/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js b/Open-ILS/web/js/ui/default/staff/circ/checkin/app.js
new file mode 100644 (file)
index 0000000..c319f88
--- /dev/null
@@ -0,0 +1,79 @@
+angular.module('egCheckinApp', ['ngRoute', 'ui.bootstrap', 
+    'egCoreMod', 'egUiMod', 'egListMod', 'egUserMod'])
+
+.config(function($routeProvider, $locationProvider) {
+    $locationProvider.html5Mode(true);
+    // no routes needed 
+})
+
+/**
+ * checkin service
+ */
+.factory('checkinSvc',
+       ['$q','egList','egNet','egAuth','egUser','egEnv','egOrg','egList',
+function($q,  egList,  egNet,  egAuth,  egUser,  egEnv,  egOrg,  egList) {
+
+    var service = {};
+    service.checkins = egList.create();
+    return service;
+}])
+
+/**
+ * Manages checkin
+ * */
+.controller('CheckinCtrl',
+       ['$scope','egStartup','checkinSvc','egNet','egAuth',
+function($scope,  egStartup,  checkinSvc,  egNet,  egAuth) {
+
+    // run egStartup here since it's not handled via resolver
+    egStartup.go().then(
+        function() {
+            // handle post-startup business
+        }
+    );
+
+    $scope.focusMe = true;
+    $scope.checkins = checkinSvc.checkins;
+
+    $scope.checkin = function(args) {
+        performCheckin(angular.copy(args));
+        args.copy_barcode = ''; // reset UI
+    }
+
+    function performCheckin(args, override) {
+        var method = 'open-ils.circ.checkin';
+        if (override) method += '.override';
+
+        egNet.request('open-ils.circ', method, egAuth.token(), args)
+        .then(function(evt) {
+
+            if (!evt) { 
+                console.error('no checkin response received');
+                return;
+            }
+
+            if (angular.isArray(evt)) evt = evt[0];
+            evt.id = checkinSvc.checkins.count();
+            evt.copy_barcode = args.copy_barcode;
+            handleCheckinResponse(evt, args, override);
+        });
+    }
+
+    function handleCheckinResponse(evt, args, override) {
+
+        switch (evt.textcode) {
+            case 'SUCCESS':
+            case 'ROUTE_ITEM':
+            case 'ASSET_COPY_NOT_FOUND':
+                checkinSvc.checkins.items.push(evt);
+                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.
+                $scope.checkins.items.push(evt);
+        }
+    }
+}])
+
index 96b00d1..3e79386 100644 (file)
@@ -20,22 +20,11 @@ angular.module('egPatronApp', ['ngRoute', 'ui.bootstrap',
         // TODO: $inject array
         function(egAuth, egUser, egNet, egEnv, egPCRUD, egStartup, egOrg) {
 
-        // load needed org unit settings and munge the data into 
-        // key/value pairs for ease of use.
+        // fetch the org settings we care about during egStartup
+        // and toss them into egEnv as egEnv.aous[name] = value.
         egEnv.classLoaders.aous = function() {
-            return egNet.request(
-                'open-ils.actor',
-                'open-ils.actor.ou_setting.ancestor_default.batch',
-                egAuth.user().ws_ou(),
-                ['circ.obscure_dob'], 
-                egAuth.token()
-            ).then(function(blob) {
-                var settings = {};
-                angular.forEach(blob, function(val, key) {
-                    if (val) { settings[key] = val.value }
-                });
-                egEnv.aous = settings;
-            });
+            return egOrg.settings(['circ.obscure_dob'])
+            .then(function(settings) { egEnv.aous = settings });
         }
 
         egEnv.loadClasses.push('aous');
index c4071fc..b8a9cf0 100644 (file)
@@ -5,8 +5,9 @@
  */
 angular.module('egCoreMod')
 
-.factory('egOrg', ['egEnv', 'egAuth', 'egPCRUD',
-function(egEnv, egAuth, egPCRUD) { 
+.factory('egOrg', 
+       ['$q','egEnv','egAuth','egNet',
+function($q,  egEnv,  egAuth,  egNet) { 
 
     var service = {};
 
@@ -56,6 +57,29 @@ function(egEnv, egAuth, egPCRUD) {
         return list;
     }
 
+    // returns a promise, resolved with a hash of setting name =>
+    // setting value for the selected org unit.  Org unit defaults to 
+    // auth workstation org unit.
+    service.settings = function(names, ou_id) {
+        var deferred = $q.defer();
+        ou_id = ou_id || egAuth.user().ws_ou();
+        egNet.request(
+            'open-ils.actor',
+            'open-ils.actor.ou_setting.ancestor_default.batch',
+            ou_id, names, egAuth.token()
+        ).then(function(blob) {
+            var settings = {};
+            angular.forEach(blob, function(val, key) {
+                // val is either null or a structure containing 
+                // the value
+                if (val) { settings[key] = val.value }
+            });
+            deferred.resolve(settings);
+        });
+        return deferred.promise;
+    }
+
+
     return service;
 }]);