From a45ecfce64b6768b395ae89a303393d06ce86a48 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 12 Dec 2017 14:14:56 -0300 Subject: [PATCH] =?UTF-8?q?Bug=2019287:=20Add=20ability=20to=20mark=20an?= =?UTF-8?q?=20item=20=E2=80=98Lost=E2=80=99=20from=20=E2=80=98Holds=20to?= =?UTF-8?q?=20pull=E2=80=99=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal to this enhancement is to add the ability to cancel a hold and mark items as lost from the ‘Holds to pull’ page. A new pref is added to control the behaviour, default is off To mark items as lost you need to set the new pref CanMarkHoldsToPullAsLost to one of these two values: - "Allow to mark items as lost" => The item will be marked as lost and the hold will be cancelled - "Allow to mark items as lost and notify the patron" => Same as previously but the patron will be notified as well. The notification is done using a new notice template (code=CANCEL_HOLD_ON_LOST). Feel free to suggest another default wording. To update the values of the items when one of these 2 buttons are used, you need to fill the UpdateItemWhenLostFromHoldList with something like: 'itemlost: 1' Test plan: 1/ Place holds on some items 2/ Go to Home › Circulation › Holds to pull From here you can cancel the hold or 3/ Mark the items as lost => You will receive feedback messages depending on different situations: * The CANCEL_HOLD_ON_LOST does not exist * The patron does not have an email address (but the notice has been enqueued! It is the current behaviour with other notices) * The notice has been enqueued * The hold has been cancelled QA Notes: From which library do we want to pick the notice? This patch use reserves.branchcode --- circ/pendingreserves.pl | 93 +++++++++++++++++++++- installer/data/mysql/atomicupdate/bug_19287.sql | 5 ++ installer/data/mysql/sysprefs.sql | 2 + .../en/modules/admin/preferences/circulation.pref | 12 +++ .../prog/en/modules/circ/pendingreserves.tt | 44 ++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_19287.sql diff --git a/circ/pendingreserves.pl b/circ/pendingreserves.pl index 15873201b1..2e1612f8a9 100755 --- a/circ/pendingreserves.pl +++ b/circ/pendingreserves.pl @@ -25,16 +25,21 @@ use C4::Context; use C4::Output; use CGI qw ( -utf8 ); use C4::Auth; -use Koha::Biblios; use C4::Debug; +use C4::Items qw( ModItem ModItemTransfer ); +use C4::Reserves qw( ModReserveCancelAll ); +use Koha::Biblios; use Koha::DateUtils; +use Koha::Holds; use DateTime::Duration; my $input = new CGI; my $startdate = $input->param('from'); my $enddate = $input->param('to'); - my $theme = $input->param('theme'); # only used if allowthemeoverride is set +my $op = $input->param('op') || ''; +my $borrowernumber = $input->param('borrowernumber'); +my $reserve_id = $input->param('reserve_id'); my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { @@ -47,6 +52,80 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( } ); +my @messages; +if ( $op eq 'cancel_reserve' and $reserve_id ) { + my $hold = Koha::Holds->find( $reserve_id ); + if ( $hold ) { + $hold->cancel; + push @messages, { type => 'message', code => 'hold_cancelled' }; + } +} elsif ( $op =~ m|^mark_as_lost| ) { + my $hold = Koha::Holds->find( $reserve_id ); + die "wrong reserve_id" unless $hold; # This is a bit rude, but we are not supposed to get a wrong reserve_id + my $item = $hold->item; + if ( $item and C4::Context->preference('CanMarkHoldsToPullAsLost') =~ m|^allow| ) { + my $patron = $hold->borrower; + C4::Circulation::LostItem( $item->itemnumber ); + if ( $op eq 'mark_as_lost_and_notify' and C4::Context->preference('CanMarkHoldsToPullAsLost') eq 'allow_and_notify' ) { + my $library = $hold->branch; + my $letter = C4::Letters::GetPreparedLetter( + module => 'reserves', + letter_code => 'CANCEL_HOLD_ON_LOST', + branchcode => $library->branchcode, # FIXME Is it what we want? + lang => $patron->lang, + tables => { + branches => $library->branchcode, + borrowers => $patron->borrowernumber, + items => $item->itemnumber, + biblio => $hold->biblionumber, + biblioitems => $hold->biblionumber, + reserves => $hold->unblessed, + }, + ); + if ( $letter ) { + my $admin_email_address = $library->branchemail || C4::Context->preference('KohaAdminEmailAddress'); + + C4::Letters::EnqueueLetter( + { letter => $letter, + borrowernumber => $patron->borrowernumber, + message_transport_type => 'email', + from_address => $admin_email_address, + } + ); + unless ( C4::Members::GetNoticeEmailAddress( $patron->borrowernumber ) ) { + push @messages, {type => 'alert', code => 'no_email_address', }; + } + push @messages, { type => 'message', code => 'letter_enqueued' }; + } else { + push @messages, { type => 'error', code => 'no_template_notice' }; + } + } + $hold->cancel; + if ( $item->homebranch ne $item->holdingbranch ) { + C4::Items::ModItemTransfer( $item->itemnumber, $item->holdingbranch, $item->homebranch ); + } + + if ( my $yaml = C4::Context->preference('UpdateItemWhenLostFromHoldList') ) { + $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt + my $assignments; + eval { $assignments = YAML::Load($yaml); }; + if ($@) { + warn "Unable to parse UpdateItemWhenLostFromHoldList syspref : $@" if $@; + } + else { + eval { + C4::Items::ModItem( $assignments, undef, $item->itemnumber ); + }; + warn "Unable to modify item itemnumber=" . $item->itemnumber . ": $@" if $@; + } + } + + } elsif ( not $item ) { + push @messages, { type => 'alert', code => 'hold_placed_at_biblio_level'}; + } # else the url parameters have been modified and the user is not allowed to continue +} + + my $today = dt_from_string; if ( $startdate ) { @@ -91,11 +170,16 @@ if ($enddate_iso) { my $strsth = "SELECT min(reservedate) as l_reservedate, + reserves.reserve_id, reserves.borrowernumber as borrowernumber, + GROUP_CONCAT(DISTINCT items.holdingbranch ORDER BY items.itemnumber SEPARATOR '|') l_holdingbranch, reserves.biblionumber, reserves.branchcode as l_branch, + items.itemnumber, + items.holdingbranch, + items.homebranch, GROUP_CONCAT(DISTINCT items.itype ORDER BY items.itemnumber SEPARATOR '|') l_itype, GROUP_CONCAT(DISTINCT items.location @@ -167,6 +251,10 @@ while ( my $data = $sth->fetchrow_hashref ) { pullcount => $data->{icount} <= $data->{rcount} ? $data->{icount} : $data->{rcount}, itypes => [split('\|', $data->{l_itype})], locations => [split('\|', $data->{l_location})], + reserve_id => $data->{reserve_id}, + holdingbranch => $data->{holdingbranch}, + homebranch => $data->{homebranch}, + itemnumber => $data->{itemnumber}, } ); } @@ -180,6 +268,7 @@ $template->param( "BiblioDefaultView".C4::Context->preference("BiblioDefaultView") => 1, HoldsToPullStartDate => C4::Context->preference('HoldsToPullStartDate') || PULL_INTERVAL, HoldsToPullEndDate => C4::Context->preference('ConfirmFutureHolds') || 0, + messages => \@messages, ); output_html_with_http_headers $input, $cookie, $template->output; diff --git a/installer/data/mysql/atomicupdate/bug_19287.sql b/installer/data/mysql/atomicupdate/bug_19287.sql new file mode 100644 index 0000000000..d5d03a999d --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_19287.sql @@ -0,0 +1,5 @@ +INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('CanMarkHoldsToPullAsLost','do_not_allow','do_not_allow|allow|allow_and_notify','Add a button to the "Holds to pull" screen to mark an item as lost and notify the patron.','Choice'); + +INSERT IGNORE INTO letter(module, code, branchcode, name, is_html, title, content, message_transport_type, lang) VALUES ('reserves', 'CANCEL_HOLD_ON_LOST', '', 'Hold has been cancelled', 0, "Hold has been cancelled", "Dear [% borrower.firstname %] [% borrower.surname %],\n\nWe regret to inform you that the following item cannot longer be placed on hold, it has been marked as lost\n\nTitle: [% biblio.title %]\nAuthor: [% biblio.author %]\nCopy: [% item.copynumber %]\nLocation: [% branch.branchname %]", 'email', 'default'); + +INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES ('UpdateItemWhenLostFromHoldList','',NULL,'This is a list of values to update an item when it is marked as lost from the holds to pull screen','Free'); diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql index 23cefb8723..360c5dea40 100644 --- a/installer/data/mysql/sysprefs.sql +++ b/installer/data/mysql/sysprefs.sql @@ -93,6 +93,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('BranchTransferLimitsType','ccode','itemtype|ccode','When using branch transfer limits, choose whether to limit by itemtype or collection code.','Choice'), ('CalculateFinesOnReturn','1','','Switch to control if overdue fines are calculated on return or not','YesNo'), ('CalendarFirstDayOfWeek','0','0|1|2|3|4|5|6','Select the first day of week to use in the calendar.','Choice'), +('CanMarkHoldsToPullAsLost','do_not_allow','do_not_allow|allow|allow_and_notify','Add a button to the "Holds to pull" screen to mark an item as lost and notify the patron.','Choice'), ('canreservefromotherbranches','1','','With Independent branches on, can a user from one library place a hold on an item from another library','YesNo'), ('CardnumberLength', '', '', 'Set a length for card numbers with a maximum of 32 characters.', 'Free'), ('casAuthentication','0','','Enable or disable CAS authentication','YesNo'), @@ -558,6 +559,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('UNIMARCAuthorityField100','afrey50 ba0',NULL,'Define the contents of UNIMARC authority control field 100 position 08-35','Textarea'), ('UNIMARCAuthorsFacetsSeparator',', ',NULL,'UNIMARC authors facets separator','short'), ('UNIMARCField100Language','fre',NULL,'UNIMARC field 100 default language','short'), +('UpdateItemWhenLostFromHoldList','',NULL,'This is a list of values to update an item when it is marked as lost from the holds to pull screen','Free'), ('UniqueItemFields','barcode','','Space-separated list of fields that should be unique (used in acquisition module for item creation). Fields must be valid SQL column names of items table','Free'), ('UpdateNotForLoanStatusOnCheckin', '', 'NULL', 'This is a list of value pairs. When an item is checked in, if the not for loan value on the left matches the items not for loan value it will be updated to the right-hand value. E.g. ''-1: 0'' will cause an item that was set to ''Ordered'' to now be available for loan. Each pair of values should be on a separate line.', 'Free'), ('UpdateTotalIssuesOnCirc','0',NULL,'Whether to update the totalissues field in the biblio on each circ.','YesNo'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index 6589e3e836..d0b4b88086 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -702,6 +702,18 @@ Circulation: - "Patron categories not affected by OPACHoldsIfAvailableAtPickup" - pref: OPACHoldsIfAvailableAtPickupExceptions - "(list of patron categories separated with a pipe '|')" + - + - pref: CanMarkHoldsToPullAsLost + choices: + do_not_allow: "Do not allow to mark items as lost" + allow: "Allow to mark items as lost" + allow_and_notify: "Allow to mark items as lost and notify the patron" + - "from the 'Holds to pull' screen" + - + - Update item's values when marked as lost from the hold to pull screen + - pref: UpdateItemWhenLostFromHoldList + type: textarea + - This is a list of values to update an item when it is marked as lost from the holds to pull screen. Interlibrary Loans: - - pref: ILLModule diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt index f2e443d45f..00917a05d6 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/pendingreserves.tt @@ -1,3 +1,4 @@ +[% USE Koha %] [% USE KohaDates %] [% USE ColumnsSettings %] [% USE AuthorisedValues %] @@ -22,6 +23,24 @@
+ [% FOR m IN messages %] +
+ [% SWITCH m.code %] + [% CASE 'letter_enqueued' %] + The notice has been correctly enqueued. + [% CASE 'no_email_address' %] + The patron does not have an email address defined. + [% CASE 'no_template_notice' %] + There is no notice template with a code 'CANCEL_HOLD_ON_LOST' defined in your system. + [% CASE 'hold_cancelled' %] + The hold has been correctly cancelled. + [% CASE 'hold_placed_at_biblio_level' %] + The hold has been placed at biblio level. It is not possible to mark it as lost. + [% CASE %] + [% m.code %] + [% END %] +
+ [% END %]

Holds to pull placed between [% from | $KohaDates %] and [% to | $KohaDates %]

Reported on [% todaysdate | $KohaDates %]

@@ -43,6 +62,7 @@ Available itypes Available locations Earliest hold date + Action @@ -87,6 +107,29 @@ [% reserveloo.reservedate | $KohaDates %] in [% Branches.GetName ( reserveloo.branch ) %] + +
+ + + [% IF reserveloo.holdingbranch != reserveloo.homebranch %] + + [% ELSE %] + + [% END %] +
+ + [% IF Koha.Preference('CanMarkHoldsToPullAsLost') != 'do_not_allow' %] +
+ + [% IF Koha.Preference('CanMarkHoldsToPullAsLost') == 'allow' %] + + + [% ELSIF Koha.Preference('CanMarkHoldsToPullAsLost') == 'allow_and_notify' %] + + + [% END %] +
+ [% END %] [% END %] @@ -104,6 +147,7 @@ + -- 2.11.0