webstaff: add subscription management pane
authorGalen Charlton <gmc@equinoxinitiative.org>
Fri, 21 Apr 2017 16:08:32 +0000 (12:08 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Tue, 30 May 2017 16:06:36 +0000 (12:06 -0400)
TODO: more precise dirty field detection
TODO: formatting of form
TODO: use something other than buttons to add distributions and streams?

Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/templates/staff/serials/t_manage.tt2
Open-ILS/web/js/ui/default/staff/serials/app.js

index 23c1cbb..566054c 100644 (file)
@@ -8,7 +8,69 @@
       <!-- note that non-numeric index values must be enclosed in single-quotes,
            otherwise selecting the active table won't work cleanly -->
       <uib-tab index="'create-subscription'" heading="[% l('Create Subscription') %]">
-        <p>Create Subscription TODO</p>
+<!-- TODO: move the subscription / distribution manager to separate template -->
+<form>
+  <div ng-repeat="ssub in subscriptions">
+    <div class="row col-md-12">
+      <div class="col-md-2">
+        <label>[% l('Owning Library') %]</label>
+        <eg-org-selector selected="ssub.owning_lib"></eg-org-selector>
+        <button class="btn btn-sm btn-primary" ng-click="add_distribution(ssub)">[% l('Add distribution') %]</button>
+      </div>
+      <div class="col-md-1">
+        <label>[% l('Start Date') %]</label>
+      </div>
+      <div class="col-md-2">
+        <eg-date-input ng-model="ssub.start_date"></eg-date-input>
+      </div>
+      <div class="col-md-1">
+        <label>[% l('End Date') %]</label>
+      </div>
+      <div class="col-md-2">
+        <eg-date-input ng-model="ssub.end_date"></eg-date-input>
+      </div>
+      <div class="col-md-3 form-inline">
+        <label>[% l('Expected Offset') %]</label>
+        <input type="text" ng-model="ssub.expected_offset"></input>
+      </div>
+    </div>
+    <div class="row" ng-repeat="sdist in ssub.distributions">
+      <div class="col-md-1"></div>
+      <div class="col-md-2">
+        <label>[% l('Library') %]</label>
+        <eg-org-selector selected="sdist.holding_lib"></eg-org-selector>
+      </div>
+      <div class="col-md-2 form-inline">
+        <label>[% l('Label') %]</label>
+        <input type="text" required ng-model="sdist.label"></input>
+      </div>
+      <div class="col-md-2">
+        <button class="btn btn-sm btn-primary" ng-click="add_stream(sdist)">[% l('Add copy stream') %]</button>
+      </div>
+      <div class="col-md-3">
+        <div class="row" ng-repeat="sstr in sdist.streams">
+            <div class="form-inline">
+              <label>[% l('Send to') %]</label>
+              <input type="text" ng-model="sstr.routing_label"></input>
+            </div>
+        </div>
+      </div>
+      <div class="col-md-2 form-inline">
+        <label>[% l('OPAC Display') %]</label>
+        <select ng-model="sdist.display_grouping">
+          <option value="chron">[% l('Chronological') %]</option>
+          <option value="enum" >[% l('Enumeration') %]</option>
+        </select>
+      </div>
+    </div>
+    <div class="row pad-vert"></div>
+  </div>
+  <div class="row">
+    <button class="btn btn-default pull-left" ng-click="add_subscription()">[% l('New Subscription') %]</button>
+    <button class="btn btn-primary pull-right" ng-click="save_subscriptions()">[% l('Save') %]</button>
+  </div>
+  <div class="row pad-vert"></div>
+</form>
 <!-- TODO: move the grid to a separate template file -->
 <div>
   <eg-grid
index 636f710..5c6510c 100644 (file)
@@ -35,6 +35,7 @@ function($scope , $routeParams , $location , $window , $q , egSerialsCoreSvc , e
     $scope.bib_id = $routeParams.bib_id;
     $scope.active_tab = $routeParams.active_tab ?  $routeParams.active_tab : 'create-subscription';
     egSerialsCoreSvc.fetch($scope.bib_id).then(function() {
+        $scope.subscriptions = egCore.idl.toTypedHash(egSerialsCoreSvc.subTree);
     });
     $scope.distStreamGridControls = {
         activateItem : function (item) { } // TODO
@@ -45,4 +46,90 @@ function($scope , $routeParams , $location , $window , $q , egSerialsCoreSvc , e
         }
     });
 
+    $scope.add_subscription = function() {
+        var new_ssub = egCore.idl.toTypedHash(new egCore.idl.ssub());
+        new_ssub._isnew = true;
+        new_ssub.record_entry = $scope.bib_id;
+        $scope.subscriptions.push(new_ssub);
+    }
+    $scope.add_distribution = function(ssub) {
+        var new_sdist = egCore.idl.toTypedHash(new egCore.idl.sdist());
+        new_sdist._isnew = true;
+        new_sdist.subscription = ssub.id;
+        if (!angular.isArray(ssub.distributions)){
+            ssub.distributions = [];
+        }
+        ssub.distributions.push(new_sdist);
+    }
+    $scope.add_stream = function(sdist) {
+        var new_sstr = egCore.idl.toTypedHash(new egCore.idl.sstr());
+        new_sstr.distribution = sdist.id;
+        new_sstr._isnew = true;
+        if (!angular.isArray(sdist.streams)){
+            sdist.streams = [];
+        }
+        sdist.streams.push(new_sstr);
+    }
+    $scope.save_subscriptions = function() {
+        // traverse through structure and set _ischanged
+        // TODO add more granular dirty input detection
+        angular.forEach($scope.subscriptions, function(ssub) {
+            if (!ssub._isnew) ssub._ischanged = true;
+            angular.forEach(ssub.distributions, function(sdist) {
+                if (!sdist._isnew) sdist._ischanged = true;
+                angular.forEach(sdist.streams, function(sstr) {
+                    if (!sstr._isnew) sstr._ischanged = true;
+                });
+            });
+        });
+
+        var obj = egCore.idl.fromTypedHash($scope.subscriptions);
+
+        // create a bunch of promises that each get resolved upon each
+        // CUD update; that way, we can know when the entire save
+        // operation is completed
+        var promises = [];
+        angular.forEach(obj, function(ssub) {
+            ssub._cud_done = $q.defer();
+            promises.push(ssub._cud_done.promise);
+            angular.forEach(ssub.distributions(), function(sdist) {
+                sdist._cud_done = $q.defer();
+                promises.push(sdist._cud_done.promise);
+                angular.forEach(sdist.streams(), function(sstr) {
+                    sstr._cud_done = $q.defer();
+                    promises.push(sstr._cud_done.promise);
+                });
+            });
+        });
+
+        angular.forEach(obj, function(ssub) {
+            ssub.owning_lib(ssub.owning_lib().id()); // deflesh
+            egCore.pcrud.apply(ssub).then(function(res) {
+                var ssub_id = (ssub.isnew() && angular.isObject(res)) ? res.id() : ssub.id();
+                angular.forEach(ssub.distributions(), function(sdist) {
+                    // set subscription ID just in case it's new
+                    sdist.holding_lib(sdist.holding_lib().id()); // deflesh
+                    sdist.subscription(ssub_id);
+                    egCore.pcrud.apply(sdist).then(function(res) {
+                        var sdist_id = (sdist.isnew() && angular.isObject(res)) ? res.id() : sdist.id();
+                        angular.forEach(sdist.streams(), function(sstr) {
+                            // set distribution ID just in case it's new
+                            sstr.distribution(sdist_id);
+                            egCore.pcrud.apply(sstr).then(function(res) {
+                                sstr._cud_done.resolve();
+                            });
+                        });
+                    });
+                    sdist._cud_done.resolve();
+                });
+                ssub._cud_done.resolve();
+            });
+        });
+        $q.all(promises).then(function(resolutions) {
+            egSerialsCoreSvc.fetch($scope.bib_id).then(function() {
+                $scope.subscriptions = egCore.idl.toTypedHash(egSerialsCoreSvc.subTree);
+                $scope.distStreamGridDataProvider.refresh();
+            });
+        });
+    }
 }])