From 876068fb28bdf8159b375fb1a563a5baabf98feb Mon Sep 17 00:00:00 2001 From: dbs Date: Mon, 9 Aug 2010 20:33:26 +0000 Subject: [PATCH] Teach the staff client volume copy creator to respect OU call number preferences To teach the "Add volumes" dialog in the staff client how to show the correct set of call numbers based on the workstation OU's default classification scheme, this commit: * Adds a column "field" to the asset.call_number_class table that specifies the list of tag/subfield combinations to search for a candidate call number for a given classification scheme * Adds a new OU setting, 'cat.default_classification_scheme', that points to the asset.call_number_class ID * Extends the open-ils.cat.biblio.record.marc_cn.retrieve method to support a second argument, identifying the classification scheme for the call number extraction * Fixes the IDL for asset.call_number_class to include the ID as an explicit field * Makes the "Add volumes" dialog look up the 'cat.default_classification_scheme' setting for the workstation OU and apply that to the call to the open-ils.cat.biblio.record.marc_cn.retrieve method TODO: * Provide a means of switching the classification scheme for the current volume, repopulating the call number selector widget * Save the chosen scheme as part of the acn object git-svn-id: svn://svn.open-ils.org/ILS/trunk@17141 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/fm_IDL.xml | 2 + Open-ILS/src/perlmods/OpenILS/Application/Cat.pm | 74 ++++++++++---- .../OpenILS/Application/Storage/CDBI/asset.pm | 8 ++ .../OpenILS/Application/Storage/Driver/Pg/dbi.pm | 6 ++ Open-ILS/src/sql/Pg/002.schema.config.sql | 2 +- Open-ILS/src/sql/Pg/040.schema.asset.sql | 15 ++- Open-ILS/src/sql/Pg/950.data.seed-values.sql | 20 ++++ .../0365.schema.asset_call_number_class_field.sql | 32 ++++++ .../staff_client/server/cat/volume_copy_creator.js | 107 ++++++++++++--------- 9 files changed, 192 insertions(+), 74 deletions(-) create mode 100644 Open-ILS/src/sql/Pg/upgrade/0365.schema.asset_call_number_class_field.sql diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index bae749d53..db066c78b 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -1625,8 +1625,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Cat.pm b/Open-ILS/src/perlmods/OpenILS/Application/Cat.pm index f90b7dda2..cb2b08129 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Cat.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Cat.pm @@ -347,33 +347,65 @@ sub biblio_record_record_metadata { __PACKAGE__->register_method( - method => "biblio_record_marc_cn", - api_name => "open-ils.cat.biblio.record.marc_cn.retrieve", - argc => 1, #(bib id ) + method => "biblio_record_marc_cn", + api_name => "open-ils.cat.biblio.record.marc_cn.retrieve", + argc => 1, #(bib id ) + signature => { + desc => 'Extracts call number candidates from a bibliographic record', + params => [ + {desc => 'Record ID', type => 'number'}, + {desc => '(Optional) Classification scheme ID', type => 'number'}, + ] + }, + return => {desc => 'Hash of candidate call numbers identified by tag' } ); sub biblio_record_marc_cn { - my( $self, $client, $id ) = @_; + my( $self, $client, $id, $class ) = @_; - my $session = OpenSRF::AppSession->create("open-ils.cstore"); - my $marc = $session - ->request("open-ils.cstore.direct.biblio.record_entry.retrieve", $id ) - ->gather(1) - ->marc; + my $e = new_editor(); + my $marc = $e->retrieve_biblio_record_entry($id)->marc; - my $doc = XML::LibXML->new->parse_string($marc); - $doc->documentElement->setNamespace( "http://www.loc.gov/MARC21/slim", "marc", 1 ); - - my @res; - for my $tag ( qw/050 055 060 070 080 082 086 088 090 092 096 098 099/ ) { - my @node = $doc->findnodes("//marc:datafield[\@tag='$tag']"); - for my $x (@node) { - my $cn = $x->findvalue("marc:subfield[\@code='a' or \@code='b']"); - push @res, {$tag => $cn} if ($cn); - } - } + my $doc = XML::LibXML->new->parse_string($marc); + $doc->documentElement->setNamespace( "http://www.loc.gov/MARC21/slim", "marc", 1 ); + + my @fields; + my @res; + if ($class) { + @fields = split(/,/, $e->retrieve_asset_call_number_class($class)->field); + } else { + @fields = qw/050ab 055ab 060ab 070ab 080ab 082ab 086ab 088ab 090 092 096 098 099/; + } + + # Get field/subfield combos based on acnc value; for example "050ab,055ab" + + foreach my $field (@fields) { + my $tag = substr($field, 0, 3); + $logger->debug("Tag = $tag"); + my @node = $doc->findnodes("//marc:datafield[\@tag='$tag']"); + + # Now parse the subfields and build up the subfield XPath + my @subfields = split(//, substr($field, 3)); + + # If they give us no subfields to parse, default to just the 'a' + if (!@subfields) { + @subfields = ('a'); + } + my $subxpath; + foreach my $sf (@subfields) { + $subxpath .= "\@code='$sf' or "; + } + $subxpath = substr($subxpath, 0, -4); + $logger->debug("subxpath = $subxpath"); + + # Find the contents of the specified subfields + foreach my $x (@node) { + my $cn = $x->findvalue("marc:subfield[$subxpath]"); + push @res, {$tag => $cn} if ($cn); + } + } - return \@res + return \@res; } __PACKAGE__->register_method( diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/asset.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/asset.pm index 63c894db4..dca9fe461 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/asset.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/CDBI/asset.pm @@ -21,6 +21,14 @@ __PACKAGE__->columns( Primary => qw/id/ ); __PACKAGE__->columns( Essential => qw/location org position/ ); #------------------------------------------------------------------------------- +package asset::call_number_class; +use base qw/asset/; + +__PACKAGE__->table( 'asset_call_number_class' ); +__PACKAGE__->columns( Primary => qw/id/ ); +__PACKAGE__->columns( Essential => qw/name normalizer field/ ); + +#------------------------------------------------------------------------------- package asset::call_number; use base qw/asset/; diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm index 0cb4b51e8..f5a0975a5 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg/dbi.pm @@ -322,6 +322,12 @@ asset::call_number->sequence( 'asset.call_number_id_seq' ); #--------------------------------------------------------------------- + package asset::call_number_class; + + asset::call_number->table( 'asset.call_number_class' ); + asset::call_number->sequence( 'asset.call_number_class_id_seq' ); + + #--------------------------------------------------------------------- package asset::copy_location_order; asset::copy_location_order->table( 'asset.copy_location_order' ); diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql index 3b12cbf6a..5f22bd7b6 100644 --- a/Open-ILS/src/sql/Pg/002.schema.config.sql +++ b/Open-ILS/src/sql/Pg/002.schema.config.sql @@ -68,7 +68,7 @@ CREATE TABLE config.upgrade_log ( install_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); -INSERT INTO config.upgrade_log (version) VALUES ('0364'); -- dbs +INSERT INTO config.upgrade_log (version) VALUES ('0365'); -- dbs CREATE TABLE config.bib_source ( id SERIAL PRIMARY KEY, diff --git a/Open-ILS/src/sql/Pg/040.schema.asset.sql b/Open-ILS/src/sql/Pg/040.schema.asset.sql index 0d91bdd80..72d3a1431 100644 --- a/Open-ILS/src/sql/Pg/040.schema.asset.sql +++ b/Open-ILS/src/sql/Pg/040.schema.asset.sql @@ -170,8 +170,15 @@ CREATE TABLE asset.uri ( CREATE TABLE asset.call_number_class ( id bigserial PRIMARY KEY, name TEXT NOT NULL, - normalizer TEXT NOT NULL DEFAULT 'asset.normalize_generic' + normalizer TEXT NOT NULL DEFAULT 'asset.normalize_generic', + field TEXT NOT NULL DEFAULT '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099' ); +COMMENT ON TABLE asset.call_number_class IS $$ +Defines the call number normalization database functions in the "normalizer" +column and the tag/subfield combinations to use to lookup the call number in +the "field" column for a given classification scheme. Tag/subfield combinations +are delimited by commas. +$$; CREATE OR REPLACE FUNCTION asset.label_normalizer() RETURNS TRIGGER AS $func$ DECLARE @@ -259,9 +266,9 @@ CREATE OR REPLACE FUNCTION asset.label_normalizer_lc(TEXT) RETURNS TEXT AS $func $func$ LANGUAGE PLPERLU; INSERT INTO asset.call_number_class (name, normalizer) VALUES - ('Generic', 'asset.label_normalizer_generic'), - ('Dewey (DDC)', 'asset.label_normalizer_dewey'), - ('Library of Congress (LC)', 'asset.label_normalizer_lc') + ('Generic', 'asset.label_normalizer_generic', '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099'), + ('Dewey (DDC)', 'asset.label_normalizer_dewey', '080ab,082ab'), + ('Library of Congress (LC)', 'asset.label_normalizer_lc', '050ab,055ab') ; CREATE TABLE asset.call_number ( diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index a8dab2cb5..644684423 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -6462,6 +6462,26 @@ VALUES ( 'acpl' ); +INSERT INTO config.org_unit_setting_type ( name, label, description, datatype, fm_class ) +VALUES ( + 'cat.default_classification_scheme', + oils_i18n_gettext( + 'setting.name', + 'Cataloging: Default Classification Scheme', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'setting.name', + 'Defines the default classification scheme for new call numbers: 1 = Generic; 2 = Dewey; 3 = LC', + 'coust', + 'descripton' + ), + 'link', + 'acnc' +); + + -- 0355.data.missing_pieces_format.sql INSERT INTO action_trigger.hook (key,core_type,description,passive) VALUES diff --git a/Open-ILS/src/sql/Pg/upgrade/0365.schema.asset_call_number_class_field.sql b/Open-ILS/src/sql/Pg/upgrade/0365.schema.asset_call_number_class_field.sql new file mode 100644 index 000000000..dd40fa40a --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/0365.schema.asset_call_number_class_field.sql @@ -0,0 +1,32 @@ +BEGIN; + +INSERT INTO config.upgrade_log (version) VALUES ('0365'); -- dbs + +ALTER TABLE asset.call_number_class ADD COLUMN field TEXT NOT NULL DEFAULT '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099'; + +COMMENT ON TABLE asset.call_number_class IS $$ +Defines the call number normalization database functions in the "normalizer" +column and the tag/subfield combinations to use to lookup the call number in +the "field" column for a given classification scheme. Tag/subfield combinations +are delimited by commas. +$$; + +-- Generic fields +UPDATE asset.call_number_class + SET field = '050ab,055ab,060ab,070ab,080ab,082ab,086ab,088ab,090,092,096,098,099' + WHERE id = 1 +; + +-- Dewey fields +UPDATE asset.call_number_class + SET field = '080ab,082ab' + WHERE id = 2 +; + +-- LC fields +UPDATE asset.call_number_class + SET field = '050ab,055ab' + WHERE id = 3 +; + +COMMIT; diff --git a/Open-ILS/xul/staff_client/server/cat/volume_copy_creator.js b/Open-ILS/xul/staff_client/server/cat/volume_copy_creator.js index 66e417236..fd6bdd310 100644 --- a/Open-ILS/xul/staff_client/server/cat/volume_copy_creator.js +++ b/Open-ILS/xul/staff_client/server/cat/volume_copy_creator.js @@ -45,6 +45,15 @@ function my_init() { var ou_ids = xul_param('ou_ids',{'concat' : true}) || []; + // Get the default callnumber classification scheme from OU settings + dojo.require('fieldmapper.OrgUtils'); + var label_class = fieldmapper.aou.fetchOrgSettingDefault(ses('ws_ou'), 'cat.default_classification_scheme'); + + // Assign a default value if none was returned + if (!label_class.value) { + label_class.value = 1; + } + /***********************************************************************************************************/ /* If we're passed existing_copies, rig up a copy_shortcut object to leverage existing code for rendering the volume labels, etc. * Also make a lookup object for existing copies keyed on org id and callnumber label, and another keyed on copy id. */ @@ -89,53 +98,7 @@ function my_init() { /* For the call number drop down */ if (!g.copy_shortcut) { - var cn_blob; - try { - cn_blob = g.network.simple_request('BLOB_MARC_CALLNUMBERS_RETRIEVE',[g.doc_id]); - } catch(E) { - cn_blob = []; - } - var hbox = document.getElementById('marc_cn'); - var ml = util.widgets.make_menulist( - util.functional.map_list( - cn_blob, - function(o) { - for (var i in o) { - return [ o[i], i ]; - } - } - ).sort( - function(a,b) { - a = a[1]; b = b[1]; - if (a == '082') return -1; - if (b == '082') return 1; - if (a == '092') return -1; - if (b == '092') return 1; - if (a < b) return -1; - if (a > b) return 1; - return 0; - } - ) - ); hbox.appendChild(ml); - ml.setAttribute('editable','true'); - ml.setAttribute('width', '200'); - var btn = document.createElement('button'); - btn.setAttribute('label',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.label')); - btn.setAttribute('accesskey',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.accesskey')); - btn.setAttribute('image','/xul/server/skin/media/images/down_arrow.gif'); - hbox.appendChild(btn); - btn.addEventListener( - 'command', - function() { - var nl = document.getElementsByTagName('textbox'); - for (var i = 0; i < nl.length; i++) { - if (nl[i].getAttribute('rel_vert_pos')==2 - && !nl[i].disabled) nl[i].value = ml.value; - } - if (g.last_focus) setTimeout( function() { g.last_focus.focus(); }, 0 ); - }, - false - ); + g.list_callnumbers(g.doc_id, label_class.value); } /***********************************************************************************************************/ @@ -590,4 +553,52 @@ g.save_prefs = function () { } } - +g.list_callnumbers = function(doc_id, label_class) { + var cn_blob; + try { + cn_blob = g.network.simple_request('BLOB_MARC_CALLNUMBERS_RETRIEVE',[g.doc_id, label_class]); + } catch(E) { + cn_blob = []; + } + var hbox = document.getElementById('marc_cn'); + var ml = util.widgets.make_menulist( + util.functional.map_list( + cn_blob, + function(o) { + for (var i in o) { + return [ o[i], i ]; + } + } + ).sort( + function(a,b) { + a = a[1]; b = b[1]; + if (a == '082') return -1; + if (b == '082') return 1; + if (a == '092') return -1; + if (b == '092') return 1; + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + ) + ); hbox.appendChild(ml); + ml.setAttribute('editable','true'); + ml.setAttribute('width', '200'); + var btn = document.createElement('button'); + btn.setAttribute('label',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.label')); + btn.setAttribute('accesskey',$('catStrings').getString('staff.cat.volume_copy_creator.my_init.btn.accesskey')); + btn.setAttribute('image','/xul/server/skin/media/images/down_arrow.gif'); + hbox.appendChild(btn); + btn.addEventListener( + 'command', + function() { + var nl = document.getElementsByTagName('textbox'); + for (var i = 0; i < nl.length; i++) { + if (nl[i].getAttribute('rel_vert_pos')==2 + && !nl[i].disabled) nl[i].value = ml.value; + } + if (g.last_focus) setTimeout( function() { g.last_focus.focus(); }, 0 ); + }, + false + ); +} -- 2.11.0