webstaff: Additional Routing in serials grid
authorJason Etheridge <jason@esilibrary.com>
Thu, 20 Apr 2017 05:16:32 +0000 (01:16 -0400)
committerJason Etheridge <jason@esilibrary.com>
Fri, 21 Apr 2017 21:11:50 +0000 (17:11 -0400)
Signed-off-by: Jason Etheridge <jason@esilibrary.com>
Open-ILS/src/templates/staff/serials/t_manage.tt2
Open-ILS/src/templates/staff/serials/t_routing_list.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/serials/app.js

index 702975d..f4e4a38 100644 (file)
@@ -83,7 +83,7 @@
       label="[% l('Apply Receiving Template') %]"></eg-grid-action>
     <eg-grid-action handler="apply_binding_template"
       label="[% l('Apply Binding Template') %]"></eg-grid-action>
-    <eg-grid-action handler="additional_routing"
+    <eg-grid-action handler="additional_routing" disabled="need_one_selected"
       label="[% l('Additional Routing') %]"></eg-grid-action>
     <eg-grid-action handler="link_mfhd"
       label="[% l('Link MFHD') %]"></eg-grid-action>
diff --git a/Open-ILS/src/templates/staff/serials/t_routing_list.tt2 b/Open-ILS/src/templates/staff/serials/t_routing_list.tt2
new file mode 100644 (file)
index 0000000..b9518a4
--- /dev/null
@@ -0,0 +1,118 @@
+<form ng-submit="ok(args)" role="form">
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()" 
+        aria-hidden="true">&times;</button>
+    <h4 class="modal-title">
+        [% l('Manage Routing List for [_1]','{{stream_label}}') %]
+    </h4>
+</div>
+<style>
+/* odd/even row styling */
+.modal-header > div:nth-child(odd) {
+  background-color: rgb(248, 248, 248);
+}
+.strike {
+    text-decoration: line-through;
+}
+</style>
+<div class="modal-header">
+    <div ng-repeat="route in routes">
+        <div class="row">
+            <div class="col-md-2">
+                <span>
+                    [% l('[_1].','{{route.pos + 1}}') %]
+                </span>
+            </div>
+            <div class="col-md-8">
+                <span ng-show="route.reader" ng-class="route.delete_me ? 'strike' : ''">
+                {{route.reader.family_name}}, {{route.reader.first_given_name}}
+                ({{route.reader.home_ou.shortname}})
+                </span>
+                <span ng-show="route.department" ng-class="route.delete_me ? 'strike' : ''">
+                {{route.department}}
+                </span>
+            </div>
+            <div class="col-md-2">
+                <span>
+                    <a href ng-click="move_route_up(route)">&uarr;</a>
+                    <a href ng-click="move_route_down(route)">&darr;</a>
+                    <a href ng-click="toggle_delete(route)">&times;</a>
+                </span>
+            </div>
+        </div>
+        <div class="row">
+            <div class="col-md-2">
+            </div>
+            <div class="col-md-8" ng-class="route.delete_me ? 'strike' : ''">
+                {{route.note}}
+            </div>
+            <div class="col-md-2">
+            </div>
+        </div>
+    </div>
+</div>
+
+<div class="modal-body">
+    <div class="row">
+        <div class="col-md-1">
+            <input type="radio" name="which_radio_button"
+                ng-model="args.which_radio_button" value="reader">
+            </input>
+        </div>
+        <div class="col-md-3">
+            <label for="reader">
+                [% l('Reader (barcode):') %]
+            </label>
+        </div>
+        <div class="col-md-8">
+            <input type="textbox" ng-model="args.reader" id="reader"
+                ng-click="args.which_radio_button='reader'" focus-me="readerInFocus"
+                ng-model-options="{ debounce: 1000 }">
+            </input>
+            <span>{{reader_obj.family_name}}</span>
+            <span class="alert alert-warning" ng-show="readerNotFound">
+                [% l('Not Found') %]
+            </span>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-1">
+            <input type="radio" name="which_radio_button"
+                ng-model="args.which_radio_button" value="department">
+            </input>
+        </div>
+        <div class="col-md-3">
+            <label for="department">
+                [% l('Department:') %]
+            </label>
+        </div>
+        <div class="col-md-8">
+            <input type="textbox" ng-model="args.department" id="department"
+                ng-click="args.which_radio_button='department'">
+            </input>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col-md-1">
+        </div>
+        <div class="col-md-3">
+            <label for="note">[% l('Note:') %]</label>
+        </div>
+        <div class="col-md-8">
+            <input ng-model="args.note" type="textbox" id="note"></input>
+        </div>
+    </div>
+</div>
+
+<div class="modal-footer">
+    <button type="button" class="btn btn-primary pull-left"
+        ng-click="add_route()"
+        ng-disabled="(args[args.which_radio_button] == '')||(args.which_radio_button=='reader'&&readerNotFound)"
+    >
+        [% l('Add Route') %]
+    </button>
+    <input type="submit" class="btn btn-primary" ng-disabled="!model_has_changed"
+        value="[% l('Update') %]"></input>
+    <button class="btn btn-warning" ng-click="cancel()">[% l('Cancel') %]</button>
+</div>
+</form>
index 76de65a..c494e56 100644 (file)
@@ -28,9 +28,9 @@ angular.module('egSerialsApp', ['ui.bootstrap','ngRoute','egCoreMod','egGridMod'
 
 .controller('ManageCtrl',
        ['$scope','$routeParams','$location','$window','$q','egSerialsCoreSvc','egCore',
-        'egGridDataProvider',
+        'egGridDataProvider','$uibModal',
 function($scope , $routeParams , $location , $window , $q , egSerialsCoreSvc , egCore ,
-         egGridDataProvider
+         egGridDataProvider , $uibModal
 ) {
     $scope.bib_id = $routeParams.bib_id;
     $scope.active_tab = $routeParams.active_tab ?  $routeParams.active_tab : 'create-subscription';
@@ -53,6 +53,12 @@ function($scope , $routeParams , $location , $window , $q , egSerialsCoreSvc , e
         });
     }
 
+    $scope.need_one_selected = function() {
+        var items = $scope.distStreamGridControls.selectedItems();
+        if (items.length == 1) return false;
+        return true;
+    };
+
     $scope.add_subscription = function() {
         var new_ssub = egCore.idl.toTypedHash(new egCore.idl.ssub());
         new_ssub._isnew = true;
@@ -142,4 +148,168 @@ function($scope , $routeParams , $location , $window , $q , egSerialsCoreSvc , e
             form.$setPristine();
         });
     }
+    $scope.additional_routing = function(rows) {
+        if (!rows) { return; }
+        var row = rows[0];
+        if (!row) { row = $scope.distStreamGridControls.selectedItems()[0]; }
+        if (row && row['sstr.id']) {
+            egCore.pcrud.search('srlu', {
+                    stream : row['sstr.id']
+                }, {
+                    flesh : 2,
+                    flesh_fields : {
+                        'srlu' : ['reader'],
+                        'au'  : ['mailing_address','billing_address','home_ou']
+                    },
+                    order_by : { srlu : 'pos' }
+                },
+                { atomic : true }
+            ).then(function(list) {
+                $uibModal.open({
+                    templateUrl: './serials/t_routing_list',
+                    controller: 'RoutingCtrl',
+                    resolve : {
+                        rowInfo : function() {
+                            return row;
+                        },
+                        routes : function() {
+                            return egCore.idl.toHash(list);
+                        }
+                    }
+                }).result.then(function(routes) {
+                    // delete all of the routes first;
+                    // it's easiest given the constraints
+                    var deletions = [];
+                    var creations = [];
+                    angular.forEach(routes, function(r) {
+                        var srlu = new egCore.idl.srlu();
+                        srlu.stream(r.stream);
+                        srlu.pos(r.pos);
+                        if (r.reader) {
+                            srlu.reader(r.reader.id);
+                        }
+                        srlu.department(r.department);
+                        srlu.note(r.note);
+                        if (r.id) {
+                            srlu.id(r.id);
+                            var srlu_copy = angular.copy(srlu);
+                            srlu_copy.isdeleted(true);
+                            deletions.push(srlu_copy);
+                        }
+                        if (!r.delete_me) {
+                            srlu.isnew(true);
+                            creations.push(srlu);
+                        }
+                    });
+                    egCore.pcrud.apply(deletions.concat(creations)).then(function(){
+                        reload();
+                    });
+                });
+            });
+        }
+    }
+}])
+
+.controller('RoutingCtrl',
+       ['$scope','$uibModalInstance','egCore','rowInfo','routes',
+function($scope , $uibModalInstance , egCore , rowInfo , routes ) {
+    $scope.args = {
+         which_radio_button: 'reader'
+        ,reader: ''
+        ,department: ''
+        ,delete_me: false
+    };
+    $scope.stream_id = rowInfo['sstr.id'];
+    $scope.stream_label = rowInfo['sstr.routing_label'];
+    $scope.routes = routes;
+    $scope.readerInFocus = true;
+    $scope.ok = function(count) { $uibModalInstance.close($scope.routes) }
+    $scope.cancel = function () { $uibModalInstance.dismiss() }
+    $scope.model_has_changed = false;
+    $scope.find_user = function () {
+
+        $scope.readerNotFound = null;
+        $scope.reader_obj = null;
+        if (!$scope.args.reader) return;
+
+        egCore.net.request(
+            'open-ils.actor',
+            'open-ils.actor.get_barcodes',
+            egCore.auth.token(), egCore.auth.user().ws_ou(),
+            'actor', $scope.args.reader)
+
+        .then(function(resp) { // get_barcodes
+
+            if (evt = egCore.evt.parse(resp)) {
+                console.error(evt.toString());
+                return;
+            }
+
+            if (!resp || !resp[0]) {
+                $scope.readerNotFound = $scope.args.reader;
+                return;
+            }
+
+            egCore.pcrud.search('au', {
+                    id : resp[0].id
+                }, {
+                    flesh : 1,
+                    flesh_fields : {
+                        'au'  : ['mailing_address','billing_address','home_ou']
+                    }
+                },
+                { atomic : true }
+            ).then(function(usr) {
+                $scope.reader_obj = egCore.idl.toHash(usr[0]);
+            });
+        });
+    }
+    $scope.add_route = function () {
+        var new_route = {
+             stream: $scope.stream_id
+            ,pos: $scope.routes.length
+            ,note: $scope.args.note
+        }
+        if ($scope.args.which_radio_button == 'reader') {
+            new_route.reader = $scope.reader_obj;
+        } else {
+            new_route.department = $scope.args.department;
+        }
+        $scope.routes.push(new_route);
+        $scope.model_has_changed = true;
+    }
+    function adjust_pos_field() {
+        var idx = 0;
+        for (var i = 0; i < $scope.routes.length; i++) {
+            $scope.routes[i].pos = $scope.routes[i].delete_me ? idx : idx++;
+        }
+        $scope.model_has_changed = true;
+    }
+    $scope.move_route_up = function(r) {
+        var pos = r.pos;
+        if (pos > 0) {
+            var temp = $scope.routes[ pos - 1 ];
+            $scope.routes[ pos - 1 ] = $scope.routes[ pos ];
+            $scope.routes[ pos ] = temp;
+            adjust_pos_field();
+        }
+    }
+    $scope.move_route_down = function(r) {
+        var pos = r.pos;
+        if (pos < $scope.routes.length - 1) {
+            var temp = $scope.routes[ pos + 1 ];
+            $scope.routes[ pos + 1 ] = $scope.routes[ pos ];
+            $scope.routes[ pos ] = temp;
+            adjust_pos_field();
+        }
+    }
+    $scope.toggle_delete = function(r) {
+        r.delete_me = ! r.delete_me;
+        adjust_pos_field();
+    }
+    $scope.$watch("args.reader", function(newVal, oldVal) {
+        if (newVal && newVal != oldVal) {
+            $scope.find_user();
+        }
+    });
 }])