Bugzilla – Attachment 128948 Details for
Bug 27208
Add a configurable time delay feature to hold notice templates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 27208: Add the ability to delay pickup notices.
Bug-27208-Add-the-ability-to-delay-pickup-notices.patch (text/plain), 23.41 KB, created by
Björn Nylén
on 2022-01-02 16:08:48 UTC
(
hide
)
Description:
Bug 27208: Add the ability to delay pickup notices.
Filename:
MIME Type:
Creator:
Björn Nylén
Created:
2022-01-02 16:08:48 UTC
Size:
23.41 KB
patch
obsolete
>From 5de0993363a68c1042473ccc70f99d22d32c591c Mon Sep 17 00:00:00 2001 >From: =?UTF-8?q?Bj=C3=B6rn=20Nyl=C3=A9n?= <bjorn.nylen@ub.lu.se> >Date: Tue, 14 Dec 2021 08:34:30 +0000 >Subject: [PATCH] Bug 27208: Add the ability to delay pickup notices. > >This bug adds the ability to delay sending a pickup notice. This can be done in two >ways, either by a fixed configurable delay of all pickup notices or a time selectable >by staff at checkin. This is controlled by two new system preferences, >PickupNoticeDelayMode and PickupNoticeDelayDuration. A delayed notice will also be >visible in the patron notice log. > >To test: > >1. Apply patch and run updatedatabase.pl to add new column to message_queue. >2. Check in items with holds with different delay modes ('no delay','fixed delay','selectable by staff'). >3. Check the patron notice logs to check notice delay. Delayed notices have status 'pending, delayed until...' >4. Expected behaviour is: > 'No delay': No notices are delayed. > 'Fixed delay': All pickup notices are delayed by the no of hours set in PickupNoticeDelayDuration. > 'Delay selectable by staff': Pickup notice is delayed until the time set in UI. If no delay is set, > notice will not be delayed. Also note the warning at the checkin page > when a delay is set. >5. Run process_message_queue.pl before and after the delay times above. Notices without delay are sent > immediatly, delayed notices are only sent after the set time. >6. Tests should pass. >--- > C4/Letters.pm | 8 +-- > C4/Reserves.pm | 26 ++++++++-- > circ/returns.pl | 15 +++++- > installer/data/mysql/mandatory/sysprefs.sql | 2 + > .../prog/en/includes/calendar.inc | 49 +++++++++++++++++++ > .../en/modules/admin/preferences/patrons.pref | 12 +++++ > .../prog/en/modules/circ/returns.tt | 31 +++++++++++- > .../prog/en/modules/members/notices.tt | 2 +- > 8 files changed, 133 insertions(+), 12 deletions(-) > >diff --git a/C4/Letters.pm b/C4/Letters.pm >index c36553ac9a..5a2420652d 100644 >--- a/C4/Letters.pm >+++ b/C4/Letters.pm >@@ -963,9 +963,9 @@ sub EnqueueLetter { > my $dbh = C4::Context->dbh(); > my $statement = << 'ENDSQL'; > INSERT INTO message_queue >-( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, reply_address, content_type, failure_code ) >+( borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, reply_address, content_type, failure_code, delay_until ) > VALUES >-( ?, ?, ?, ?, ?, ?, ?, CAST(NOW() AS DATETIME), ?, ?, ?, ?, ? ) >+( ?, ?, ?, ?, ?, ?, ?, CAST(NOW() AS DATETIME), ?, ?, ?, ?, ?, ?) > ENDSQL > > my $sth = $dbh->prepare($statement); >@@ -982,6 +982,7 @@ ENDSQL > $params->{'reply_address'}, # reply_address > $params->{'letter'}->{'content-type'}, # content_type > $params->{'failure_code'} || '', # failure_code >+ $params->{'delay_until'} || undef, # delay_until > ); > return $dbh->last_insert_id(undef,undef,'message_queue', undef); > } >@@ -1124,7 +1125,7 @@ sub GetQueuedMessages { > > my $dbh = C4::Context->dbh(); > my $statement = << 'ENDSQL'; >-SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, updated_on, failure_code >+SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, updated_on, failure_code, delay_until > FROM message_queue > ENDSQL > >@@ -1292,6 +1293,7 @@ sub _get_unsent_messages { > FROM message_queue mq > LEFT JOIN borrowers b ON b.borrowernumber = mq.borrowernumber > WHERE status = ? >+ AND ( delay_until < CURRENT_TIMESTAMP OR delay_until IS NULL) > }; > > my @query_params = ('pending'); >diff --git a/C4/Reserves.pm b/C4/Reserves.pm >index a42168bc72..ec2127adc0 100644 >--- a/C4/Reserves.pm >+++ b/C4/Reserves.pm >@@ -1173,7 +1173,7 @@ sub ModReserveStatus { > > =head2 ModReserveAffect > >- &ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend,$reserve_id, $desk_id); >+ &ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend,$reserve_id, $desk_id, $delay_notice_until); > > This function affect an item and a status for a given reserve, either fetched directly > by record_id, or by borrowernumber and itemnumber or biblionumber. If only biblionumber >@@ -1189,7 +1189,8 @@ This function also removes any entry of the hold in holds queue table. > =cut > > sub ModReserveAffect { >- my ( $itemnumber, $borrowernumber, $transferToDo, $reserve_id, $desk_id ) = @_; >+ my ( $itemnumber, $borrowernumber, $transferToDo, $reserve_id, $desk_id, $delay_notice_until) = @_; >+ > my $dbh = C4::Context->dbh; > > # we want to attach $itemnumber to $borrowernumber, find the biblionumber >@@ -1211,6 +1212,20 @@ sub ModReserveAffect { > > return unless $hold; > >+ # Handle notice delay >+ my $delay_notice_mode = C4::Context->preference('PickupNoticeDelayMode') || 'off'; >+ if ( $delay_notice_mode eq 'fixed'){ >+ my $delay_notice_duration = C4::Context->preference('PickupNoticeDelayDuration') || 0; >+ $delay_notice_until = dt_from_string()->add( hours => $delay_notice_duration ); >+ } >+ elsif ( $delay_notice_mode eq 'staff') { >+ $delay_notice_until = undef unless (ref($delay_notice_until) eq 'DateTime'); >+ warn "$delay_notice_until is no DateTime object" unless (ref($delay_notice_until) eq 'DateTime'); >+ } >+ else { >+ $delay_notice_until = undef; >+ } >+ > my $already_on_shelf = $hold->found && $hold->found eq 'W'; > > $hold->itemnumber($itemnumber); >@@ -1223,7 +1238,7 @@ sub ModReserveAffect { > $hold->set_processing(); > } else { > $hold->set_waiting($desk_id); >- _koha_notify_reserve( $hold->reserve_id ) unless $already_on_shelf; >+ _koha_notify_reserve( $hold->reserve_id , $delay_notice_until ) unless $already_on_shelf; > # Complete transfer if one exists > my $transfer = $hold->item->get_transfer; > $transfer->receive if $transfer; >@@ -1818,7 +1833,7 @@ sub _Findgroupreserve { > > =head2 _koha_notify_reserve > >- _koha_notify_reserve( $hold->reserve_id ); >+ _koha_notify_reserve( $hold->reserve_id, $delay_until ); > > Sends a notification to the patron that their hold has been filled (through > ModReserveAffect, _not_ ModReserveFill) >@@ -1845,7 +1860,7 @@ The following tables are availalbe witin the notice: > =cut > > sub _koha_notify_reserve { >- my $reserve_id = shift; >+ my ($reserve_id, $delay_until )= @_; > my $hold = Koha::Holds->find($reserve_id); > my $borrowernumber = $hold->borrowernumber; > >@@ -1894,6 +1909,7 @@ sub _koha_notify_reserve { > borrowernumber => $borrowernumber, > from_address => $admin_email_address, > message_transport_type => $mtt, >+ delay_until => $delay_until, > } ); > }; > >diff --git a/circ/returns.pl b/circ/returns.pl >index 8ab9986d91..3e58af357e 100755 >--- a/circ/returns.pl >+++ b/circ/returns.pl >@@ -86,6 +86,16 @@ my $userenv = C4::Context->userenv; > my $userenv_branch = $userenv->{'branch'} // ''; > my $forgivemanualholdsexpire = $query->param('forgivemanualholdsexpire'); > >+# Handle notice delay >+my $delay_notice_until = $query->param('delay_notice_until') || ''; >+my $notice_delay_mode = C4::Context->preference('PickupNoticeDelayMode') || 'off'; >+my $delay_notice_until_dt = undef; >+if ( $notice_delay_mode eq 'staff' && $delay_notice_until ){ >+ $delay_notice_until_dt = eval { dt_from_string( $delay_notice_until ) }; >+} else { >+ $delay_notice_until = ''; >+} >+ > my $overduecharges = (C4::Context->preference('finesMode') && C4::Context->preference('finesMode') eq 'production'); > > # Set up the item stack .... >@@ -150,7 +160,7 @@ if ( $query->param('reserve_id') ) { > my $diffBranchSend = ($userenv_branch ne $diffBranchReturned) ? $diffBranchReturned : undef; > # diffBranchSend tells ModReserveAffect whether document is expected in this library or not, > # i.e., whether to apply waiting status >- ModReserveAffect( $itemnumber, $borrowernumber, $diffBranchSend, $reserve_id, $desk_id ); >+ ModReserveAffect( $itemnumber, $borrowernumber, $diffBranchSend, $reserve_id, $desk_id, $delay_notice_until_dt ); > } > # check if we have other reserves for this document, if we have a return send the message of transfer > my ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber); >@@ -434,7 +444,7 @@ if ( $messages->{'ResFound'}) { > my $biblio = $item->biblio; > > my $diffBranchSend = !$branchCheck ? $reserve->{branchcode} : undef; >- ModReserveAffect( $reserve->{itemnumber}, $reserve->{borrowernumber}, $diffBranchSend, $reserve->{reserve_id}, $desk_id ); >+ ModReserveAffect( $reserve->{itemnumber}, $reserve->{borrowernumber}, $diffBranchSend, $reserve->{reserve_id}, $desk_id, $delay_notice_until_dt ); > my ( $messages, $nextreservinfo ) = GetOtherReserves($reserve->{itemnumber}); > > $template->param( >@@ -641,6 +651,7 @@ $template->param( > forgivemanualholdsexpire => $forgivemanualholdsexpire, > overduecharges => $overduecharges, > AudioAlerts => C4::Context->preference("AudioAlerts"), >+ delay_notice_until => $delay_notice_until, > ); > > if ( $barcode ) { >diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql >index 68877bbbce..31c3ae0873 100644 >--- a/installer/data/mysql/mandatory/sysprefs.sql >+++ b/installer/data/mysql/mandatory/sysprefs.sql >@@ -529,6 +529,8 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` > ('PatronsPerPage','20','20','Number of Patrons Per Page displayed by default','Integer'), > ('PatronQuickAddFields', '', NULL , 'A list of fields separated by "|" to be displayed along with mandatory fields in the patron quick add form if chosen at patron entry', 'Free' ), > ('PhoneNotification','0',NULL,'If ON, enables generation of phone notifications to be sent by plugins','YesNo'), >+('PickupNoticeDelayMode', 'off','off,fixed,staff', 'Delay mode for pickup notices', 'Choice' ), >+('PickupNoticeDelayDuration', '', NULL , 'Delay for pickup notices in hours if PickupNoticeDelayMode is set to "Fixed delay"', 'Integer' ), > ('PrefillGuaranteeField', 'phone,email,streetnumber,address,city,state,zipcode,country', NULL, 'Prefill these fields in guarantee member entry form from guarantor patron record', 'Multiple'), > ('PrefillItem','0','','When a new item is added, should it be prefilled with last created item values?','YesNo'), > ('PreserveSerialNotes','1','','When a new "Expected" issue is generated, should it be prefilled with last created issue notes?','YesNo'), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >index 2805870d10..8e06466eed 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/calendar.inc >@@ -155,6 +155,55 @@ > options['enableTime'] = true; > options['dateFormat'] = flatpickr_dateformat_string + " " + flatpickr_timeformat_string; > } >+ if ( $(this).data('flatpickr-futuredatetime') === true ) { >+ let original_date = $(this).val(); >+ if ( original_date ) { >+ original_date = DateTime_from_syspref( original_date ).getTime(); >+ let now = new Date().getTime(); >+ >+ options['enable'] = [function(date){ >+ date = date.getTime(); >+ if ( date == original_date ) return true; >+ if ( date >= now) return true; >+ }]; >+ } >+ else { >+ options['minDate'] = new Date(); >+ options['defaultHour'] = new Date().getHours(); >+ options['defaultMinute'] = new Date().getMinutes(); >+ >+ } >+ options['plugins'] = [ ShortcutButtonsPlugin({ >+ button: [ >+ { >+ label: __("1h") >+ }, >+ { >+ label: __("2h") >+ }, >+ { >+ label: __("4h") >+ } >+ ], >+ label: __("or"), >+ onClick: (index, fp) => { >+ let date; >+ let hh = 23, mm = 59; >+ switch (index) { >+ case 0: >+ date = new Date(Date.now() + 1 * 60 * 60 * 1000); >+ break; >+ case 1: >+ date = new Date(Date.now() + 2 * 60 * 60 * 1000); >+ break; >+ case 2: >+ date = new Date(Date.now() + 4 * 60 * 60 * 1000); >+ break; >+ } >+ fp.setDate(date, true); >+ } >+ })]; >+ } > > let fp = $(this).flatpickr(options); > if ( refresh_max_date ) { >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >index 5a6f1bd5a4..9e6234942c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref >@@ -206,6 +206,18 @@ Patrons: > never: never > preferences: according to patron messaging preferences > cron: (Deprecated) according to --send-notices cron switch >+ - >+ - "Delay pickup notices to allow time for processing. Send with: " >+ - pref: PickupNoticeDelayMode >+ default: 'off' >+ choices: >+ off: "no delay" >+ fixed: "fixed delay" >+ staff: "delay selectable by staff" >+ - "If 'Fixed delay' then delay the notice by " >+ - pref: PickupNoticeDelayDuration >+ default: 0 >+ - "hours" > Patron forms: > - > - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> must be filled in on the patron entry screen:" >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >index c119c2708e..1562815b49 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt >@@ -367,6 +367,7 @@ > <form method="post" action="/cgi-bin/koha/circ/returns.pl" autocomplete="off"> > <input type="hidden" name="barcode" value="[% item.barcode | html %]" /> > <input type="hidden" name="multiple_confirm" value="1" /> >+ <input type="hidden" name="delay_notice_until" value="[% delay_notice_until | html %]" /> > [% FOREACH inputloo IN inputloop %] > <input type="hidden" name="ri-[% inputloo.counter | html %]" value="[% inputloo.barcode | html %]" /> > <input type="hidden" name="dd-[% inputloo.counter | html %]" value="[% inputloo.duedate | html %]" /> >@@ -432,6 +433,7 @@ > <form method="post" action="returns.pl" name="wrongtransferform" id="wrongtransferform"> > <input type="hidden" name="return_date_override" value="[% return_date_override | html %]" /> > <input type="hidden" name="return_date_override_remember" value="[% return_date_override_remember | html %]" /> >+ <input type="hidden" name="delay_notice_until" value="[% delay_notice_until | html %]" /> > <input type="hidden" name="itemnumber" value="[% itemnumber | html %]" /> > <input type="hidden" name="transit" value="[% NewTransfer | html %]" /> > [% FOREACH inputloo IN inputloop %] >@@ -538,6 +540,7 @@ > > <input type="hidden" name="return_date_override" value="[% return_date_override | html %]" /> > <input type="hidden" name="return_date_override_remember" value="[% return_date_override_remember | html %]" /> >+ <input type="hidden" name="delay_notice_until" value="[% delay_notice_until | html %]" /> > [% INCLUDE all_checkin_messages %] > </div> <!-- /.modal-body --> > >@@ -609,6 +612,7 @@ > [% END %] > <input type="hidden" name="return_date_override" value="[% return_date_override | html %]" /> > <input type="hidden" name="return_date_override_remember" value="[% return_date_override_remember | html %]" /> >+ <input type="hidden" name="delay_notice_until" value="[% delay_notice_until | html %]" /> > <input type="hidden" name="exemptfine" value="[% exemptfine | html %]" /> > <input type="hidden" name="dropboxmode" value="[% dropboxmode | html %]" /> > <input type="hidden" name="forgivemanualholdsexpire" value="[% forgivemanualholdsexpire | html %]" /> >@@ -708,6 +712,7 @@ > <input type="hidden" name="forgivemanualholdsexpire" value="[% forgivemanualholdsexpire | html %]" /> > <input type="hidden" name="return_date_override" value="[% return_date_override | html %]" /> > <input type="hidden" name="return_date_override_remember" value="[% return_date_override_remember | html %]" /> >+ <input type="hidden" name="delay_notice_until" value="[% delay_notice_until | html %]" /> > [% INCLUDE all_checkin_messages %] > </div> > >@@ -800,6 +805,13 @@ > [% END %] > <p><i class="fa fa-check"></i> Saved check-in date: <span id="saved_return_date" class="single-line">[% return_date_override | html %]</span></p> > </div> >+ [% IF ( delay_notice_until ) %] >+ <div id="delay_notice" class="checkin-active-setting"> >+ [% ELSE %] >+ <div id="delay_notice" class="checkin-active-setting" style="display:none;"> >+ [% END %] >+ <p><i class="fa fa-check"></i> Delay pickup notice until: <span id="saved_delay_notice" class="single-line">[% delay_notice_until | html %]</span></p> >+ </div> > </div> > </div> > >@@ -851,7 +863,12 @@ > <label for="forgivemanualholdsexpire">Forgive fees for manually expired holds</label> > </div> > [% END %] <!-- overduecharges --> >- >+ [% IF Koha.Preference('PickupNoticeDelayMode') == 'staff' %] >+ <div id="delay-notice" class="date-select" > >+ <div class="hint">Delay pickup notice until: </div> >+ <input type="text" size="20" id="delay_notice_until" name="delay_notice_until" value="[% delay_notice_until | html %]" class="flatpickr" data-flatpickr-enable-time="true" data-flatpickr-on-close-focus="#barcode" data-flatpickr-futuredatetime="true" /> >+ </div> >+ [% END %] > </div> <!-- /.circ-settings --> > </fieldset> <!-- /#circ_returns_checkin --> > </form> <!-- /#checkin-form --> >@@ -1038,6 +1055,7 @@ > "dom": 'B<"clearfix">t', > }, columns_settings); > >+ > $("#exemptcheck").change(function () { > if (this.checked == true) { > $("#barcode").addClass("input-warning"); >@@ -1147,6 +1165,17 @@ > window.open("/cgi-bin/koha/members/printslip.pl?borrowernumber=" + borrowernumber + "&print=checkinslip", "printwindow"); > }); > >+ $("input#delay_notice_until").on("change", function () { >+ let delay_date = $(this).val(); >+ $("span#saved_delay_notice").text(delay_date); >+ if ( delay_date == '' ){ >+ $("div#delay_notice").hide(); >+ } >+ else { >+ $("div#delay_notice").show(); >+ } >+ }); >+ > }); > </script> > [% END %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/notices.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/notices.tt >index acfa28cd72..c36c538203 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/notices.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/notices.tt >@@ -72,7 +72,7 @@ > </td> > <td> > [% IF ( QUEUED_MESSAGE.status == 'sent' ) %]sent >- [% ELSIF ( QUEUED_MESSAGE.status == 'pending' ) %]pending >+ [% ELSIF ( QUEUED_MESSAGE.status == 'pending' ) %]pending [% IF QUEUED_MESSAGE.delay_until %], delayed until [% QUEUED_MESSAGE.delay_until | $KohaDates with_hours => 1 %][% END %] > [% ELSIF ( QUEUED_MESSAGE.status == 'failed' ) %]failed > [% ELSIF ( QUEUED_MESSAGE.status == 'deleted' ) %]deleted > [% ELSE %][% QUEUED_MESSAGE.status | html %][% END %] >-- >2.20.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 27208
:
128387
|
128388
|
128389
|
128390
|
128587
|
128588
|
128589
|
128590
| 128948 |
128949
|
128950
|
128951