From d14e046c9490e41495c0a0b44b9d2f1d1a85b50e Mon Sep 17 00:00:00 2001 From: Jane Sandberg Date: Fri, 24 Jul 2020 13:16:25 -0700 Subject: [PATCH] LP1849212: Allow users to detach all types of materials from courses Signed-off-by: Jane Sandberg Signed-off-by: Michele Morgan Signed-off-by: Galen Charlton --- Open-ILS/examples/fm_IDL.xml | 7 +- .../course-associate-material.component.html | 24 ++---- .../course-associate-material.component.ts | 35 ++++---- .../lib/OpenILS/Application/Courses.pm | 85 +++++++++++++++++-- Open-ILS/src/perlmods/live_t/30-courses.t | 23 ----- Open-ILS/src/perlmods/live_t/31-courses.t | 82 ++++++++++++++++++ 6 files changed, 184 insertions(+), 72 deletions(-) delete mode 100644 Open-ILS/src/perlmods/live_t/30-courses.t create mode 100644 Open-ILS/src/perlmods/live_t/31-courses.t diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 8c76cab9b2..87288f5b90 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -3114,13 +3114,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - + + - + - diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.html b/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.html index 724545a030..242357be22 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.html +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.html @@ -148,16 +148,6 @@ -
-
-
- Relationship -
- -
-
@@ -184,18 +174,18 @@
- Relationship +
-
- + Relationship
-
@@ -213,14 +203,14 @@
- + - - + + diff --git a/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts b/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts index b50634f52d..541ea1a8b1 100644 --- a/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-material.component.ts @@ -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'; @@ -29,7 +28,7 @@ export class CourseAssociateMaterialComponent extends DialogComponent implements @Input() displayMode: String; materials: any[] = []; @ViewChild('editDialog', { static: true }) editDialog: FmRecordEditorComponent; - @ViewChild('materialsGrid', {static: true}) materialsGrid: GridComponent; + @ViewChild('materialsGrid', {static: false}) materialsGrid: GridComponent; @ViewChild('materialDeleteFailedString', { static: true }) materialDeleteFailedString: StringComponent; @ViewChild('materialDeleteSuccessString', { static: true }) @@ -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)); + } + ); } } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Courses.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Courses.pm index fe32164cd4..a12831c74d 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Courses.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Courses.pm @@ -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 index 480206c5df..0000000000 --- a/Open-ILS/src/perlmods/live_t/30-courses.t +++ /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 index 0000000000..da14e65b09 --- /dev/null +++ b/Open-ILS/src/perlmods/live_t/31-courses.t @@ -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(''); +$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'); + + -- 2.43.2