View Course Information on the Item Record
authorKyle Huckins <khuckins@catalyte.io>
Thu, 12 Dec 2019 21:57:34 +0000 (21:57 +0000)
committerJane Sandberg <sandbej@linnbenton.edu>
Mon, 7 Sep 2020 18:11:26 +0000 (11:11 -0700)
- Users with the MANAGE_RESERVES permission who are opted
into the course module can view a new Course Info tab on
the item record.
- Course Info tab displays a list of all courses(with link
to the Admin Course Page) item is associated with, and a
list of all instructors associated with those courses.
- Improvements to open-ils.circ.course_users.retrieve.

Signed-off-by: Kyle Huckins <khuckins@catalyte.io>
 Changes to be committed:
modified:   Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
new file:   Open-ILS/src/templates/staff/cat/item/t_course_pane.tt2
modified:   Open-ILS/src/templates/staff/cat/item/t_view.tt2
modified:   Open-ILS/web/js/ui/default/staff/cat/item/app.js

Open-ILS/src/perlmods/lib/OpenILS/Application/Circ.pm
Open-ILS/src/templates/staff/cat/item/t_course_pane.tt2 [new file with mode: 0644]
Open-ILS/src/templates/staff/cat/item/t_view.tt2
Open-ILS/web/js/ui/default/staff/cat/item/app.js

index 0a7c80f..7110a8b 100644 (file)
@@ -1169,7 +1169,7 @@ sub fetch_course_users {
         unless ($self->api_name =~ /\.staff/) and $e->allowed('MANAGE_RESERVES');
     
     
-    $users->{list} =  $e->search_asset_course_module_course_users($filter);
+    $users->{list} =  $e->search_asset_course_module_course_users($filter, {order_by => {acmcu => 'course'}});
     for my $course_user (@{$users->{list}}) {
         my $patron = {};
         $patron->{id} = $course_user->id;
@@ -1183,10 +1183,15 @@ sub fetch_course_users {
         my $final_user = {};
         $final_user->{id} = $user->{id};
         $final_user->{usr_role} = $user->{usr_role};
+        $final_user->{patron_id} = $user->{patron_data}->id;
         $final_user->{first_given_name} = $user->{patron_data}->first_given_name;
+        $final_user->{second_given_name} = $user->{patron_data}->second_given_name;
         $final_user->{family_name} = $user->{patron_data}->family_name;
         $final_user->{pref_first_given_name} = $user->{patron_data}->pref_first_given_name;
         $final_user->{pref_family_name} = $user->{patron_data}->pref_family_name;
+        $final_user->{pref_second_given_name} = $user->{patron_data}->pref_second_given_name;
+        $final_user->{pref_suffix} = $user->{patron_data}->pref_suffix;
+        $final_user->{pref_prefix} = $user->{patron_data}->pref_prefix;
         
         push @$targets, $final_user;
     }
diff --git a/Open-ILS/src/templates/staff/cat/item/t_course_pane.tt2 b/Open-ILS/src/templates/staff/cat/item/t_course_pane.tt2
new file mode 100644 (file)
index 0000000..befa04a
--- /dev/null
@@ -0,0 +1,72 @@
+<div class="col-md-12" ng-show="!has_course_perms">
+  <div class="alert alert-danger">
+    [% l('You do not have sufficient permissions to view this page') %]
+  </div>
+</div>
+
+<div ng-show="has_course_perms">
+  <div class="col-md-6" ng-show="!courses.length">
+    <div class="alert alert-info">
+      [% l('No Associated Courses') %]
+    </div>
+  </div>
+  <div class="col-md-6" ng-show="courses.length">
+    <div class="flex-row">
+      <div class="flex-cell flex-2 strong-text-2">
+        [% l('Associated Courses') %]
+      </div>
+    </div>
+
+    <div class="flex-row well well-sm" ng-repeat="course in courses">
+      <div class="flex-cell">
+        <a href="/eg2/staff/admin/local/asset/course_list/{{course.id()}}">{{course.course_number()}}: {{course.name()}}</a>
+      </div>
+  </div>
+</div>
+
+  <div class="col-md-6" ng-show="!instructors_exist">
+    <div class="alert alert-info">
+      [% l('No Associated Instructors') %]
+    </div>
+  </div>
+  <div class="col-md-6" ng-show="instructors_exist">
+    <div class="flex-row">
+      <div class="flex-cell flex-2 strong-text-2">
+        [% l('Associated Instructors') %]
+      </div>
+    </div>
+
+    <div class="flex-row" ng-repeat="(key, instructor) in instructors">
+      <div class="flex-cell">
+        <strong>
+        <span ng-if="instructor.pref_family_name">
+          {{instructor.pref_family_name}}, 
+        </span>
+        <span ng-if="!instructor.pref_family_name">
+          {{instructor.family_name}}, 
+        </span>
+        <span ng-if="instructor.pref_first_given_name">
+          {{instructor.pref_first_given_name}}
+        </span>
+        <span ng-if="!instructor.pref_first_given_name">
+          {{instructor.first_given_name}}
+        </span>
+        <span ng-if="instructor.pref_second_given_name">
+          {{instructor.pref_second_given_name}}
+        </span>
+        <span ng-if="!instructor.pref_second_given_name && instructor.second_given_name">
+          {{instructor.second_given_name}}
+        </span>
+        </strong>
+        <div class="well well-sm dt">
+          <div class="flex-row" ng-repeat="key in instructor._linked_course">
+            <div class="flex-cell">
+              <span>{{key.course}} </span> 
+              <span>({{key.role}})</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
index 1859865..bf9eaa4 100644 (file)
@@ -23,6 +23,9 @@
   <li ng-class="{active : tab == 'triggered_events'}">
     <a href="./cat/item/{{copy.id()}}/triggered_events">[% l('Triggered Events') %]</a>
   </li>
+  <li ng-class="{active : tab == 'course'}" ng-if="has_course_perms && courseModulesOptIn">
+    <a href="./cat/item/{{copy.id()}}/course">[% l('Course Info') %]</a>
+  </li>
 </ul>
 <div class="tab-content">
   <div class="tab-pane active">
index 2237d75..2995069 100644 (file)
@@ -777,21 +777,21 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
  * Detail view -- shows one copy
  */
 .controller('ViewCtrl', 
-       ['$scope','$q','$location','$routeParams','$timeout','$window','egCore','egItem','egBilling','egCirc',
-function($scope , $q , $location , $routeParams , $timeout , $window , egCore , itemSvc , egBilling , egCirc) {
+       ['$scope','$q','egGridDataProvider','$location','$routeParams','$timeout','$window','egCore','egItem','egBilling','egCirc',
+function($scope , $q , egGridDataProvider , $location , $routeParams , $timeout , $window , egCore , itemSvc , egBilling , egCirc) {
     var copyId = $routeParams.id;
     $scope.args.copyId = copyId;
     $scope.tab = $routeParams.tab || 'summary';
     $scope.context.page = 'detail';
     $scope.summaryRecord = null;
-
+    $scope.courseModulesOptIn = fetchCourseOptIn();
+    $scope.has_course_perms = fetchCoursePerms();
     $scope.edit = false;
     if ($scope.tab == 'edit') {
         $scope.tab = 'summary';
         $scope.edit = true;
     }
 
-
     // use the cached record info
     if (itemSvc.copy) {
         $scope.copy_alert_count = itemSvc.copy.copy_alerts().filter(function(aca) {
@@ -998,6 +998,27 @@ console.debug($scope.copy_alert_count);
         });
     }
 
+    // Check for Course Modules Opt-In to enable Course Info tab
+    function fetchCourseOptIn() {
+        return egCore.org.settings(
+            'circ.course_materials_opt_in'
+        ).then(function(set) {
+            $scope.courseModulesOptIn = set['circ.course_materials_opt_in'];
+
+            return $scope.courseModulesOptIn;
+        });
+    }
+
+    function fetchCoursePerms() {
+        return egCore.perm.hasPermAt('MANAGE RESERVES', true).then(function(orgIds) {
+            if(orgIds.indexOf(egCore.auth.user().ws_ou()) != -1){
+                $scope.has_course_perms = true;
+
+                return $scope.has_course_perms;
+            }
+        });
+    }
+
     $scope.addBilling = function(circ) {
         egBilling.showBillDialog({
             xact_id : circ.id(),
@@ -1172,6 +1193,47 @@ console.debug($scope.copy_alert_count);
         })
     }
 
+    function loadCourseInfo() {
+        delete $scope.courses;
+        delete $scope.instructors;
+        delete $scope.course_ids;
+        delete $scope.instructors_exist;
+        if (!copyId) return;
+        $scope.course_ids = [];
+        $scope.courses = [];
+        $scope.instructors = {};
+
+        egCore.pcrud.search('acmcm', {
+            item: copyId
+        }, {
+            flesh: 3,
+            flesh_fields: {
+                acmcm: ['course']
+            }, order_by: {acmc : 'id desc'}
+        }).then(null, null, function(material) {
+            
+            $scope.courses.push(material.course());
+            egCore.net.request(
+                'open-ils.circ',
+                'open-ils.circ.course_users.retrieve',
+                material.course().id()
+            ).then(null, null, function(instructors) {
+                angular.forEach(instructors, function(instructor) {
+                    var patron_id = instructor.patron_id.toString();
+                    if (!$scope.instructors[patron_id]) {
+                        $scope.instructors[patron_id] = instructor;
+                        $scope.instructors_exist = true;
+                        $scope.instructors[patron_id]._linked_course = [];
+                    }
+                    $scope.instructors[patron_id]._linked_course.push({
+                        role: instructor.usr_role,
+                        course: material.course().name()
+                    });
+                });
+            });
+        });
+    }
+
 
     // we don't need all data on all tabs, so fetch what's needed when needed.
     function loadTabData() {
@@ -1194,6 +1256,10 @@ console.debug($scope.copy_alert_count);
                 loadMostRecentTransit();
                 break;
 
+            case 'course':
+                loadCourseInfo();
+                break;
+
             case 'triggered_events':
                 var url = $location.absUrl().replace(/\/staff.*/, '/actor/user/event_log');
                 url += '?copy_id=' + encodeURIComponent(copyId);