View | Details | Raw Unified | Return to bug 14364
Collapse All | Expand All

(-)a/C4/Items.pm (-1 / +1 lines)
Lines 299-305 sub AddItem { Link Here
299
299
300
    $item->{'itemnumber'} = $itemnumber;
300
    $item->{'itemnumber'} = $itemnumber;
301
301
302
    ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver" );
302
    C4::Biblio::ModZebra( $item->{biblionumber}, "specialUpdate", "biblioserver" );
303
303
304
    logaction( "CATALOGUING", "ADD", $itemnumber, "item" )
304
    logaction( "CATALOGUING", "ADD", $itemnumber, "item" )
305
      if C4::Context->preference("CataloguingLog");
305
      if C4::Context->preference("CataloguingLog");
(-)a/C4/Reserves.pm (-3 / +40 lines)
Lines 778-783 sub CancelExpiredReserves { Link Here
778
        if ( $hold->found eq 'W' ) {
778
        if ( $hold->found eq 'W' ) {
779
            $cancel_params->{charge_cancel_fee} = 1;
779
            $cancel_params->{charge_cancel_fee} = 1;
780
        }
780
        }
781
        $cancel_params->{autofill} = C4::Context->preference('ExpireReservesAutoFill');
781
        $hold->cancel( $cancel_params );
782
        $hold->cancel( $cancel_params );
782
    }
783
    }
783
}
784
}
Lines 967-973 sub ModReserveStatus { Link Here
967
968
968
=head2 ModReserveAffect
969
=head2 ModReserveAffect
969
970
970
  &ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend,$reserve_id);
971
&ModReserveAffect(
972
    $itemnumber, $borrowernumber, $diffBranchSend,
973
    $reserve_id, $notify_library
974
);
971
975
972
This function affect an item and a status for a given reserve, either fetched directly
976
This function affect an item and a status for a given reserve, either fetched directly
973
by record_id, or by borrowernumber and itemnumber or biblionumber. If only biblionumber
977
by record_id, or by borrowernumber and itemnumber or biblionumber. If only biblionumber
Lines 981-987 take care of the waiting status Link Here
981
=cut
985
=cut
982
986
983
sub ModReserveAffect {
987
sub ModReserveAffect {
984
    my ( $itemnumber, $borrowernumber, $transferToDo, $reserve_id ) = @_;
988
    my ( $itemnumber, $borrowernumber, $transferToDo, $reserve_id, $notify_library ) = @_;
985
    my $dbh = C4::Context->dbh;
989
    my $dbh = C4::Context->dbh;
986
990
987
    # we want to attach $itemnumber to $borrowernumber, find the biblionumber
991
    # we want to attach $itemnumber to $borrowernumber, find the biblionumber
Lines 1008-1014 sub ModReserveAffect { Link Here
1008
    $hold->itemnumber($itemnumber);
1012
    $hold->itemnumber($itemnumber);
1009
    $hold->set_waiting($transferToDo);
1013
    $hold->set_waiting($transferToDo);
1010
1014
1011
    _koha_notify_reserve( $hold->reserve_id )
1015
    _koha_notify_reserve( $hold->reserve_id, $notify_library )
1012
      if ( !$transferToDo && !$already_on_shelf );
1016
      if ( !$transferToDo && !$already_on_shelf );
1013
1017
1014
    _FixPriority( { biblionumber => $biblionumber } );
1018
    _FixPriority( { biblionumber => $biblionumber } );
Lines 1603-1608 The following tables are availalbe witin the notice: Link Here
1603
1607
1604
sub _koha_notify_reserve {
1608
sub _koha_notify_reserve {
1605
    my $reserve_id = shift;
1609
    my $reserve_id = shift;
1610
    my $notify_library = shift;
1611
1606
    my $hold = Koha::Holds->find($reserve_id);
1612
    my $hold = Koha::Holds->find($reserve_id);
1607
    my $borrowernumber = $hold->borrowernumber;
1613
    my $borrowernumber = $hold->borrowernumber;
1608
1614
Lines 1669-1674 sub _koha_notify_reserve { Link Here
1669
        &$send_notification('print', 'HOLD');
1675
        &$send_notification('print', 'HOLD');
1670
    }
1676
    }
1671
1677
1678
    if ($notify_library) {
1679
        my $letter = C4::Letters::GetPreparedLetter(
1680
            module      => 'reserves',
1681
            letter_code => 'HOLD_CHANGED',
1682
            branchcode  => $hold->branchcode,
1683
            substitute  => { today => output_pref( dt_from_string ) },
1684
            tables      => {
1685
                'branches'    => $library,
1686
                'borrowers'   => $patron->unblessed,
1687
                'biblio'      => $hold->biblionumber,
1688
                'biblioitems' => $hold->biblionumber,
1689
                'reserves'    => $hold->unblessed,
1690
                'items'       => $hold->itemnumber,
1691
            },
1692
        );
1693
1694
        my $email =
1695
             C4::Context->preference('ExpireReservesAutoFillEmail')
1696
          || $library->{branchemail}
1697
          || C4::Context->preference('KohaAdminEmailAddress');
1698
1699
        C4::Letters::EnqueueLetter(
1700
            {
1701
                letter                 => $letter,
1702
                borrowernumber         => $borrowernumber,
1703
                message_transport_type => 'email',
1704
                from_address           => $email,
1705
                to_address             => $email,
1706
            }
1707
        );
1708
    }
1672
}
1709
}
1673
1710
1674
=head2 _ShiftPriorityByDateAndPriority
1711
=head2 _ShiftPriorityByDateAndPriority
(-)a/Koha/Hold.pm (+15 lines)
Lines 25-30 use Data::Dumper qw(Dumper); Link Here
25
25
26
use C4::Context qw(preference);
26
use C4::Context qw(preference);
27
use C4::Log;
27
use C4::Log;
28
use C4::Reserves;
28
29
29
use Koha::DateUtils qw(dt_from_string output_pref);
30
use Koha::DateUtils qw(dt_from_string output_pref);
30
use Koha::Patrons;
31
use Koha::Patrons;
Lines 340-345 Cancel a hold: Link Here
340
341
341
sub cancel {
342
sub cancel {
342
    my ( $self, $params ) = @_;
343
    my ( $self, $params ) = @_;
344
345
    my $autofill_next = $params->{autofill} && $self->itemnumber && $self->found && $self->found eq 'W';
346
343
    $self->_result->result_source->schema->txn_do(
347
    $self->_result->result_source->schema->txn_do(
344
        sub {
348
        sub {
345
            $self->cancellationdate(dt_from_string);
349
            $self->cancellationdate(dt_from_string);
Lines 360-365 sub cancel { Link Here
360
                if C4::Context->preference('HoldsLog');
364
                if C4::Context->preference('HoldsLog');
361
        }
365
        }
362
    );
366
    );
367
368
    if ($autofill_next) {
369
        my ( undef, $next_hold ) = C4::Reserves::CheckReserves( $self->itemnumber );
370
        if ($next_hold) {
371
            my $is_transfer = $self->branchcode ne $next_hold->{branchcode};
372
373
            ModReserveAffect( $self->itemnumber, $self->borrowernumber, $is_transfer, $next_hold->{reserve_id}, $autofill_next );
374
            ModItemTransfer( $self->itemnumber, $self->branchcode, $next_hold->{branchcode} ) if $is_transfer;
375
        }
376
    }
377
363
    return $self;
378
    return $self;
364
}
379
}
365
380
(-)a/installer/data/mysql/atomicupdate/bug_14364.sql (+13 lines)
Line 0 Link Here
1
INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
2
('ExpireReservesAutoFill','0',NULL,'Automatically fill the next hold with a automatically canceled expired waiting hold.','YesNo'),
3
('ExpireReservesAutoFillEmail','', NULL,'If ExpireReservesAutoFill and an email is defined here, the email notification for the change in the hold will be sent to this address.','Free');
4
5
INSERT INTO letter(module,code,branchcode,name,is_html,title,content,message_transport_type)
6
VALUES ( 'reserves', 'HOLD_CHANGED', '', 'Canceled Hold Available for Different Patron', '0', 'Canceled Hold Available for Different Patron', 'The patron picking up <<biblio.title>> (<<items.barcode>>) has changed to <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).
7
8
Please update the hold information for this item.
9
10
Title: <<biblio.title>>
11
Author: <<biblio.author>>
12
Copy: <<items.copynumber>>
13
Pickup location: <<branches.branchname>>', 'email');
(-)a/installer/data/mysql/en/mandatory/sample_notices.sql (+10 lines)
Lines 175-177 INSERT INTO `letter` (`module`, `code`, `branchcode`, `name`, `is_html`, `title` Link Here
175
('circulation', 'AR_SLIP', '', 'Article request - print slip', 0, 'Article request', 'Article request:\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>),\r\n\r\nTitle: <<biblio.title>>\r\nBarcode: <<items.barcode>>\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n', 'print'),
175
('circulation', 'AR_SLIP', '', 'Article request - print slip', 0, 'Article request', 'Article request:\r\n\r\n<<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>),\r\n\r\nTitle: <<biblio.title>>\r\nBarcode: <<items.barcode>>\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n', 'print'),
176
('circulation', 'AR_PROCESSING', '', 'Article request - processing', 0, 'Article request processing', 'Dear <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>),\r\n\r\nWe are now processing your request for an article from <<biblio.title>> (<<items.barcode>>).\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n\r\nThank you!', 'email'),
176
('circulation', 'AR_PROCESSING', '', 'Article request - processing', 0, 'Article request processing', 'Dear <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>),\r\n\r\nWe are now processing your request for an article from <<biblio.title>> (<<items.barcode>>).\r\n\r\nArticle requested:\r\nTitle: <<article_requests.title>>\r\nAuthor: <<article_requests.author>>\r\nVolume: <<article_requests.volume>>\r\nIssue: <<article_requests.issue>>\r\nDate: <<article_requests.date>>\r\nPages: <<article_requests.pages>>\r\nChapters: <<article_requests.chapters>>\r\nNotes: <<article_requests.patron_notes>>\r\n\r\nThank you!', 'email'),
177
('circulation', 'CHECKOUT_NOTE', '', 'Checkout note on item set by patron', '0', 'Checkout note', '<<borrowers.firstname>> <<borrowers.surname>> has added a note to the item <<biblio.title>> - <<biblio.author>> (<<biblio.biblionumber>>).','email');
177
('circulation', 'CHECKOUT_NOTE', '', 'Checkout note on item set by patron', '0', 'Checkout note', '<<borrowers.firstname>> <<borrowers.surname>> has added a note to the item <<biblio.title>> - <<biblio.author>> (<<biblio.biblionumber>>).','email');
178
179
INSERT INTO letter(module,code,branchcode,name,is_html,title,content,message_transport_type)
180
    VALUES ( 'reserves', 'HOLD_CHANGED', '', 'Canceled Hold Available for Different Patron', '0', 'Canceled Hold Available for Different Patron', 'The patron picking up <<biblio.title>> (<<items.barcode>>) has changed to <<borrowers.firstname>> <<borrowers.surname>> (<<borrowers.cardnumber>>).
181
182
	            Please update the hold information for this item.
183
184
	            Title: <<biblio.title>>
185
	            Author: <<biblio.author>>
186
	            Copy: <<items.copynumber>>
187
	            Pickup location: <<branches.branchname>>', 'email');
(-)a/installer/data/mysql/sysprefs.sql (+2 lines)
Lines 154-159 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
154
('EnhancedMessagingPreferences','1','','If ON, allows patrons to select to receive additional messages about items due or nearly due.','YesNo'),
154
('EnhancedMessagingPreferences','1','','If ON, allows patrons to select to receive additional messages about items due or nearly due.','YesNo'),
155
('EnhancedMessagingPreferencesOPAC', '1', NULL, 'If ON, show patrons messaging setting on the OPAC.', 'YesNo'),
155
('EnhancedMessagingPreferencesOPAC', '1', NULL, 'If ON, show patrons messaging setting on the OPAC.', 'YesNo'),
156
('expandedSearchOption','0',NULL,'If ON, set advanced search to be expanded by default','YesNo'),
156
('expandedSearchOption','0',NULL,'If ON, set advanced search to be expanded by default','YesNo'),
157
('ExpireReservesAutoFill','0',NULL,'Automatically fill the next hold with a automatically canceled expired waiting hold.','YesNo'),
158
('ExpireReservesAutoFillEmail','', NULL,'If ExpireReservesAutoFill and an email is defined here, the email notification for the change in the hold will be sent to this address.','Free'),
157
('ExpireReservesMaxPickUpDelay','0','','Enabling this allows holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay','YesNo'),
159
('ExpireReservesMaxPickUpDelay','0','','Enabling this allows holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay','YesNo'),
158
('ExpireReservesMaxPickUpDelayCharge','0',NULL,'If ExpireReservesMaxPickUpDelay is enabled, and this field has a non-zero value, than a borrower whose waiting hold has expired will be charged this amount.','free'),
160
('ExpireReservesMaxPickUpDelayCharge','0',NULL,'If ExpireReservesMaxPickUpDelay is enabled, and this field has a non-zero value, than a borrower whose waiting hold has expired will be charged this amount.','free'),
159
('ExpireReservesOnHolidays', '1', NULL, 'If false, reserves at a library will not be canceled on days the library is not open.', 'YesNo'),
161
('ExpireReservesOnHolidays', '1', NULL, 'If false, reserves at a library will not be canceled on days the library is not open.', 'YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+10 lines)
Lines 559-564 Circulation: Link Here
559
                  no: "Don't allow"
559
                  no: "Don't allow"
560
            - "holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay"
560
            - "holds to expire automatically if they have not been picked by within the time period specified in ReservesMaxPickUpDelay"
561
        -
561
        -
562
            - pref: ExpireReservesAutoFill
563
              choices:
564
                  yes: "Do"
565
                  no: "Don't"
566
            - automatically fill the next hold using the item. If enabled, an email notification will be sent to either the email address defined in ExpireReservesAutoFillEmail, the item's holding library's email address, or the email address defined in KohaAdminEmailAddress in that order.
567
        -
568
            - Send email notification of the new hold filled with a canceled item to
569
            - pref: ExpireReservesAutoFillEmail
570
            - . If no address is defined here, the email will be sent to either the item's holding library or the email address defined in KohaAdminEmailAddress in that order.
571
        -
562
            - If using ExpireReservesMaxPickUpDelay, charge a borrower who allows his or her waiting hold to expire a fee of
572
            - If using ExpireReservesMaxPickUpDelay, charge a borrower who allows his or her waiting hold to expire a fee of
563
            - pref: ExpireReservesMaxPickUpDelayCharge
573
            - pref: ExpireReservesMaxPickUpDelayCharge
564
              class: currency
574
              class: currency
(-)a/t/db_dependent/Holds/ExpireReservesAutoFill.t (-1 / +137 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
use Modern::Perl;
4
5
use Test::More tests => 9;
6
7
use t::lib::Mocks;
8
use t::lib::TestBuilder;
9
10
use MARC::Record;
11
12
use C4::Context;
13
use C4::Biblio;
14
use C4::Items;
15
use Koha::Database;
16
use Koha::Holds;
17
18
BEGIN {
19
    use FindBin;
20
    use lib $FindBin::Bin;
21
    use_ok('C4::Reserves');
22
}
23
24
my $schema = Koha::Database->new->schema;
25
$schema->storage->txn_begin;
26
27
my $builder = t::lib::TestBuilder->new();
28
my $dbh     = C4::Context->dbh;
29
30
# Create two random branches
31
my $library = $builder->build( { source => 'Branch' } );
32
my $branchcode = $library->{branchcode};
33
34
$dbh->do('DELETE FROM reserves');
35
$dbh->do('DELETE FROM message_queue');
36
37
# Create a biblio instance for testing
38
my ($biblionumber) = create_helper_biblio('DUMMY');
39
40
# Create item instance for testing.
41
my ( $item_bibnum, $item_bibitemnum, $itemnumber ) =
42
  AddItem( { homebranch => $branchcode, holdingbranch => $branchcode },
43
    $biblionumber );
44
45
my $patron_1 = $builder->build( { source => 'Borrower' } );
46
my $patron_2 = $builder->build( { source => 'Borrower' } );
47
my $patron_3 = $builder->build( { source => 'Borrower' } );
48
49
# Add a hold on the item for each of our patrons
50
my $hold_1 = Koha::Hold->new(
51
    {
52
        priority       => 0,
53
        borrowernumber => $patron_1->{borrowernumber},
54
        branchcode     => $library->{branchcode},
55
        biblionumber   => $biblionumber,
56
        itemnumber     => $itemnumber,
57
        found          => 'W',
58
        reservedate    => '1900-01-01',
59
        waitingdate    => '1900-01-01',
60
        expirationdate => '1900-01-01',
61
        lowestPriority => 0,
62
        suspend        => 0,
63
    }
64
)->store();
65
my $hold_2 = Koha::Hold->new(
66
    {
67
        priority       => 1,
68
        borrowernumber => $patron_2->{borrowernumber},
69
        branchcode     => $library->{branchcode},
70
        biblionumber   => $biblionumber,
71
        itemnumber     => $itemnumber,
72
        reservedate    => '1900-01-01',
73
        expirationdate => '9999-01-01',
74
        lowestPriority => 0,
75
        suspend        => 0,
76
    }
77
)->store();
78
my $hold_3 = Koha::Hold->new(
79
    {
80
        priority       => 2,
81
        borrowernumber => $patron_2->{borrowernumber},
82
        branchcode     => $library->{branchcode},
83
        biblionumber   => $biblionumber,
84
        itemnumber     => $itemnumber,
85
        reservedate    => '1900-01-01',
86
        expirationdate => '9999-01-01',
87
        lowestPriority => 0,
88
        suspend        => 0,
89
    }
90
)->store();
91
92
# Test CancelExpiredReserves
93
t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelay', 1 );
94
t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay',       1 );
95
t::lib::Mocks::mock_preference( 'ExpireReservesOnHolidays',     1 );
96
t::lib::Mocks::mock_preference( 'ExpireReservesAutoFill',       1 );
97
t::lib::Mocks::mock_preference( 'ExpireReservesAutoFillEmail',
98
    'kyle@example.com' );
99
100
CancelExpiredReserves();
101
102
my @holds = Koha::Holds->search( {}, { order_by => 'priority' } );
103
$hold_2 = $holds[0];
104
$hold_3 = $holds[1];
105
106
is( @holds,            2,   'Found 2 holds' );
107
is( $hold_2->priority, 0,   'Next hold in line now has priority of 0' );
108
is( $hold_2->found,    'W', 'Next hold in line is now set to waiting' );
109
110
my @messages = $schema->resultset('MessageQueue')
111
  ->search( { letter_code => 'HOLD_CHANGED' } );
112
is( @messages, 1, 'Found 1 message in the message queue' );
113
is( $messages[0]->to_address, 'kyle@example.com', 'Message sent to correct email address' );
114
115
$hold_2->expirationdate('1900-01-01')->store();
116
117
CancelExpiredReserves();
118
119
@holds = Koha::Holds->search( {}, { order_by => 'priority' } );
120
$hold_3 = $holds[0];
121
122
is( @holds,            1,   'Found 1 hold' );
123
is( $hold_3->priority, 0,   'Next hold in line now has priority of 0' );
124
is( $hold_3->found,    'W', 'Next hold in line is now set to waiting' );
125
126
# Helper method to set up a Biblio.
127
sub create_helper_biblio {
128
    my $itemtype = shift;
129
    my $bib      = MARC::Record->new();
130
    my $title    = 'Silence in the library';
131
    $bib->append_fields(
132
        MARC::Field->new( '100', ' ', ' ', a => 'Moffat, Steven' ),
133
        MARC::Field->new( '245', ' ', ' ', a => $title ),
134
        MARC::Field->new( '942', ' ', ' ', c => $itemtype ),
135
    );
136
    return my ( $b, $t, $bi ) = AddBiblio( $bib, '' );
137
}

Return to bug 14364