From cf77f78a83e0a3690c0dca1d206577f486441f74 Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Thu, 13 Apr 2017 12:03:52 -0400 Subject: [PATCH] LP#1708291: web staff client serials module This patch adds a serials module to the web staff client, implementing a unified serials interface allowing for the following actions supported by the XUL staff client: - creating subscriptions, distributions, and streams - creating and editing prediction patterns - receiving serial issues, with or without barcodes (units) - batch and quick receiving This module also implements some new features, including - the ability to save prediction pattern codes as templates that can be shared and reused within an Evergreen database - a more streamlined interface for managing subscriptions, distributions, and streams - it is no longer necessary to create a starting issue in order to predict a run of issues; the dialog box for generating a set of predicted issues now lets you specify the starting point directly. - the ability to more directly edit MFHDs The new serials interfaces can be accessed from the record details page via a Serials drop-down button that links to a subscription management page, a quick-receive action, and a MFHD management page. There is also a new Serials Administration page where prediction pattern and serial copy templates can be managed. To test ------- * Create, edit, and delete subscriptions, distribution streams, and routing lists. * Use the prediction pattern wizard to create patterns. * Save prediction pattern templates and use them to apply a pattern to new subscriptions. * Verify that sets of issues can be predicted and received. * Create and apply serial copy templates and verify that they are applied when receiving barcoded issues. This patch represents a group coding effort by Galen Charlton, Jason Etheridge, and Mike Rylander. Signed-off-by: Galen Charlton Signed-off-by: Kathy Lussier Conflicts: Open-ILS/src/sql/Pg/950.data.seed-values.sql Open-ILS/web/js/ui/default/staff/cat/catalog/app.js Signed-off-by: Kathy Lussier Signed-off-by: Dan Wells --- Open-ILS/examples/fm_IDL.xml | 68 +- Open-ILS/src/extras/ils_events.xml | 3 + .../lib/OpenILS/Application/Serial.pm | 323 ++++- .../src/perlmods/lib/OpenILS/Utils/MFHD.pm | 5 +- Open-ILS/src/sql/Pg/210.schema.serials.sql | 22 + Open-ILS/src/sql/Pg/950.data.seed-values.sql | 5 +- Open-ILS/src/sql/Pg/live_t/spt-visibility.pg | 48 + .../XXXX.schema.serial_pattern_templates.sql | 25 + .../sql/Pg/upgrade/YYYY.data.spt_perms.sql | 24 + .../ZZZZ.schema.issuance_scap_fkey.sql | 18 + .../templates/staff/admin/local/t_splash.tt2 | 1 - .../templates/staff/admin/serials/index.tt2 | 33 + .../staff/admin/serials/pattern_template.tt2 | 44 + .../staff/admin/serials/t_attr_edit.tt2 | 338 +++++ .../staff/admin/serials/t_splash.tt2 | 38 + .../staff/admin/serials/t_template_list.tt2 | 54 + .../staff/admin/serials/t_templates.tt2 | 20 + .../src/templates/staff/cat/catalog/index.tt2 | 11 + .../templates/staff/cat/catalog/t_catalog.tt2 | 16 + Open-ILS/src/templates/staff/navbar.tt2 | 6 + .../src/templates/staff/serials/index.tt2 | 76 + .../staff/serials/share/serials_strings.tt2 | 27 + .../serials/t_apply_binding_template.tt2 | 55 + .../staff/serials/t_batch_receive.tt2 | 183 +++ .../staff/serials/t_chron_selector.tt2 | 5 + .../staff/serials/t_clone_subscription.tt2 | 57 + .../staff/serials/t_day_of_week_selector.tt2 | 9 + .../staff/serials/t_holding_code_dialog.tt2 | 100 ++ .../staff/serials/t_item_manager.tt2 | 7 + .../templates/staff/serials/t_link_mfhd.tt2 | 35 + .../src/templates/staff/serials/t_manage.tt2 | 32 + .../staff/serials/t_mfhd_manager.tt2 | 26 + .../staff/serials/t_mfhd_tooltip.tt2 | 77 ++ .../staff/serials/t_month_day_selector.tt2 | 17 + .../staff/serials/t_month_selector.tt2 | 14 + .../src/templates/staff/serials/t_notes.tt2 | 103 ++ .../staff/serials/t_pattern_editor_dialog.tt2 | 15 + .../staff/serials/t_pattern_summary.tt2 | 48 + .../staff/serials/t_prediction_manager.tt2 | 73 + .../staff/serials/t_prediction_wizard.tt2 | 461 +++++++ .../staff/serials/t_print_routing_list.tt2 | 15 + .../staff/serials/t_receive_alerts.tt2 | 76 + .../staff/serials/t_routing_list.tt2 | 118 ++ .../staff/serials/t_season_selector.tt2 | 6 + .../staff/serials/t_select_pattern_dialog.tt2 | 32 + .../staff/serials/t_sub_selector.tt2 | 17 + .../staff/serials/t_subscription_manager.tt2 | 157 +++ .../staff/serials/t_view_items_grid.tt2 | 117 ++ .../serials/t_week_in_month_selector.tt2 | 11 + .../src/templates/staff/share/t_edit_mfhd.tt2 | 14 + .../staff/share/t_mfhd_create_dialog.tt2 | 25 + .../staff/share/t_org_select_dialog.tt2 | 22 + .../share/t_subscription_select_dialog.tt2 | 22 + .../serial/print_routing_list_users.js | 16 +- .../js/ui/default/staff/admin/serials/app.js | 592 ++++++++ .../staff/admin/serials/pattern_template.js | 135 ++ .../js/ui/default/staff/cat/catalog/app.js | 63 +- .../web/js/ui/default/staff/serials/app.js | 69 + .../staff/serials/directives/item_manager.js | 20 + .../staff/serials/directives/mfhd_manager.js | 97 ++ .../serials/directives/prediction_manager.js | 203 +++ .../serials/directives/prediction_wizard.js | 711 ++++++++++ .../staff/serials/directives/sub_selector.js | 31 + .../directives/subscription_manager.js | 943 +++++++++++++ .../serials/directives/view-items-grid.js | 545 ++++++++ .../ui/default/staff/serials/services/core.js | 1217 +++++++++++++++++ .../web/js/ui/default/staff/services/mfhd.js | 41 + .../web/js/ui/default/staff/services/ui.js | 24 +- 68 files changed, 7813 insertions(+), 48 deletions(-) create mode 100644 Open-ILS/src/sql/Pg/live_t/spt-visibility.pg create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.serial_pattern_templates.sql create mode 100644 Open-ILS/src/sql/Pg/upgrade/YYYY.data.spt_perms.sql create mode 100644 Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.issuance_scap_fkey.sql create mode 100644 Open-ILS/src/templates/staff/admin/serials/index.tt2 create mode 100644 Open-ILS/src/templates/staff/admin/serials/pattern_template.tt2 create mode 100644 Open-ILS/src/templates/staff/admin/serials/t_attr_edit.tt2 create mode 100644 Open-ILS/src/templates/staff/admin/serials/t_splash.tt2 create mode 100644 Open-ILS/src/templates/staff/admin/serials/t_template_list.tt2 create mode 100644 Open-ILS/src/templates/staff/admin/serials/t_templates.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/index.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/share/serials_strings.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_apply_binding_template.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_batch_receive.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_chron_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_clone_subscription.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_day_of_week_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_holding_code_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_item_manager.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_manage.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_mfhd_manager.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_mfhd_tooltip.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_month_day_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_month_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_notes.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_pattern_editor_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_pattern_summary.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_prediction_manager.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_prediction_wizard.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_print_routing_list.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_receive_alerts.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_routing_list.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_season_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_select_pattern_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_sub_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_subscription_manager.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_view_items_grid.tt2 create mode 100644 Open-ILS/src/templates/staff/serials/t_week_in_month_selector.tt2 create mode 100644 Open-ILS/src/templates/staff/share/t_edit_mfhd.tt2 create mode 100644 Open-ILS/src/templates/staff/share/t_mfhd_create_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/share/t_org_select_dialog.tt2 create mode 100644 Open-ILS/src/templates/staff/share/t_subscription_select_dialog.tt2 create mode 100644 Open-ILS/web/js/ui/default/staff/admin/serials/app.js create mode 100644 Open-ILS/web/js/ui/default/staff/admin/serials/pattern_template.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/app.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/item_manager.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/mfhd_manager.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/prediction_manager.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/prediction_wizard.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/sub_selector.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/subscription_manager.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/directives/view-items-grid.js create mode 100644 Open-ILS/web/js/ui/default/staff/serials/services/core.js create mode 100644 Open-ILS/web/js/ui/default/staff/services/mfhd.js diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 7764758566..d075d354c3 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -3956,7 +3956,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - + @@ -3977,6 +3977,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + + + + + + @@ -5069,7 +5077,7 @@ SELECT usr, - + @@ -5084,6 +5092,20 @@ SELECT usr, + + + + + + + + + + + + + + @@ -5174,7 +5196,7 @@ SELECT usr, - + @@ -5379,7 +5401,7 @@ SELECT usr, - + @@ -5394,7 +5416,22 @@ SELECT usr, - + + + + + + + + + + + + + + + + @@ -5503,6 +5540,27 @@ SELECT usr, + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/extras/ils_events.xml b/Open-ILS/src/extras/ils_events.xml index 570e19bc9b..a4573b41bb 100644 --- a/Open-ILS/src/extras/ils_events.xml +++ b/Open-ILS/src/extras/ils_events.xml @@ -1054,6 +1054,9 @@ The stream still has dependent objects + + The prediction pattern still has dependent objects + diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm index 071922c9de..04f79c0de3 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm @@ -257,6 +257,7 @@ sub fleshed_item_alter { my %found_sdist_ids; my %found_sstr_ids; + my %siss_to_potentially_delete; for my $item (@$items) { my $sstr_id = ref $item->stream ? $item->stream->id : $item->stream; if (!exists($found_sstr_ids{$sstr_id})) { @@ -279,6 +280,8 @@ sub fleshed_item_alter { $item->edit_date('now'); if( $item->isdeleted ) { + my $siss_id = ref $item->issuance ? $item->issuance->id : $item->issuance; + $siss_to_potentially_delete{$siss_id}++; $evt = _delete_sitem( $editor, $override, $item); } elsif( $item->isnew ) { # TODO: reconsider this @@ -299,6 +302,31 @@ sub fleshed_item_alter { $editor->rollback; return $evt; } + if( %siss_to_potentially_delete ) { + foreach my $id (keys %siss_to_potentially_delete) { + my $issuance = $editor->retrieve_serial_issuance([ + $id, { + "flesh" => 1, "flesh_fields" => { + "siss" => ["items"], + } + } + ]); + unless ($issuance) { + $logger->warn("fleshed item-alter failed to retrieve issuance $id to potenitally delete"); + $editor->rollback; + return $editor->die_event; + } + unless (@{ $issuance->items }) { + $logger->info("fleshed item-alter deleting issuance $id as it has no items left"); + $evt = _delete_siss( $editor, $override, $issuance); + if( $evt ) { + $logger->info("fleshed item-alter failed with event: ".OpenSRF::Utils::JSON->perl2JSON($evt)); + $editor->rollback; + return $evt; + } + } + } + } $logger->debug("item-alter: done updating item batch"); $editor->commit; $logger->info("fleshed item-alter successfully updated ".scalar(@$items)." items"); @@ -894,14 +922,47 @@ __PACKAGE__->register_method( sub make_predictions { my ($self, $conn, $authtoken, $args) = @_; - my $editor = OpenILS::Utils::CStoreEditor->new(); my $ssub_id = $args->{ssub_id}; - my $mfhd = MFHD->new(MARC::Record->new()); + my $editor = OpenILS::Utils::CStoreEditor->new(); my $ssub = $editor->retrieve_serial_subscription([$ssub_id]); - my $scaps = $editor->search_serial_caption_and_pattern({ subscription => $ssub_id, active => 't'}); my $sdists = $editor->search_serial_distribution( [{ subscription => $ssub->id }, { flesh => 1, flesh_fields => {sdist => [ qw/ streams / ]} }] ); #TODO: 'deleted' support? + return store_predictions( + $self, $conn, $authtoken, $args, $ssub, $sdists, + make_prediction_values($self, $conn, $authtoken, $args, $ssub, $sdists, $editor) + ); +} + +__PACKAGE__->register_method( + method => 'make_prediction_values', + api_name => 'open-ils.serial.make_prediction_values', + api_level => 1, + argc => 1, + signature => { + desc => 'Receives an ssub id and returns objects that can be used to populate the issuance and item tables', + 'params' => [ { + name => 'ssub_id', + desc => 'Serial Subscription ID', + type => 'int' + } + ] + } +); + +sub make_prediction_values { + my ($self, $conn, $authtoken, $args, $ssub, $sdists, $editor) = @_; + $logger->debug('make_prediction_values with args: ' . OpenSRF::Utils::JSON->perl2JSON($args)); + + my $ssub_id = $args->{ssub_id}; + + $editor ||= OpenILS::Utils::CStoreEditor->new(); + $ssub ||= $editor->retrieve_serial_subscription([$ssub_id]); + $sdists ||= $editor->search_serial_distribution( [{ subscription => $ssub->id }, { flesh => 1, flesh_fields => {sdist => [ qw/ streams / ]} }] ); #TODO: 'deleted' support? + + my $scaps = $editor->search_serial_caption_and_pattern({ subscription => $ssub_id, active => 't'}); + my $mfhd = MFHD->new(MARC::Record->new()); + my $total_streams = 0; foreach (@$sdists) { $total_streams += scalar(@{$_->streams}); @@ -942,13 +1003,14 @@ sub make_predictions { my $options = { 'caption' => $caption_field, 'scap_id' => $scap->id, + 'include_base_issuance' => $args->{include_base_issuance}, 'num_to_predict' => $args->{num_to_predict}, 'end_date' => defined $args->{end_date} ? $_strp_date->parse_datetime($args->{end_date}) : undef }; my $predict_from_siss; if ($args->{base_issuance}) { # predict from a given issuance - $predict_from_siss = $args->{base_issuance}->holding_code; + $predict_from_siss = $args->{base_issuance}; } else { # default to predicting from last published my $last_published = $editor->search_serial_issuance([ {'caption_and_pattern' => $scap->id, @@ -973,16 +1035,25 @@ sub make_predictions { ); } } + $logger->debug('make_prediction_values reviving holdings: ' . OpenSRF::Utils::JSON->perl2JSON($predict_from_siss)); $options->{predict_from} = _revive_holding($predict_from_siss->holding_code, $caption_field, 1); # fresh MFHD Record, so we simply default to 1 for seqno if ($fake_chron_needed) { $options->{faked_chron_date} = DateTime::Format::ISO8601->new->parse_datetime(cleanse_ISO8601($predict_from_siss->date_published)); } + $logger->debug('make_prediction_values predicting with options: ' . OpenSRF::Utils::JSON->perl2JSON($options)); push( @predictions, _generate_issuance_values($mfhd, $options) ); $link_id++; } + $logger->debug('make_prediction_values predictions: ' . OpenSRF::Utils::JSON->perl2JSON(\@predictions)); + return \@predictions; +} + +sub store_predictions { + my ($self, $conn, $authtoken, $args, $ssub, $sdists, $predictions) = @_; + my @issuances; - foreach my $prediction (@predictions) { + foreach my $prediction (@$predictions) { my $issuance = new Fieldmapper::serial::issuance; $issuance->isnew(1); $issuance->label($prediction->{label}); @@ -999,7 +1070,7 @@ sub make_predictions { my @items; for (my $i = 0; $i < @issuances; $i++) { - my $date_expected = $predictions[$i]->{date_published}->add(seconds => interval_to_seconds($ssub->expected_date_offset))->strftime('%F'); + my $date_expected = $$predictions[$i]->{date_published}->add(seconds => interval_to_seconds($ssub->expected_date_offset))->strftime('%F'); my $issuance = $issuances[$i]; #$issuance->label(interval_to_seconds($ssub->expected_date_offset)); foreach my $sdist (@$sdists) { @@ -1038,11 +1109,13 @@ sub _generate_issuance_values { my ($mfhd, $options) = @_; my $caption = $options->{caption}; my $scap_id = $options->{scap_id}; + my $include_base_issuance = $options->{include_base_issuance}; my $num_to_predict = $options->{num_to_predict}; my $end_date = $options->{end_date}; my $predict_from = $options->{predict_from}; # MFHD::Holding to predict from my $faked_chron_date = $options->{faked_chron_date}; # serial does not have a (complete) chronology caption, so add one (temporarily) based on this date + $logger->debug('_generate_issuance_values predict_from: ' . OpenSRF::Utils::JSON->perl2JSON($predict_from)); # Only needed for 'real' MFHD records, not our temp records # my $link_id = $caption->link_id; @@ -1082,9 +1155,16 @@ sub _generate_issuance_values { # to recreate rather than try to update $faked_caption = new MFHD::Caption($faked_caption); $predict_from = new MFHD::Holding($predict_from->seqno, new MARC::Field($predict_from->tag, $predict_from->indicator(1), $predict_from->indicator(2), $predict_from->subfields_list), $faked_caption); + $logger->debug('_generate_issuance_values fake predict_from: ' . OpenSRF::Utils::JSON->perl2JSON($predict_from)); } - my @predictions = $mfhd->generate_predictions({'base_holding' => $predict_from, 'num_to_predict' => $num_to_predict, 'end_date' => $end_date}); + my @predictions = $mfhd->generate_predictions({ + 'include_base_issuance' => $include_base_issuance, + 'base_holding' => $predict_from, + 'num_to_predict' => $num_to_predict, + 'end_date' => $end_date + }); + $logger->debug('_generate_issuance_values predictions: ' . OpenSRF::Utils::JSON->perl2JSON(\@predictions)); my $pub_date; my @issuance_values; @@ -1169,6 +1249,11 @@ __PACKAGE__->register_method( name => 'donor_unit_ids', desc => 'hash of unit_ids => 1, keyed with ids of any units giving up items', type => 'hash' + }, + { + name => 'extras', + desc => 'hash of hashes, circ_mod code and copy_location id, keyed as above', + type => 'hash' } ], 'return' => { @@ -1204,6 +1289,11 @@ __PACKAGE__->register_method( name => 'donor_unit_ids', desc => 'hash of unit_ids => 1, keyed with ids of any units giving up items', type => 'hash' + }, + { + name => 'extras', + desc => 'hash of hashes, circ_mod code and copy_location id, keyed as above', + type => 'hash' } ], 'return' => { @@ -1236,7 +1326,7 @@ __PACKAGE__->register_method( ); sub unitize_items { - my ($self, $conn, $auth, $items, $barcodes, $call_numbers, $donor_unit_ids) = @_; + my ($self, $conn, $auth, $items, $barcodes, $call_numbers, $donor_unit_ids, $extras) = @_; my $editor = new_editor("authtoken" => $auth, "xact" => 1); return $editor->die_event unless $editor->checkauth; @@ -1250,6 +1340,7 @@ sub unitize_items { } my %found_stream_ids; my %found_types; + my $prev_loc_setting_map = {}; my %stream_ids_by_unit_id; @@ -1295,7 +1386,7 @@ sub unitize_items { if (!exists($found_types{$stream_id})) { $found_types{$stream_id} = {}; } - $found_types{$stream_id}->{$scap->type} = 1; + $found_types{$stream_id}->{$scap->type} = 1 if ($scap); # create unit if needed if ($unit_id == -1 or (!$new_unit_id and $unit_id == -2)) { # create unit per item @@ -1314,7 +1405,11 @@ sub unitize_items { $unit->{"note"} = "Item ID: " . $item->id; return $unit; } + $unit->barcode($barcodes->{$item->id}) if exists($barcodes->{$item->id}); + $unit->location($extras->{copy_locations}->{$item->id}) if exists($extras->{copy_locations}->{$item->id}); + $unit->circ_modifier($extras->{circ_mods}->{$item->id}) if exists($extras->{circ_mods}->{$item->id}); + my $evt = _create_sunit($editor, $unit); return $evt if $evt; if ($unit_id == -2) { @@ -1349,6 +1444,57 @@ sub unitize_items { my $evt = _update_sitem($editor, undef, $item); return $evt if $evt; + + if ($mode eq 'receive') { + my $sdists = $editor->search_serial_distribution([ + {"+sstr" => {"id" => $stream_id}}, + { + "join" => {"sstr" => {}}, + "flesh" => 1, + "flesh_fields" => {"sdist" => ["subscription"]} + }]); + + #------------------------------------------------------------------------- + # The following is copied from open-ils.serial.receive_items.one_unit_per + + # Fetch a list of issuances with received copies already existing + # on this distribution (and with the same holding type on the + # issuance). This will be used in up to two places: once when building + # a summary, once when changing the copy location of the previous + # issuance's copy. + my $issuances_received = _issuances_received($editor, $item); + if ($U->event_code($issuances_received)) { + $editor->rollback; + return $issuances_received; + } + + # Find out if we need to to deal with previous copy location changing. + my $ou = $sdists->[0]->holding_lib; + unless (exists $prev_loc_setting_map->{$ou}) { + $prev_loc_setting_map->{$ou} = $U->ou_ancestor_setting_value( + $ou, "serial.prev_issuance_copy_location", $editor + ); + } + + # If there is a previous copy location setting, we need the previous + # issuance, from which we can in turn look up the item attached to the + # same stream we're on now. + if ($prev_loc_setting_map->{$ou}) { + if (my $prev_iss = + _previous_issuance($issuances_received, $item->issuance)) { + + # Now we can change the copy location of the previous unit, + # if needed. + return $editor->event if defined $U->event_code( + move_previous_unit( + $editor, $prev_iss, $item, $prev_loc_setting_map->{$ou} + ) + ); + } + } + #------------------------------------------------------------------------- + } + } # cleanup 'dead' units (units which are now emptied of their items) @@ -1464,13 +1610,22 @@ sub unitize_items { sub _find_or_create_call_number { my ($e, $lib, $cn_string, $record) = @_; - # FIXME: should suffix and prefix come into play here? - my $existing = $e->search_asset_call_number({ - "owning_lib" => $lib, - "label" => $cn_string, - "record" => $record, - "deleted" => "f" - }) or return $e->die_event; + my ($prefix,$suffix) = ('',''); + if (ref($cn_string)) { + ($prefix,$cn_string,$suffix) = @$cn_string; + } + + my $existing = $e->search_asset_call_number([{ + owning_lib => $lib, + label => $cn_string, + record => $record, + deleted => "f", + '+acnp' => { label => $prefix }, + '+acns' => { label => $suffix }, + + },{ + join => { acnp => {}, acns => {} } + }]) or return $e->die_event; if (@$existing) { return $existing->[0]->id; @@ -1478,6 +1633,43 @@ sub _find_or_create_call_number { return $e->die_event unless $e->allowed("CREATE_VOLUME", $lib); + $prefix = -1 if (!$prefix); + $suffix = -1 if (!$suffix); + + if ($prefix ne '-1') { + my $acnp = $e->search_asset_call_number_prefix({ + owning_lib => $lib, + label => $prefix, + })->[0]; + + if (!$acnp) { + $acnp = new Fieldmapper::asset::call_number_prefix; + $acnp->label($prefix); + $acnp->owning_lib($lib); + $e->create_asset_call_number_prefix($acnp) or return $e->die_event; + $prefix = $e->data->id; + } else { + $prefix = $acnp->id; + } + } + + if ($suffix ne '-1') { + my $acns = $e->search_asset_call_number_suffix({ + owning_lib => $lib, + label => $suffix, + })->[0]; + + if (!$acns) { + $acns = new Fieldmapper::asset::call_number_suffix; + $acns->label($suffix); + $acns->owning_lib($lib); + $e->create_asset_call_number_suffix($acns) or return $e->die_event; + $suffix = $e->data->id; + } else { + $suffix = $acns->id; + } + } + my $acn = new Fieldmapper::asset::call_number; $acn->creator($e->requestor->id); @@ -1485,6 +1677,8 @@ sub _find_or_create_call_number { $acn->record($record); $acn->label($cn_string); $acn->owning_lib($lib); + $acn->prefix($prefix); + $acn->suffix($suffix); $e->create_asset_call_number($acn) or return $e->die_event; return $e->data->id; @@ -2399,6 +2593,18 @@ __PACKAGE__->register_method( / ); +__PACKAGE__->register_method( + method => 'safe_delete', + api_name => 'open-ils.serial.caption_and_pattern.safe_delete', + signature => q/ + Deletes an existing caption and pattern object, but only + if there are no attached serial issuances. + @param authtoken The login session key + @param strid The id of the scap to delete + @return 1 on success - Event otherwise. + / +); + __PACKAGE__->register_method( method => 'safe_delete', api_name => 'open-ils.serial.subscription.safe_delete.dry_run', @@ -2411,6 +2617,10 @@ __PACKAGE__->register_method( method => 'safe_delete', api_name => 'open-ils.serial.stream.safe_delete.dry_run', ); +__PACKAGE__->register_method( + method => 'safe_delete', + api_name => 'open-ils.serial.caption_and_pattern.safe_delete.dry_run', +); sub safe_delete { my( $self, $conn, $authtoken, $id ) = @_; @@ -2439,10 +2649,10 @@ sub safe_delete { foreach my $sitem (@{$sstr->items}) { if ($sitem->status ne 'Expected') { - return OpenILS::Event->new('SERIAL_STREAM_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_STREAM_NOT_EMPTY', payload=>$id)); } if ($sitem->unit && !$U->is_true($sitem->unit->deleted)) { - return OpenILS::Event->new('SERIAL_STREAM_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_STREAM_NOT_EMPTY', payload=>$id)); } } @@ -2465,16 +2675,48 @@ sub safe_delete { foreach my $sstr (@{$sdist->streams}) { foreach my $sitem (@{$sstr->items}) { if ($sitem->status ne 'Expected') { - return OpenILS::Event->new('SERIAL_DISTRIBUTION_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_DISTRIBUTION_NOT_EMPTY', payload=>$id)); } if ($sitem->unit && !$U->is_true($sitem->unit->deleted)) { - return OpenILS::Event->new('SERIAL_DISTRIBUTION_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_DISTRIBUTION_NOT_EMPTY', payload=>$id)); } } } $obj = $sdist; + } elsif ($type eq 'caption_and_pattern') { + my $scap = $e->retrieve_serial_caption_and_pattern([ + $id, + { flesh => 1, flesh_fields => { scap => ['subscription'] } } + ]) or return $e->die_event; + + return $e->die_event unless + $e->allowed("ADMIN_SERIAL_CAPTION_PATTERN", $scap->subscription->owning_lib); + + my $issuances = $e->search_serial_issuance([{ + caption_and_pattern => $id + },{ + flesh => 2, + flesh_fields => { + siss => ['items'], + sitem => ['unit'] + } + }]); + + foreach my $siss (@$issuances) { + foreach my $sitem (@{$siss->items}) { + if ($sitem->status ne 'Expected') { + return $e->die_event(OpenILS::Event->new('SERIAL_CAPTION_AND_PATTERN_NOT_EMPTY', payload=>$id)); + } + if ($sitem->unit && !$U->is_true($sitem->unit->deleted)) { + return $e->die_event(OpenILS::Event->new('SERIAL_CAPTION_AND_PATTERN_NOT_EMPTY', payload=>$id)); + } + } + } + + $obj = $scap; + } else { # subscription my $sub = $e->retrieve_serial_subscription([ $id, { @@ -2494,10 +2736,10 @@ sub safe_delete { foreach my $sstr (@{$sdist->streams}) { foreach my $sitem (@{$sstr->items}) { if ($sitem->status ne 'Expected') { - return OpenILS::Event->new('SERIAL_SUBSCRIPTION_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_SUBSCRIPTION_NOT_EMPTY', payload=>$id)); } if ($sitem->unit && !$U->is_true($sitem->unit->deleted)) { - return OpenILS::Event->new('SERIAL_SUBSCRIPTION_NOT_EMPTY', payload=>$id); + return $e->die_event(OpenILS::Event->new('SERIAL_SUBSCRIPTION_NOT_EMPTY', payload=>$id)); } } } @@ -2511,6 +2753,7 @@ sub safe_delete { $e->$method($obj) or return $e->die_event; $e->commit; } + return 1; } @@ -4052,4 +4295,40 @@ sub summary_test { return; } +__PACKAGE__->register_method( + "method" => "fetch_pattern_templates", + "api_name" => "open-ils.serial.pattern_template.retrieve.at", + "stream" => 1, + "signature" => { + "desc" => q{Return the set of pattern templates that are + visible to the specified library.}, + "params" => [ + {"desc" => "Authtoken", "type" => "string"}, + {"desc" => "OU ID", "type" => "number"}, + ], + return => { + desc => "stream of pattern templates", + type => "object", class => "spt" + } + } +); + +sub fetch_pattern_templates { + my ($self, $client, $auth, $org_unit) = @_; + + my $e = new_editor("authtoken" => $auth); + return $e->die_event unless $e->checkauth; + + my $patterns = $e->json_query({ + from => [ 'serial.pattern_templates_visible_to' => $org_unit ] + }); +$logger->info(Dumper($patterns)); use Data::Dumper; + + $client->respond($e->retrieve_serial_pattern_template($_->{id})) + foreach (@$patterns); + + $e->disconnect; + return undef; +} + 1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHD.pm b/Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHD.pm index 03975cf176..bbe36611f1 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHD.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Utils/MFHD.pm @@ -273,6 +273,7 @@ sub _holding_date { # generate_predictions() # Accepts a hash ref of options initially defined as: # base_holding : reference to the holding field to predict from +# include_base_issuance : whether to "predict" the startting holding, so as to generate a label for it # num_to_predict : the number of issues you wish to predict # OR # end_holding : holding field ref, keep predicting until you meet or exceed it @@ -293,6 +294,7 @@ sub generate_predictions { my $end_holding = $options->{end_holding}; my $end_date = $options->{end_date}; my $max_to_predict = $options->{max_to_predict} || 10000; # fail-safe + my $include_base_issuance = $options->{include_base_issuance}; if (!defined($base_holding)) { carp("Base holding not defined in generate_predictions, returning empty set"); @@ -305,7 +307,8 @@ sub generate_predictions { my $curr_holding = $base_holding->clone; # prevent side-effects my @predictions; - + push(@predictions, $curr_holding->clone) if ($include_base_issuance); + if ($num_to_predict) { for (my $i = 0; $i < $num_to_predict; $i++) { push(@predictions, $curr_holding->increment->clone); diff --git a/Open-ILS/src/sql/Pg/210.schema.serials.sql b/Open-ILS/src/sql/Pg/210.schema.serials.sql index 2e5af44f06..8c65f6f573 100644 --- a/Open-ILS/src/sql/Pg/210.schema.serials.sql +++ b/Open-ILS/src/sql/Pg/210.schema.serials.sql @@ -195,6 +195,7 @@ CREATE TABLE serial.issuance ( label TEXT, date_published TIMESTAMP WITH TIME ZONE, caption_and_pattern INT REFERENCES serial.caption_and_pattern (id) + ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, holding_code TEXT CONSTRAINT issuance_holding_code_check CHECK ( holding_code IS NULL OR could_be_serial_holding_code(holding_code) @@ -421,5 +422,26 @@ CREATE INDEX assist_holdings_display CREATE TRIGGER materialize_holding_code AFTER INSERT OR UPDATE ON serial.issuance FOR EACH ROW EXECUTE PROCEDURE serial.materialize_holding_code() ; + +CREATE TABLE serial.pattern_template ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + pattern_code TEXT NOT NULL, + owning_lib INTEGER REFERENCES actor.org_unit(id) DEFERRABLE INITIALLY DEFERRED, + share_depth INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX serial_pattern_template_name_idx ON serial.pattern_template (evergreen.lowercase(name)); + +CREATE OR REPLACE FUNCTION serial.pattern_templates_visible_to(org_unit INT) RETURNS SETOF serial.pattern_template AS $func$ +BEGIN + RETURN QUERY SELECT * + FROM serial.pattern_template spt + WHERE ( + SELECT ARRAY_AGG(id) + FROM actor.org_unit_descendants(spt.owning_lib, spt.share_depth) + ) @@ org_unit::TEXT::QUERY_INT; +END; +$func$ LANGUAGE PLPGSQL; + COMMIT; 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 f3d5aa5576..391ad5ae6a 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -1681,7 +1681,9 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES ( 591, 'ADMIN_COPY_TAG', oils_i18n_gettext( 591, 'Administer copy tag', 'ppl', 'description' )), ( 592,'CONTAINER_BATCH_UPDATE', oils_i18n_gettext( 592, - 'Allow batch update via buckets', 'ppl', 'description' )) + 'Allow batch update via buckets', 'ppl', 'description' )), + ( 593, 'ADMIN_SERIAL_PATTERN_TEMPLATE', oils_i18n_gettext( 593, + 'Administer serial prediction pattern templates', 'ppl', 'description' )) ; SELECT SETVAL('permission.perm_list_id_seq'::TEXT, 1000); @@ -2489,6 +2491,7 @@ INSERT INTO permission.grp_perm_map (grp, perm, depth, grantable) 'ADMIN_SERIAL_CAPTION_PATTERN', 'ADMIN_SERIAL_DISTRIBUTION', 'ADMIN_SERIAL_ITEM', + 'ADMIN_SERIAL_PATTERN_TEMPLATE', 'ADMIN_SERIAL_STREAM', 'ADMIN_SERIAL_SUBSCRIPTION', 'ISSUANCE_HOLDS', diff --git a/Open-ILS/src/sql/Pg/live_t/spt-visibility.pg b/Open-ILS/src/sql/Pg/live_t/spt-visibility.pg new file mode 100644 index 0000000000..455877ea5f --- /dev/null +++ b/Open-ILS/src/sql/Pg/live_t/spt-visibility.pg @@ -0,0 +1,48 @@ +BEGIN; + +SELECT plan(6); + +INSERT INTO serial.pattern_template(name, pattern_code, owning_lib, share_depth) +VALUES ('spt-vis-test', '[]', 4, 0); + +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(4) + WHERE name = 'spt-vis-test'), + 1::BIGINT, + 'BR1 can see its own pattern at consortial sharing depth' +); +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(7) + WHERE name = 'spt-vis-test'), + 1::BIGINT, + 'BR4 can see it as well at consortial sharing depth' +); +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(8) + WHERE name = 'spt-vis-test'), + 1::BIGINT, + 'SL1 can see it as well at consortial sharing depth' +); + +UPDATE serial.pattern_template SET share_depth = 2 WHERE name = 'spt-vis-test'; + +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(4) + WHERE name = 'spt-vis-test'), + 1::BIGINT, + 'BR1 can still see own pattern at branch sharing depth' +); +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(7) + WHERE name = 'spt-vis-test'), + 0::BIGINT, + 'BR4 CANNOT see it at branch sharing depth' +); +SELECT is( + (SELECT COUNT(*) FROM serial.pattern_templates_visible_to(8) + WHERE name = 'spt-vis-test'), + 1::BIGINT, + 'SL1 can still see it at branch sharing depth' +); + +ROLLBACK; diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.serial_pattern_templates.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.serial_pattern_templates.sql new file mode 100644 index 0000000000..d396682841 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.serial_pattern_templates.sql @@ -0,0 +1,25 @@ +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +CREATE TABLE serial.pattern_template ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + pattern_code TEXT NOT NULL, + owning_lib INTEGER REFERENCES actor.org_unit(id) DEFERRABLE INITIALLY DEFERRED, + share_depth INTEGER NOT NULL DEFAULT 0 +); +CREATE INDEX serial_pattern_template_name_idx ON serial.pattern_template (evergreen.lowercase(name)); + +CREATE OR REPLACE FUNCTION serial.pattern_templates_visible_to(org_unit INT) RETURNS SETOF serial.pattern_template AS $func$ +BEGIN + RETURN QUERY SELECT * + FROM serial.pattern_template spt + WHERE ( + SELECT ARRAY_AGG(id) + FROM actor.org_unit_descendants(spt.owning_lib, spt.share_depth) + ) @@ org_unit::TEXT::QUERY_INT; +END; +$func$ LANGUAGE PLPGSQL; + +COMMIT; diff --git a/Open-ILS/src/sql/Pg/upgrade/YYYY.data.spt_perms.sql b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.spt_perms.sql new file mode 100644 index 0000000000..2ceef9134f --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/YYYY.data.spt_perms.sql @@ -0,0 +1,24 @@ +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +INSERT INTO permission.perm_list ( id, code, description ) VALUES + ( 593, 'ADMIN_SERIAL_PATTERN_TEMPLATE', oils_i18n_gettext( 593, + 'Administer serial prediction pattern templates', 'ppl', 'description' )) +; + +INSERT INTO permission.grp_perm_map (grp, perm, depth, grantable) + SELECT + pgt.id, perm.id, aout.depth, FALSE + FROM + permission.grp_tree pgt, + permission.perm_list perm, + actor.org_unit_type aout + WHERE + pgt.name = 'Serials' AND + aout.name = 'System' AND + perm.code IN ( + 'ADMIN_SERIAL_PATTERN_TEMPLATE' + ); + +COMMIT; diff --git a/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.issuance_scap_fkey.sql b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.issuance_scap_fkey.sql new file mode 100644 index 0000000000..d27f8bc974 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/ZZZZ.schema.issuance_scap_fkey.sql @@ -0,0 +1,18 @@ +BEGIN; + +ALTER TABLE serial.issuance DROP CONSTRAINT IF EXISTS issuance_caption_and_pattern_fkey; + +-- Using NOT VALID and VALIDATE CONSTRAINT limits the impact to concurrent work. +-- For details, see: https://www.postgresql.org/docs/current/static/sql-altertable.html + +ALTER TABLE serial.issuance ADD CONSTRAINT issuance_caption_and_pattern_fkey + FOREIGN KEY (caption_and_pattern) + REFERENCES serial.caption_and_pattern (id) + ON DELETE CASCADE + DEFERRABLE INITIALLY DEFERRED + NOT VALID; + +ALTER TABLE serial.issuance VALIDATE CONSTRAINT issuance_caption_and_pattern_fkey; + +COMMIT; + diff --git a/Open-ILS/src/templates/staff/admin/local/t_splash.tt2 b/Open-ILS/src/templates/staff/admin/local/t_splash.tt2 index cdcccb7967..82599b34eb 100644 --- a/Open-ILS/src/templates/staff/admin/local/t_splash.tt2 +++ b/Open-ILS/src/templates/staff/admin/local/t_splash.tt2 @@ -29,7 +29,6 @@ ,[ l('Notifications / Action Triggers'), "./admin/local/action_trigger/event_definition" ] ,[ l('Patrons with Negative Balances'), "./admin/local/circ/neg_balance_users" ] ,[ l('Search Filter Groups'), "./admin/local/actor/search_filter_group" ] - ,[ l('Serial Copy Template Editor'), "./admin/local/asset/copy_template" ] ,[ l('Standing Penalties'), "./admin/local/config/standing_penalty" ] ,[ l('Statistical Categories Editor'), "./admin/local/asset/stat_cat_editor" ] ,[ l('Statistical Popularity Badges'), "./admin/local/rating/badge" ] diff --git a/Open-ILS/src/templates/staff/admin/serials/index.tt2 b/Open-ILS/src/templates/staff/admin/serials/index.tt2 new file mode 100644 index 0000000000..2a54931c81 --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/index.tt2 @@ -0,0 +1,33 @@ +[% + WRAPPER "staff/base.tt2"; + ctx.page_title = l("Serials Administration"); + ctx.page_app = "egSerialsAdmin"; +%] + +[% BLOCK APP_JS %] + + + + + +[% END %] + +
+ +[% END %] + + diff --git a/Open-ILS/src/templates/staff/admin/serials/pattern_template.tt2 b/Open-ILS/src/templates/staff/admin/serials/pattern_template.tt2 new file mode 100644 index 0000000000..8ff79289c4 --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/pattern_template.tt2 @@ -0,0 +1,44 @@ +[% + WRAPPER "staff/base.tt2"; + ctx.page_title = l("Prediction Pattern Templates"); + ctx.page_app = "egAdminConfig"; + ctx.page_ctrl = 'PatternTemplate'; +%] + +[% BLOCK APP_JS %] + + + + +[% INCLUDE 'staff/serials/share/serials_strings.tt2' %] + + + + +[% END %] + +
+
+ [% l('Prediction Pattern Templates') %] +
+
+ + + + + + + + + + + + + + + +[% END %] diff --git a/Open-ILS/src/templates/staff/admin/serials/t_attr_edit.tt2 b/Open-ILS/src/templates/staff/admin/serials/t_attr_edit.tt2 new file mode 100644 index 0000000000..a4bfecf843 --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/t_attr_edit.tt2 @@ -0,0 +1,338 @@ + + +
+
+
+
+

[% l('Template Name') %]

+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+ [% l('Circulate?') %] +
+
+ [% l('Status') %] +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+ +
+
+ [% l('Circulation Library') %] +
+
+ [% l('Reference?') %] +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ [% l('Shelving Location') %] +
+
+ [% l('OPAC Visible?') %] +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ [% l('Circulation Modifer') %] +
+
+ [% l('Price') %] +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ [% l('Loan Duration') %] +
+
+ +
+
+ +
+
+ +
+ +
+
+ [% l('Circulate as Type') %] +
+
+ [% l('Deposit?') %] +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ [% l('Holdable?') %] +
+
+ [% l('Deposit Amount') %] +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+ +
+
+ [% l('Age-based Hold Protection') %] +
+
+ [% l('Quality') %] +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+ +
+
+ [% l('Fine Level') %] +
+
+ +
+
+ +
+
+ +
+ +
+
+ [% l('Floating') %] +
+
+ +
+
+ +
+
+
+ +
+
+
diff --git a/Open-ILS/src/templates/staff/admin/serials/t_splash.tt2 b/Open-ILS/src/templates/staff/admin/serials/t_splash.tt2 new file mode 100644 index 0000000000..308a31d8b1 --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/t_splash.tt2 @@ -0,0 +1,38 @@ + +
+
+ [% l('Serials Administration') %] +
+
+ +
+ +[% + interfaces = [ + [ l('Serial Copy Templates'), "./admin/serials/templates" ] + [ l('Prediction Pattern Templates'), "./admin/serials/pattern_template" ] + ]; + + USE table(interfaces, cols=3); +%] + +
+ [% FOREACH col = table.cols %] +
+ [% FOREACH item = col %][% IF item.1 %] +
+ +
+ [% END %] + [% END %] +
+ [% END %] +
+ +
+ diff --git a/Open-ILS/src/templates/staff/admin/serials/t_template_list.tt2 b/Open-ILS/src/templates/staff/admin/serials/t_template_list.tt2 new file mode 100644 index 0000000000..14f37ce029 --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/t_template_list.tt2 @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Open-ILS/src/templates/staff/admin/serials/t_templates.tt2 b/Open-ILS/src/templates/staff/admin/serials/t_templates.tt2 new file mode 100644 index 0000000000..547b39db1b --- /dev/null +++ b/Open-ILS/src/templates/staff/admin/serials/t_templates.tt2 @@ -0,0 +1,20 @@ +
+
+ [% l('Serials Templates') %] +
+
+ +
+
+
+ [% l('Owning Library') %] + +
+
+
+ +
+ +
+[% INCLUDE 'staff/admin/serials/t_template_list.tt2' %] +
diff --git a/Open-ILS/src/templates/staff/cat/catalog/index.tt2 b/Open-ILS/src/templates/staff/cat/catalog/index.tt2 index b98c3f14ec..3d19ca2646 100644 --- a/Open-ILS/src/templates/staff/cat/catalog/index.tt2 +++ b/Open-ILS/src/templates/staff/cat/catalog/index.tt2 @@ -11,6 +11,10 @@ +[% INCLUDE 'staff/serials/share/serials_strings.tt2' %] + + + [% INCLUDE 'staff/cat/share/marcedit_strings.tt2' %] @@ -49,6 +53,13 @@ "[% l('Item Transfer Target set') %]"; s.MARK_OVERLAY_TARGET = "[% l('Record Overlay Target set') %]"; + + s.SERIALS_NO_SUBS = "[% l('No subscription selected') %]"; + s.SERIALS_NO_ITEMS = "[% l('No items expected for the selected subscription') %]"; + + s.SERIALS_ISSUANCE_FAIL_SAVE = "[% l('Failed to save issuance') %]"; + s.SERIALS_ISSUANCE_SUCCESS_SAVE = "[% l('Issuance saved') %]"; + }]) diff --git a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 index bcb52df856..c1e326ea33 100644 --- a/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 +++ b/Open-ILS/src/templates/staff/cat/catalog/t_catalog.tt2 @@ -26,6 +26,22 @@ +
+ + +
+ + +
+ + + + + diff --git a/Open-ILS/src/templates/staff/serials/t_batch_receive.tt2 b/Open-ILS/src/templates/staff/serials/t_batch_receive.tt2 new file mode 100644 index 0000000000..cec2820355 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_batch_receive.tt2 @@ -0,0 +1,183 @@ +
+ + + + + +
diff --git a/Open-ILS/src/templates/staff/serials/t_chron_selector.tt2 b/Open-ILS/src/templates/staff/serials/t_chron_selector.tt2 new file mode 100644 index 0000000000..af5a43cdd5 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_chron_selector.tt2 @@ -0,0 +1,5 @@ + diff --git a/Open-ILS/src/templates/staff/serials/t_clone_subscription.tt2 b/Open-ILS/src/templates/staff/serials/t_clone_subscription.tt2 new file mode 100644 index 0000000000..038a57f543 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_clone_subscription.tt2 @@ -0,0 +1,57 @@ +
+ + + +
diff --git a/Open-ILS/src/templates/staff/serials/t_day_of_week_selector.tt2 b/Open-ILS/src/templates/staff/serials/t_day_of_week_selector.tt2 new file mode 100644 index 0000000000..19418611f0 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_day_of_week_selector.tt2 @@ -0,0 +1,9 @@ + diff --git a/Open-ILS/src/templates/staff/serials/t_holding_code_dialog.tt2 b/Open-ILS/src/templates/staff/serials/t_holding_code_dialog.tt2 new file mode 100644 index 0000000000..8346f0cd80 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_holding_code_dialog.tt2 @@ -0,0 +1,100 @@ +
+ + + + + +
diff --git a/Open-ILS/src/templates/staff/serials/t_item_manager.tt2 b/Open-ILS/src/templates/staff/serials/t_item_manager.tt2 new file mode 100644 index 0000000000..8c7227a5e0 --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_item_manager.tt2 @@ -0,0 +1,7 @@ +
+ +
+ +
+ +
diff --git a/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2 b/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2 new file mode 100644 index 0000000000..03820d284c --- /dev/null +++ b/Open-ILS/src/templates/staff/serials/t_link_mfhd.tt2 @@ -0,0 +1,35 @@ +
+ +