LP1849212: Allow users to detach all types of materials from courses
authorJane Sandberg <sandbej@linnbenton.edu>
Fri, 24 Jul 2020 20:16:25 +0000 (13:16 -0700)
committerJane Sandberg <sandbej@linnbenton.edu>
Wed, 26 Aug 2020 22:53:51 +0000 (15:53 -0700)
Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu>
Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts
Open-ILS/src/perlmods/lib/OpenILS/Application/Courses.pm
Open-ILS/src/perlmods/live_t/30-courses.t [deleted file]
Open-ILS/src/perlmods/live_t/31-courses.t [new file with mode: 0644]

index b50634f..5fdd404 100644 (file)
@@ -1,7 +1,6 @@
 import {Component, Input, ViewChild, OnInit, TemplateRef} from '@angular/core';
 import {ActivatedRoute} from '@angular/router';
-import {from, Observable} from 'rxjs';
-import {switchMap} from 'rxjs/operators';
+import {from, merge, Observable} from 'rxjs';
 import {DialogComponent} from '@eg/share/dialog/dialog.component';
 import {AuthService} from '@eg/core/auth.service';
 import {NetService} from '@eg/core/net.service';
@@ -206,24 +205,20 @@ export class CourseAssociateMaterialComponent extends DialogComponent implements
     }
 
     deleteSelectedMaterials(items) {
-        const item_ids = [];
+        const deleteRequest$ = [];
         items.forEach(item => {
-            this.materialsDataSource.data.splice(this.materialsDataSource.data.indexOf(item, 0), 1);
-            item_ids.push(item.id());
-        });
-        this.pcrud.search('acmcm', {course: this.courseId, item: item_ids}).subscribe(material => {
-            material.isdeleted(true);
-            this.pcrud.autoApply(material).subscribe(
-                val => {
-                    this.course.resetItemFields(material, this.currentCourse.owning_lib());
-                    console.debug('deleted: ' + val);
-                    this.materialDeleteSuccessString.current().then(str => this.toast.success(str));
-                },
-                err => {
-                    this.materialDeleteFailedString.current()
-                        .then(str => this.toast.danger(str));
-                }
-            );
+            deleteRequest$.push(this.net.request(
+                'open-ils.courses', 'open-ils.courses.detach_material',
+                this.auth.token(), item.id()));
         });
+        merge(...deleteRequest$).subscribe(
+            val => {
+                this.materialDeleteSuccessString.current().then(str => this.toast.success(str));
+            },
+            err => {
+                this.materialDeleteFailedString.current()
+                    .then(str => this.toast.danger(str));
+            }
+        );
     }
 }
index fe32164..a12831c 100644 (file)
@@ -45,7 +45,7 @@ sub attach_electronic_resource_to_course {
         }
     ]);
     return $e->event unless (($bib->source && $bib->source->transcendant) || $located_uris);
-    _attach_bib($e, $course, $record, $relationship);
+    _attach_bib($e, $course, $record, $relationship, 0);
 
     return 1;
 }
@@ -84,26 +84,22 @@ sub attach_brief_bib_to_course {
         ->request('open-ils.cat.biblio.record.xml.create',
             $authtoken, $marcxml, $bib_source_name)
         ->gather(1);
-    _attach_bib($e, $course, $bib_create->id, $relationship) if ($bib_create);
+    _attach_bib($e, $course, $bib_create->id, $relationship, 1) if ($bib_create);
     return 1;
 }
 
 # Shared logic for both e-resources and brief bibs
 sub _attach_bib {
-    my ($e, $course, $record, $relationship) = @_;
+    my ($e, $course, $record, $relationship, $temporary) = @_;
     my $acmcm = Fieldmapper::asset::course_module_course_materials->new;
     $acmcm->course($course);
     $acmcm->record($record);
     $acmcm->relationship($relationship);
+    $acmcm->temporary_record($temporary);
     $e->create_asset_course_module_course_materials( $acmcm ) or return $e->die_event;
     $e->commit;
 }
 
-sub detach_material_from_course {
-    my ($self, $conn, $authtoken, $acmcm) = @_;
-
-}
-
 __PACKAGE__->register_method(
     method          => 'fetch_course_materials',
     autoritative    => 1,
@@ -229,6 +225,79 @@ sub fetch_course_users {
 
 }
 
+__PACKAGE__->register_method(
+    method          => 'detach_material',
+    api_name        => 'open-ils.courses.detach_material',
+    signature => {
+        desc => 'Detaches a material from a course',
+        params => [
+            {desc => 'Authentication token', type => 'string'},
+            {desc => 'Course material id', type => 'number'},
+        ],
+        return => {desc => '1 on success, event on failure'}
+    });
+sub detach_material {
+    my ($self, $conn, $authtoken, $acmcm_id) = @_;
+    my $e = new_editor(authtoken=>$authtoken, xact=>1);
+    return $e->die_event unless $e->checkauth;
+    return $e->die_event unless
+        $e->allowed('MANAGE_RESERVES');
+    my $acmcm = $e->retrieve_asset_course_module_course_materials($acmcm_id)
+        or return $e->die_event;
+    my $bre_id_to_delete = $acmcm->temporary_record ? $acmcm->record : 0;
+    if ($bre_id_to_delete) {
+        # delete any attached located URIs
+        my $located_uri_cn_ids = $e->search_asset_call_number(
+            {record=>$bre_id_to_delete}, {idlist=>1});
+
+        for my $cn_id (@$located_uri_cn_ids) {
+            $e->delete_asset_call_number(
+                $e->retrieve_asset_call_number($cn_id))
+                or return $e->die_event;
+        }
+        OpenSRF::AppSession
+            ->create('open-ils.cat')
+            ->request('open-ils.cat.biblio.record_entry.delete',
+                $authtoken, $bre_id_to_delete);
+    }
+    if ($acmcm->item) {
+        _resetItemFields($e, $authtoken, $acmcm);
+    } 
+
+    $e->delete_asset_course_module_course_materials($acmcm) or return $e->die_event;
+    $e->commit;
+    return 1;
+}
+
+sub _resetItemFields {
+    my ($e, $authtoken, $acmcm) = @_;
+    my $cat_sess = OpenSRF::AppSession->connect('open-ils.cat');
+    my $acp = $e->retrieve_asset_copy($acmcm->item);
+    my $course_lib = $e->retrieve_asset_course_module_course($acmcm->course)->owning_lib;
+    if ($acmcm->original_status) {
+        $acp->status($acmcm->orginal_status);
+    }
+    if ($acmcm->original_circ_modifier) {
+        $acp->status($acmcm->orginal_circ_modifier);
+    }
+    if ($acmcm->original_location) {
+        $acp->status($acmcm->orginal_location);
+    }
+    $e->update_asset_copy($acmcm);
+    if ($acmcm->original_callnumber) {
+        my $existing_acn = $e->retrieve_asset_call_number($acp->call_number);
+        # Let's attach to an existing call number, if one exists with the original label
+        # and other appropriate specifications
+        my $acn_id = cat_sess->request('open-ils.cat.call_number.find_or_create',
+            $authtoken, $acmcm->original_callnumber,
+            $existing_acn->record, $course_lib,
+            $existing_acn->prefix, $existing_acn->suffix,
+            $existing_acn->label_class)->acn_id;
+        cat_sess->request('open-ils.cat.transfer_copies_to_volume',
+            $authtoken, $acn_id, [$acp->id]);
+    }
+}
+
 
 
 1;
diff --git a/Open-ILS/src/perlmods/live_t/30-courses.t b/Open-ILS/src/perlmods/live_t/30-courses.t
deleted file mode 100644 (file)
index 480206c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!perl
-use Test::More tests => 1;
-
-diag("Test the course materials module.");
-
-use strict; use warnings;
-
-use OpenILS::Utils::TestUtils;
-my $script = OpenILS::Utils::TestUtils->new();
-$script->bootstrap;
-
-our $apputils   = "OpenILS::Application::AppUtils";
-
-is(1, 1, 'placeholder');
-
-
-# Test: can attach a bib record with located URI
-# Test: cannot attach a bib record without a located URI
-
-# Test: can detach an item (just delete this)
-# Test: can detach a record that is not temporary (just delete this)
-# Test: can detach a record that is temporary (delete this, and delete the record too)
diff --git a/Open-ILS/src/perlmods/live_t/31-courses.t b/Open-ILS/src/perlmods/live_t/31-courses.t
new file mode 100644 (file)
index 0000000..da14e65
--- /dev/null
@@ -0,0 +1,82 @@
+#!perl
+use strict; use warnings;
+use Test::More tests => 3;
+use OpenILS::Utils::TestUtils;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Application::AppUtils;
+
+diag("Test the course materials module.");
+
+my $script = OpenILS::Utils::TestUtils->new();
+our $apputils = 'OpenILS::Application::AppUtils';
+
+# we need auth to access protected APIs
+$script->authenticate({
+    username => 'admin',
+    password => 'demo123',
+    type => 'staff'});
+
+my $authtoken = $script->authtoken;
+ok($authtoken, 'Have an authtoken');
+
+my $e = new_editor(xact => 1);
+$e->init;
+
+
+# -----------------------------------------------------------------------------
+# 1. Let's attach an existing biblio record entry to course #1, then delete it
+# -----------------------------------------------------------------------------
+
+my $acmcm = Fieldmapper::asset::course_module_course_materials->new;
+$acmcm->course(1);
+$acmcm->id(9999);
+$acmcm->record(55);
+$acmcm->temporary_record(0);
+$e->create_asset_course_module_course_materials( $acmcm ); # associated this bib record with a course
+$e->commit;
+
+$apputils->simplereq('open-ils.courses', 'open-ils.courses.detach.material', $authtoken, 9999);
+
+my $results = $e->search_asset_course_module_course_materials({id => 9999});
+is(scalar(@$results), 0, 'Successfully deleted acmcm');
+
+$results = $e->search_biblio_record_entry({id => 55, deleted => 0});
+
+is(scalar(@$results), 1,
+    'Did not inadvertantly delete bre');
+
+
+# -----------------------------------------------------------------------------
+# 2. Let's create a brief temporary bib record, attach it to course #1, then detach it
+# -----------------------------------------------------------------------------
+
+my $temp_tcn_source = 'temporary bib record for course materials module test';
+
+$e->xact_begin;
+my $bre = Fieldmapper::biblio::record_entry->new;
+$bre->marc('<record></record>');
+$bre->tcn_source($temp_tcn_source); #Use the tcn_source field, since Cstore rewrites the last_xact_id field
+$e->create_biblio_record_entry($bre);
+$e->commit;
+
+my $bib_id = $e->search_biblio_record_entry({tcn_source=>$temp_tcn_source}, {idlist=>1})->[0];
+
+$e->xact_begin;
+$acmcm = Fieldmapper::asset::course_module_course_materials->new;
+$acmcm->course(1);
+$acmcm->id(9998);
+$acmcm->record($bib_id);
+$acmcm->temporary_record(1); # this one is temporary, like brief records created in the course module interface
+$e->create_asset_course_module_course_materials( $acmcm ); # associated this bib record with a course
+$e->commit;
+
+$apputils->simplereq('open-ils.courses', 'open-ils.courses.detach.material', $authtoken, 9998);
+
+$results = $e->search_asset_course_module_course_materials({id => 9998});
+is(scalar(@$results), 0, 'Successfully deleted acmcm');
+
+$results = $e->search_biblio_record_entry({tcn_source=>$temp_tcn_source,deleted=>0});
+is(scalar(@$results), 0, 'Successfully deleted bre');
+
+