LP#1373690 EDI attribute sets admin UI
authorBill Erickson <berickxx@gmail.com>
Wed, 8 Mar 2017 17:47:55 +0000 (12:47 -0500)
committerMike Rylander <mrylander@gmail.com>
Fri, 1 Sep 2017 17:13:30 +0000 (13:13 -0400)
1. Create new attribute sets
2. Rename attribute Sets.
3. Enable / Disable attributes for each attributes set.

Found under Admin -> Acquisitions -> EDI Attribute Sets.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/src/templates/staff/admin/acq/index.tt2
Open-ILS/src/templates/staff/admin/acq/t_edi_attr_set.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/admin/acq/t_splash.tt2
Open-ILS/src/templates/staff/css/style.css.tt2
Open-ILS/web/js/ui/default/staff/admin/acq/app.js
Open-ILS/web/js/ui/default/staff/services/pcrud.js
Open-ILS/web/js/ui/default/staff/services/ui.js

index f5a8b7a..4378935 100644 (file)
@@ -8,8 +8,16 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/admin/acq/app.js"></script>
 <link rel="stylesheet" href="[% ctx.base_path %]/staff/css/admin.css" />
+<script>
+angular.module('egCoreMod').run(['egStrings', function(s) {
+  s.ATTR_SET_SUCCESS = "[% l('Attribute Set Update Succeeded') %]";
+  s.ATTR_SET_ERROR = "[% l('Attribute Set Update Failed') %]";
+  s.ATTR_SET_DELETE_CONFIRM = "[% l('Delete Attribute Set?') %]";
+}]);
+</script>
 [% END %]
 
+
 <div ng-view></div>
 
 [% END %]
diff --git a/Open-ILS/src/templates/staff/admin/acq/t_edi_attr_set.tt2 b/Open-ILS/src/templates/staff/admin/acq/t_edi_attr_set.tt2
new file mode 100644 (file)
index 0000000..c70baef
--- /dev/null
@@ -0,0 +1,67 @@
+<div class="container-fluid" style="text-align:center">
+  <div class="alert alert-info alert-less-pad strong-text-2">
+    <span>[% l('EDI Attribute Sets') %]</span>
+  </div>
+</div>
+
+<div class="row">
+  <div class="col-md-4">
+    <div class="input-group">
+      <div class="input-group-btn" uib-dropdown>
+        <button type="button" class="btn btn-default" uib-dropdown-toggle>
+          [% l('Attribute Sets') %]
+          <span class="caret"></span>
+        </button>
+        <ul uib-dropdown-menu>
+          <li>
+            <a href='' ng-click="new_set()">
+              [% l('New Attribute Set...') %]</a>
+          </li>
+          <li class="divider"></li>
+          <li ng-repeat="set in attr_sets">
+            <a href='' ng-click="select_set(set)">{{set.label()}}</a>
+          </li>
+        </ul>
+      </div><!-- /btn-group -->
+      <input type="text" ng-if="!cur_attr_set"
+        class="form-control" disabled="disabled"
+        value="[% l('No Attribute Set Selected') %]"/>
+      <input type="text" ng-if="cur_attr_set"
+        class="form-control"
+        placeholder="[% l('Attribute Set Name...') %]"
+        ng-model-options="{ getterSetter: true }"
+        ng-model="cur_attr_set.label"/>
+    </div>
+  </div>
+  <div class="col-md-4">
+    <span class="pad-right">
+      <button class="btn btn-success" 
+        ng-disabled="save_in_progress"
+        ng-click="apply()">[% l('Apply Changes') %]</button>
+    </span>
+    <span class="pad-right">
+      <button class="btn btn-warning" 
+        ng-disabled="cur_attr_set_uses || save_in_progress"
+        ng-click="remove()">[% l('Delete Attribute Set') %]</button>
+    </span>
+    <span class="pad-right" style="font-style:italic">
+      [% l('Currently used by [_1] EDI account(s).', '{{cur_attr_set_uses}}') %]
+    </span>
+  </div>
+</div>
+
+<div class="pad-vert">
+  <div class="row" ng-repeat="attr in attrs | orderBy:'key()'"
+    ng-class="cur_attr_set._local_map[attr.key()] ? 'selected-row' : ''">
+    <div class="col-md-3">
+      <span class="pad-right-min">
+        <input type="checkbox" 
+          ng-model="cur_attr_set._local_map[attr.key()]"/>
+      </span>
+      <span>{{attr.key()}}</span>
+    </div>
+    <div class="col-md-9">{{attr.label()}}</div>
+  </div>
+</div>
+
+
index a873724..e9d2894 100644 (file)
@@ -19,6 +19,7 @@
     ,[ l('Distribution Formulas'), "./admin/acq/conify/distribution_formula" ]
     ,[ l('EDI Accounts'), "./admin/acq/conify/edi_account" ]
     ,[ l('EDI Messages'), "./admin/acq/po/edi_messages" ]
+    ,[ l('EDI Attribute Sets'), "./admin/acq/edi_attr_set" ]
     ,[ l('Exchange Rates'), "./admin/acq/conify/exchange_rate" ]
     ,[ l('Fund Tags'), "./admin/acq/conify/fund_tag" ]
     ,[ l('Funding Sources'), "./admin/acq/funding_source/list" ]
index 9aa3eda..2369cd4 100644 (file)
@@ -199,6 +199,13 @@ table.list tr.selected td { /* deprecated? */
   padding: 0px;
 }
 
+/* Useful for grid-like things that aren't proper grids.
+ * Mimics the grids color scheme. */
+.selected-row {
+  background-color: rgb(248, 248, 248);
+}
+
+
 /* ----------------------------------------------------------------------
  * Grid
  * ---------------------------------------------------------------------- */
index 14dbe84..de8dddc 100644 (file)
@@ -8,6 +8,12 @@ angular.module('egAcqAdmin',
     $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); 
     var resolver = {delay : function(egStartup) {return egStartup.go()}};
 
+    $routeProvider.when('/admin/acq/edi_attr_set', {
+        templateUrl: './admin/acq/t_edi_attr_set',
+        controller: 'EDIAttrSet',
+        resolve : resolver
+    });
+
     var eframe_template = 
         '<eg-embed-frame allow-escape="true" min-height="min_height" url="acq_admin_url" handlers="funcs"></eg-embed-frame>';
 
@@ -60,3 +66,189 @@ function($scope , $routeParams , $location , egCore) {
 
 }])
 
+.controller('EDIAttrSet',
+       ['$scope','$q','egCore','ngToast','egConfirmDialog',
+function($scope , $q , egCore , ngToast , egConfirmDialog) {
+    
+    $scope.cur_attr_set = null;
+
+    // fetch all the data needed to render the page.
+    function load_data() {
+
+        return egCore.pcrud.retrieveAll('aea', {}, 
+            {atomic : true, authoritative : true})
+        .then(
+            function(attrs) { 
+                $scope.attrs = attrs 
+                return egCore.pcrud.retrieveAll('aeas', 
+                    {flesh : 1, flesh_fields : {'aeas' : ['attr_maps']}}, 
+                    {atomic : true, authoritative : true}
+                )
+            }
+
+        ).then(function(sets) { 
+            $scope.attr_sets = sets.sort(function(a, b) {
+                return a.label() < b.label() ? -1 : 1;
+            });
+
+            // create a simple true/false attr_set => attr mapping
+            var select_me;
+            angular.forEach(sets, function(set) {
+                set._local_map = {};
+                angular.forEach(set.attr_maps(), function(map) {
+                    set._local_map[map.attr()] = true;
+                })
+
+                if ($scope.cur_attr_set && set.id() 
+                        == $scope.cur_attr_set.id()) {
+                    select_me = set;
+                }
+            });
+
+            $scope.select_set(select_me || $scope.attr_sets[0]);
+        });
+    }
+
+    function create_sets() {
+        var new_sets = $scope.attr_sets.filter(function(set) { 
+            if (set.isnew() && set.label()) {
+                console.debug('creating new set: ' + set.label());
+                return true;
+            } 
+            return false;
+        });
+
+        if (new_sets.length == 0) return $q.when();
+
+        // create the new attrs sets and collect the newly generated 
+        // ID in the local data store.
+        return egCore.pcrud.apply(new_sets).then(
+            null,
+            function() { 
+                $scope.attr_sets = $scope.attr_sets.filter(
+                    function(set) { return (set.label() && !set.isnew()) });
+                return $q.reject();
+            },
+            function(new_set) { 
+                var old_set = new_sets.filter(function(s) {
+                    return (s.isnew() && s.label() == new_set.label()) })[0];
+                old_set.id(new_set.id());
+                old_set.isnew(false);
+            }
+        );
+    }
+
+    function modify_maps() {
+        var update_maps = [];
+
+        angular.forEach($scope.attr_sets, function(set) {
+            console.debug('inspecting attr set ' + set.label());
+
+            // find maps that need deleting
+            angular.forEach(set.attr_maps(), function(oldmap) {
+                if (!set._local_map[oldmap.attr()]) {
+                    console.debug('\tdeleting map for ' + oldmap.attr());
+                    oldmap.isdeleted(true);
+                    update_maps.push(oldmap);
+                }
+            });
+
+            // find maps that need creating
+            angular.forEach(set._local_map, function(value, key) {
+                if (!value) return;
+
+                var existing = set.attr_maps().filter(
+                    function(emap) { return emap.attr() == key })[0];
+
+                if (existing) return;
+
+                console.debug('\tcreating map for ' + key);
+
+                var newmap = new egCore.idl.aeasm();
+                newmap.isnew(true);
+                newmap.attr(key);
+                newmap.attr_set(set.id());
+                update_maps.push(newmap);
+            });
+        });
+
+        return egCore.pcrud.apply(update_maps);
+    }
+
+    // mark the currently selected attr set as the main display set.
+    $scope.select_set = function(set) {
+        $scope.cur_attr_set_uses = 0; // how many edi accounts use this set
+        if (set.isnew()) {
+            $scope.cur_attr_set = set;
+        } else {
+            egCore.pcrud.search('acqedi', {attr_set : set.id()}, {}, 
+                {idlist : true, atomic : true}
+            ).then(function(accts) {
+                $scope.cur_attr_set_uses = accts.length;
+                $scope.cur_attr_set = set;
+            });
+        }
+    }
+
+    $scope.new_set = function() {
+        var set = new egCore.idl.aeas();
+        set.isnew(true);
+        set.attr_maps([]);
+        set._local_map = {};
+        $scope.select_set(set);
+        $scope.attr_sets.push(set);
+    }
+
+    $scope.apply = function() {
+        $scope.save_in_progress = true;
+        create_sets()
+            .then(modify_maps)
+            .then(
+                function() { 
+                    ngToast.create(egCore.strings.ATTR_SET_SUCCESS) 
+                },
+                function() { 
+                    ngToast.warning(egCore.strings.ATTR_SET_ERROR);
+                    return $q.reject();
+                })
+            .then(load_data)
+            .finally(
+                function() { $scope.save_in_progress = false; }
+            );
+    }
+
+    // Delete the currently selected attr set.
+    // Attr set maps will cascade delete.
+    $scope.remove = function() {
+        egConfirmDialog.open(
+            egCore.strings.ATTR_SET_DELETE_CONFIRM, 
+            $scope.cur_attr_set.label()
+        ).result.then(function() {
+            $scope.save_in_progress = true;
+            (   // remove from server if necessary
+                $scope.cur_attr_set.isnew() ?
+                $q.when() :
+                egCore.pcrud.remove($scope.cur_attr_set)
+            ).then(
+                // remove from the local att_sets list
+                function() {
+                    ngToast.create(egCore.strings.ATTR_SET_SUCCESS);
+                    $scope.attr_sets = $scope.attr_sets.filter(
+                        function(set) {
+                            return set.id() != $scope.cur_attr_set.id() 
+                        }
+                    );
+                    $scope.cur_attr_set = $scope.attr_sets[0];
+                },
+                function() { ngToast.warning(egCore.strings.ATTR_SET_ERROR) }
+
+            ).finally(
+                function() { $scope.save_in_progress = false; }
+            );
+        });
+    }
+
+    load_data();
+}])
+
+
index 66fdba9..72cb94e 100644 (file)
@@ -91,7 +91,9 @@ angular.module('egCoreMod')
             this.session.disconnect();
         };
 
-        this.retrieve = function(fm_class, pkey, pcrud_ops) {
+        this.retrieve = function(fm_class, pkey, pcrud_ops, req_ops) {
+            req_ops = req_ops || {};
+            this.authoritative = req_ops.authoritative;
             return this._dispatch(
                 'open-ils.pcrud.retrieve.' + fm_class,
                 [egAuth.token(), pkey, pcrud_ops]
@@ -106,6 +108,7 @@ angular.module('egCoreMod')
 
         this.search = function (fm_class, search, pcrud_ops, req_ops) {
             req_ops = req_ops || {};
+            this.authoritative = req_ops.authoritative;
 
             var return_type = req_ops.idlist ? 'id_list' : 'search';
             var method = 'open-ils.pcrud.' + return_type + '.' + fm_class;
@@ -179,7 +182,7 @@ angular.module('egCoreMod')
                 },
 
                 // main body error handler
-                function() {}, 
+                function() {deferred.reject()}, 
 
                 // main body notify() handler
                 function(data) {deferred.notify(data)}
@@ -287,7 +290,8 @@ angular.module('egCoreMod')
                     self.cud_last = data;
                     self.cud_deferred.notify(data);
                     self._CUD_next_request();
-                }
+                },
+                self.cud_deferred.reject
             );
            
         };
index 51aac05..0c385fa 100644 (file)
@@ -398,6 +398,7 @@ function($uibModal, $interpolate) {
     var service = {};
 
     service.open = function(title, message, msg_scope, ok_button_label, cancel_button_label) {
+        msg_scope = msg_scope || {};
         return $uibModal.open({
             templateUrl: './share/t_confirm_dialog',
             controller: ['$scope', '$uibModalInstance',