From 5d7c7c21e04599213e8f9227d1d9b68c06b2bd89 Mon Sep 17 00:00:00 2001 From: Matt Blenkinsop Date: Wed, 30 Aug 2023 13:16:28 +0000 Subject: [PATCH] Bug 19316: Add sort1 and sort2 fields to interface and allow editing This patch adds the new sort1 and sort2 fields to the interface so that they can be viewed and edited Test plan: 1) Apply patch and reset_all 2) In the catalog, search for a record with at least one item 3) In the Holdings table, click on the barcode for an item. You should now be on /cgi-bin/koha/catalogue/moredetail.pl 4) Scroll down and observe that there is now a section called "Sort fields" with two fields, Sort 1 and Sort 2. 5) Enter some text in the textarea for Sort 1 (max 50 characters) and click Update 6) The page will refresh and your text should still be visible. Check that item in the database and the text should be stored in the sort1 column. 7) Repeat steps 5-6 for Sort 2. 8) Copy the barcode and navigate to Cataloging > Batch item modification 9) Enter the barcode in the textarea under "Or scan items one by one" (You can add multiple bar codes here if you wish) 10) Fill in the Required values (Home library, Current library, Koha item type) 11) In "Other attributes" there should be two fields, Sort 1 and Sort 2 12) Enter some text into both these fields 13) Click save and a job will be enqueued 14) Click "view detail of the enqueued job" 15) A message should be shown on completion that says "X item(s) modified (with Y field(s) modified)." X should match the number of barcodes that you entered into the batch mod and Y should equal X x 2 16) Check the item either in the interface or the database and the text you entered should now be stored and visible 17) Repeat steps 8 - 14 but this time only fill in Sort 1 18) This time X should equal the number of barcodes that you entered into the batch mod but Y should equal X as only one field was filled in. 19) Again, the text you entered should now be stored on the item record Signed-off-by: baptiste --- Koha/BackgroundJob/BatchUpdateItem.pm | 34 +-- Koha/Items.pm | 210 ++++++++++-------- catalogue/updateitem.pl | 26 ++- .../prog/en/modules/catalogue/moredetail.tt | 32 +++ .../prog/en/modules/tools/batchMod-edit.tt | 12 + tools/batchMod.pl | 27 ++- 6 files changed, 205 insertions(+), 136 deletions(-) diff --git a/Koha/BackgroundJob/BatchUpdateItem.pm b/Koha/BackgroundJob/BatchUpdateItem.pm index 63f6f71d40e..a140249d795 100644 --- a/Koha/BackgroundJob/BatchUpdateItem.pm +++ b/Koha/BackgroundJob/BatchUpdateItem.pm @@ -92,41 +92,43 @@ sub process { $self->start; - my @record_ids = @{ $args->{record_ids} }; - my $regex_mod = $args->{regex_mod}; - my $new_values = $args->{new_values}; - my $exclude_from_local_holds_priority = - $args->{exclude_from_local_holds_priority}; - my $mark_items_returned = - $args->{mark_items_returned}; + my @record_ids = @{ $args->{record_ids} }; + my $regex_mod = $args->{regex_mod}; + my $new_values = $args->{new_values}; + my $exclude_from_local_holds_priority = $args->{exclude_from_local_holds_priority}; + my $mark_items_returned = $args->{mark_items_returned}; + my $sort1 = $args->{sort1}; + my $sort2 = $args->{sort2}; my $report = { - total_records => scalar @record_ids, - modified_fields => 0, + total_records => scalar @record_ids, + modified_fields => 0, }; try { my ($results) = Koha::Items->search( { itemnumber => \@record_ids } )->batch_update( - { regex_mod => $regex_mod, + { + regex_mod => $regex_mod, new_values => $new_values, exclude_from_local_holds_priority => $exclude_from_local_holds_priority, mark_items_returned => $mark_items_returned, + sort1 => $sort1, + sort2 => $sort2, callback => sub { $self->step; }, } ); $report->{modified_itemnumbers} = $results->{modified_itemnumbers}; $report->{modified_fields} = $results->{modified_fields}; - } - catch { + } catch { warn $_; die "Something terrible has happened!" - if ( $_ =~ /Rollback failed/ ); # Rollback failed + if ( $_ =~ /Rollback failed/ ); # Rollback failed }; my $data = $self->decoded_data; $data->{report} = $report; - $self->finish( $data ); + $self->finish($data); } =head3 enqueue @@ -167,9 +169,7 @@ sub additional_report { if ( scalar(@$itemnumbers) > C4::Context->preference('MaxItemsToDisplayForBatchMod') ) { return { too_many_items_display => 1 }; } else { - my $items_table = - Koha::UI::Table::Builder::Items->new( { itemnumbers => $itemnumbers } ) - ->build_table; + my $items_table = Koha::UI::Table::Builder::Items->new( { itemnumbers => $itemnumbers } )->build_table; return { items => $items_table->{items}, diff --git a/Koha/Items.pm b/Koha/Items.pm index 1676a875970..8671b85dd81 100644 --- a/Koha/Items.pm +++ b/Koha/Items.pm @@ -220,7 +220,7 @@ sub move_to_biblio { =head3 batch_update - Koha::Items->search->batch_update + Koha::Items->search->batch_update( { new_values => { itemnotes => $new_item_notes, @@ -280,126 +280,142 @@ Callback function to call after an item has been modified sub batch_update { my ( $self, $params ) = @_; - my $regex_mod = $params->{regex_mod} || {}; - my $new_values = $params->{new_values} || {}; + my $regex_mod = $params->{regex_mod} || {}; + my $new_values = $params->{new_values} || {}; my $exclude_from_local_holds_priority = $params->{exclude_from_local_holds_priority}; - my $mark_items_returned = $params->{mark_items_returned}; - my $callback = $params->{callback}; + my $mark_items_returned = $params->{mark_items_returned}; + my $sort1 = $params->{sort1}; + my $sort2 = $params->{sort2}; + my $callback = $params->{callback}; my (@modified_itemnumbers, $modified_fields); my $i; my $schema = Koha::Database->new->schema; while ( my $item = $self->next ) { - try {$schema->txn_do(sub { - my $modified_holds_priority = 0; - my $item_returned = 0; - if ( defined $exclude_from_local_holds_priority ) { - if(!defined $item->exclude_from_local_holds_priority || $item->exclude_from_local_holds_priority != $exclude_from_local_holds_priority) { - $item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store; - $modified_holds_priority = 1; - } - } + try { + $schema->txn_do( + sub { + my $modified_holds_priority = 0; + my $item_returned = 0; + my $sort_fields_modified = 0; + if ( defined $exclude_from_local_holds_priority ) { + if ( !defined $item->exclude_from_local_holds_priority + || $item->exclude_from_local_holds_priority != $exclude_from_local_holds_priority ) + { + $item->exclude_from_local_holds_priority($exclude_from_local_holds_priority)->store; + $modified_holds_priority = 1; + } + } + if ( defined $sort1 || defined $sort2 ) { + $item->sort1($sort1)->store if $sort1 ne ""; + $sort_fields_modified++ if $sort1 ne ""; + $item->sort2($sort2)->store if $sort2 ne ""; + $sort_fields_modified++ if $sort2 ne ""; + } - my $modified = 0; - my $new_values = {%$new_values}; # Don't modify the original + my $modified = 0; + my $new_values = {%$new_values}; # Don't modify the original - my $old_values = $item->unblessed; - if ( $item->more_subfields_xml ) { - $old_values = { - %$old_values, - %{$item->additional_attributes->to_hashref}, - }; - } + my $old_values = $item->unblessed; + if ( $item->more_subfields_xml ) { + $old_values = { + %$old_values, + %{ $item->additional_attributes->to_hashref }, + }; + } + + for my $attr ( keys %$regex_mod ) { + my $old_value = $old_values->{$attr}; - for my $attr ( keys %$regex_mod ) { - my $old_value = $old_values->{$attr}; + next unless $old_value; - next unless $old_value; + my $value = apply_regex( + { + %{ $regex_mod->{$attr} }, + value => $old_value, + } + ); - my $value = apply_regex( - { - %{ $regex_mod->{$attr} }, - value => $old_value, + $new_values->{$attr} = $value; } - ); - $new_values->{$attr} = $value; - } + for my $attribute ( keys %$new_values ) { + next if $attribute eq 'more_subfields_xml'; # Already counted before - for my $attribute ( keys %$new_values ) { - next if $attribute eq 'more_subfields_xml'; # Already counted before + my $old = $old_values->{$attribute}; + my $new = $new_values->{$attribute}; + $modified++ + if ( defined $old xor defined $new ) + || ( defined $old && defined $new && $new ne $old ); + } - my $old = $old_values->{$attribute}; - my $new = $new_values->{$attribute}; - $modified++ - if ( defined $old xor defined $new ) - || ( defined $old && defined $new && $new ne $old ); - } + { # Dealing with more_subfields_xml - { # Dealing with more_subfields_xml - - my $frameworkcode = $item->biblio->frameworkcode; - my $tagslib = C4::Biblio::GetMarcStructure( 1, $frameworkcode, { unsafe => 1 }); - my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField( "items.itemnumber" ); - - my @more_subfield_tags = map { - ( - ref($_) - && %$_ - && !$_->{kohafield} # Get subfields that are not mapped - ) - ? $_->{tagsubfield} - : () - } values %{ $tagslib->{$itemtag} }; - - my $more_subfields_xml = Koha::Item::Attributes->new( - { - map { - exists $new_values->{$_} ? ( $_ => $new_values->{$_} ) - : exists $old_values->{$_} - ? ( $_ => $old_values->{$_} ) - : () - } @more_subfield_tags - } - )->to_marcxml($frameworkcode); + my $frameworkcode = $item->biblio->frameworkcode; + my $tagslib = C4::Biblio::GetMarcStructure( 1, $frameworkcode, { unsafe => 1 } ); + my ( $itemtag, $itemsubfield ) = C4::Biblio::GetMarcFromKohaField("items.itemnumber"); - $new_values->{more_subfields_xml} = $more_subfields_xml; + my @more_subfield_tags = map { + ( + ref($_) + && %$_ + && !$_->{kohafield} # Get subfields that are not mapped + ) + ? $_->{tagsubfield} + : () + } values %{ $tagslib->{$itemtag} }; - delete $new_values->{$_} for @more_subfield_tags; # Clean the hash + my $more_subfields_xml = Koha::Item::Attributes->new( + { + map { + exists $new_values->{$_} ? ( $_ => $new_values->{$_} ) + : exists $old_values->{$_} ? ( $_ => $old_values->{$_} ) + : () + } @more_subfield_tags + } + )->to_marcxml($frameworkcode); - } + $new_values->{more_subfields_xml} = $more_subfields_xml; - if ( $modified ) { - my $itemlost_pre = $item->itemlost; - $item->set($new_values)->store({skip_record_index => 1}); + delete $new_values->{$_} for @more_subfield_tags; # Clean the hash - C4::Circulation::LostItem( - $item->itemnumber, 'batchmod', undef, - { skip_record_index => 1 } - ) if $item->itemlost - and not $itemlost_pre; - } - if ( $mark_items_returned ){ - my $issue = $item->checkout; - if( $issue ){ - $item_returned = 1; - C4::Circulation::MarkIssueReturned( - $issue->borrowernumber, - $item->itemnumber, - undef, - $issue->patron->privacy, - { - skip_record_index => 1, - skip_holds_queue => 1, + } + + if ($modified) { + my $itemlost_pre = $item->itemlost; + $item->set($new_values)->store( { skip_record_index => 1 } ); + + C4::Circulation::LostItem( + $item->itemnumber, 'batchmod', undef, + { skip_record_index => 1 } + ) + if $item->itemlost + and not $itemlost_pre; + } + if ($mark_items_returned) { + my $issue = $item->checkout; + if ($issue) { + $item_returned = 1; + C4::Circulation::MarkIssueReturned( + $issue->borrowernumber, + $item->itemnumber, + undef, + $issue->patron->privacy, + { + skip_record_index => 1, + skip_holds_queue => 1, + } + ); } - ); - } - } + } - push @modified_itemnumbers, $item->itemnumber if $modified || $modified_holds_priority || $item_returned; - $modified_fields += $modified + $modified_holds_priority + $item_returned; - })} + push @modified_itemnumbers, $item->itemnumber + if $modified || $modified_holds_priority || $item_returned || $sort_fields_modified; + $modified_fields += $modified + $modified_holds_priority + $item_returned + $sort_fields_modified; + } + ) + } catch { warn $_ }; diff --git a/catalogue/updateitem.pl b/catalogue/updateitem.pl index 5b092763dfa..64bc6b26827 100755 --- a/catalogue/updateitem.pl +++ b/catalogue/updateitem.pl @@ -29,17 +29,19 @@ my $cgi= CGI->new; checkauth($cgi, 0, {circulate => 'circulate_remaining_permissions'}, 'intranet'); -my $op = $cgi->param('op') || ""; -my $biblionumber=$cgi->param('biblionumber'); -my $itemnumber=$cgi->param('itemnumber'); -my $biblioitemnumber=$cgi->param('biblioitemnumber'); -my $itemlost=$cgi->param('itemlost'); -my $itemnotes=$cgi->param('itemnotes'); -my $itemnotes_nonpublic=$cgi->param('itemnotes_nonpublic'); -my $withdrawn=$cgi->param('withdrawn'); -my $damaged=$cgi->param('damaged'); +my $op = $cgi->param('op') || ""; +my $biblionumber = $cgi->param('biblionumber'); +my $itemnumber = $cgi->param('itemnumber'); +my $biblioitemnumber = $cgi->param('biblioitemnumber'); +my $itemlost = $cgi->param('itemlost'); +my $itemnotes = $cgi->param('itemnotes'); +my $itemnotes_nonpublic = $cgi->param('itemnotes_nonpublic'); +my $withdrawn = $cgi->param('withdrawn'); +my $damaged = $cgi->param('damaged'); my $exclude_from_local_holds_priority = $cgi->param('exclude_from_local_holds_priority'); -my $bookable = $cgi->param('bookable'); +my $bookable = $cgi->param('bookable'); +my $sort1 = $cgi->param('sort1'); +my $sort2 = $cgi->param('sort2'); my $confirm=$cgi->param('confirm'); my $dbh = C4::Context->dbh; @@ -80,6 +82,10 @@ elsif ( $op eq "cud-set_public_note" ) { # i.e., itemnotes parameter passed from $item->bookable($bookable); } elsif ( $op eq "cud-set_damaged" && $damaged ne $item_data_hashref->{'damaged'}) { $item->damaged($damaged); +} elsif ( $op eq "set_sort1" && $sort1 ne $item_data_hashref->{'sort1'} ) { + $item->sort1($sort1); +} elsif ( $op eq "set_sort2" && $sort2 ne $item_data_hashref->{'sort2'} ) { + $item->sort2($sort2); } else { #nothings changed, so do nothing. print $cgi->redirect("moredetail.pl?biblionumber=$biblionumber&itemnumber=$itemnumber#item$itemnumber"); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt index 6ef020cecbd..db9e8b10ade 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt @@ -378,6 +378,38 @@ +
+

Sort fields

+
+
    +
  1. + Sort 1: + [% IF ( CAN_user_editcatalogue_edit_items ) %] +
    + + + +
    + [% ELSE %] + [% ITEM_DAT.sort1 | html %] + [% END %] +
  2. +
  3. + Sort 2: + [% IF ( CAN_user_editcatalogue_edit_items ) %] +
    + + + +
    + [% ELSE %] + [% ITEM_DAT.sort2 | html %] + [% END %] +
  4. +
+
+
+

History

diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-edit.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-edit.tt index 1b442b5fcf8..bda70fd9389 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-edit.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/batchMod-edit.tt @@ -218,6 +218,18 @@
+
  • +
    + + +
    +
  • +
  • +
    + + +
    +
  • diff --git a/tools/batchMod.pl b/tools/batchMod.pl index 1b432318571..28926698de9 100755 --- a/tools/batchMod.pl +++ b/tools/batchMod.pl @@ -41,18 +41,20 @@ use Koha::BackgroundJob::BatchUpdateItem; use Koha::UI::Form::Builder::Item; use Koha::UI::Table::Builder::Items; -my $input = CGI->new; -my $dbh = C4::Context->dbh; -my $error = $input->param('error'); -my @itemnumbers = $input->multi_param('itemnumber'); -my $biblionumber = $input->param('biblionumber'); -my $op = $input->param('op'); -my $del = $input->param('del'); -my $del_records = $input->param('del_records'); -my $src = $input->param('src'); -my $use_default_values = $input->param('use_default_values'); +my $input = CGI->new; +my $dbh = C4::Context->dbh; +my $error = $input->param('error'); +my @itemnumbers = $input->multi_param('itemnumber'); +my $biblionumber = $input->param('biblionumber'); +my $op = $input->param('op'); +my $del = $input->param('del'); +my $del_records = $input->param('del_records'); +my $src = $input->param('src'); +my $use_default_values = $input->param('use_default_values'); my $exclude_from_local_holds_priority = $input->param('exclude_from_local_holds_priority'); -my $mark_items_returned = $input->param('mark_items_returned'); +my $sort1 = $input->param('sort1'); +my $sort2 = $input->param('sort2'); +my $mark_items_returned = $input->param('mark_items_returned'); my $template_name; my $template_flag; @@ -177,7 +179,8 @@ if ( $op eq "cud-action" ) { && $mark_items_returned ne "" ) ? $mark_items_returned : undef, - + sort1 => ( defined $sort1 && $sort1 ne "" ) ? $sort1 : undef, + sort2 => ( defined $sort2 && $sort2 ne "" ) ? $sort2 : undef, }; try { my $job_id = -- 2.39.3 (Apple Git-146)