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

(-)a/C4/Circulation.pm (+23 lines)
Lines 998-1003 sub CanBookBeIssued { Link Here
998
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
998
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
999
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
999
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1000
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1000
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1001
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1001
                }
1002
                }
1002
                elsif ( $restype eq "Reserved" ) {
1003
                elsif ( $restype eq "Reserved" ) {
1003
                    # The item is on reserve for someone else.
1004
                    # The item is on reserve for someone else.
Lines 1008-1016 sub CanBookBeIssued { Link Here
1008
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1009
                    $needsconfirmation{'resborrowernumber'} = $patron->borrowernumber;
1009
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1010
                    $needsconfirmation{'resbranchcode'} = $patron->branchcode;
1010
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1011
                    $needsconfirmation{'resreservedate'} = $res->{reservedate};
1012
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1011
                }
1013
                }
1012
            }
1014
            }
1013
        }
1015
        }
1016
1017
        my $now = dt_from_string();
1018
        my $preventCheckoutOnSameReservePeriod =
1019
            C4::Context->preference("PreventCheckoutOnSameReservePeriod");
1020
        my $reserves_on_same_period =
1021
            ReservesOnSamePeriod($item->{biblionumber}, $item->{itemnumber}, $now->ymd, $duedate->ymd);
1022
        if ($preventCheckoutOnSameReservePeriod && $reserves_on_same_period) {
1023
            my $reserve = $reserves_on_same_period->[0];
1024
            my $patron = Koha::Patrons->find( $reserve->{borrowernumber} );
1025
            my $branchname = Koha::Libraries->find($reserve->{branchcode})->branchname;
1026
1027
            $needsconfirmation{RESERVED} = 1;
1028
            $needsconfirmation{resfirstname} = $patron->firstname;
1029
            $needsconfirmation{ressurname} = $patron->surname;
1030
            $needsconfirmation{rescardnumber} = $patron->cardnumber;
1031
            $needsconfirmation{resborrowernumber} = $patron->borrowernumber;
1032
            $needsconfirmation{resbranchname} = $branchname;
1033
            $needsconfirmation{resreservedate} = $reserve->{reservedate};
1034
            $needsconfirmation{resreserveid} = $reserve->{reserve_id};
1035
        }
1036
1014
    }
1037
    }
1015
1038
1016
    ## CHECK AGE RESTRICTION
1039
    ## CHECK AGE RESTRICTION
(-)a/C4/Reserves.pm (+48 lines)
Lines 134-139 BEGIN { Link Here
134
        &SuspendAll
134
        &SuspendAll
135
135
136
        &GetReservesControlBranch
136
        &GetReservesControlBranch
137
		&ReservesOnSamePeriod
137
138
138
        IsItemOnHoldAndFound
139
        IsItemOnHoldAndFound
139
140
Lines 2108-2113 sub GetHoldRule { Link Here
2108
    return $sth->fetchrow_hashref();
2109
    return $sth->fetchrow_hashref();
2109
}
2110
}
2110
2111
2112
=head2 ReservesOnSamePeriod
2113
2114
    my $reserve = ReservesOnSamePeriod( $biblionumber, $itemnumber, $resdate, $expdate);
2115
2116
    Return the reserve that match the period ($resdate => $expdate),
2117
    undef if no reserve match.
2118
2119
=cut
2120
2121
sub ReservesOnSamePeriod {
2122
    my ($biblionumber, $itemnumber, $resdate, $expdate) = @_;
2123
2124
    unless ($resdate && $expdate) {
2125
        return;
2126
    }
2127
2128
    my @reserves = Koha::Holds->search({ biblionumber => $biblionumber });
2129
2130
    $resdate = output_pref({ str => $resdate, dateonly => 1, dateformat => 'iso' });
2131
    $expdate = output_pref({ str => $expdate, dateonly => 1, dateformat => 'iso' });
2132
2133
    my @reserves_overlaps;
2134
    foreach my $reserve ( @reserves ) {
2135
2136
        unless ($reserve->reservedate && $reserve->expirationdate) {
2137
            next;
2138
        }
2139
2140
        if (date_ranges_overlap($resdate, $expdate,
2141
                                $reserve->reservedate,
2142
                                $reserve->expirationdate)) {
2143
2144
            # If reserve is item level and the requested periods overlap.
2145
            if ($itemnumber && $reserve->itemnumber == $itemnumber ) {
2146
                return [$reserve->unblessed];
2147
            }
2148
            push @reserves_overlaps, $reserve->unblessed;
2149
        }
2150
    }
2151
2152
    if ( @reserves_overlaps >= Koha::Items->search({ biblionumber => $biblionumber })->count() ) {
2153
        return \@reserves_overlaps;
2154
    }
2155
2156
    return;
2157
}
2158
2111
=head1 AUTHOR
2159
=head1 AUTHOR
2112
2160
2113
Koha Development Team <http://koha-community.org/>
2161
Koha Development Team <http://koha-community.org/>
(-)a/Koha/DateUtils.pm (-1 / +43 lines)
Lines 24-30 use Koha::Exceptions; Link Here
24
use base 'Exporter';
24
use base 'Exporter';
25
25
26
our @EXPORT = (
26
our @EXPORT = (
27
    qw( dt_from_string output_pref format_sqldatetime )
27
    qw( dt_from_string output_pref format_sqldatetime date_ranges_overlap )
28
);
28
);
29
29
30
=head1 DateUtils
30
=head1 DateUtils
Lines 317-320 sub format_sqldatetime { Link Here
317
    return q{};
317
    return q{};
318
}
318
}
319
319
320
=head2 date_ranges_overlap
321
322
    $bool = date_ranges_overlap($start1, $end1, $start2, $end2);
323
324
    Tells if first range ($start1 => $end1) overlaps
325
    the second one ($start2 => $end2)
326
327
=cut
328
329
sub date_ranges_overlap {
330
    my ($start1, $end1, $start2, $end2) = @_;
331
332
    $start1 = dt_from_string( $start1, 'iso' );
333
    $end1 = dt_from_string( $end1, 'iso' );
334
    $start2 = dt_from_string( $start2, 'iso' );
335
    $end2 = dt_from_string( $end2, 'iso' );
336
337
    if (
338
        # Start of range 2 is in the range 1.
339
        (
340
            DateTime->compare($start2, $start1) >= 0
341
            && DateTime->compare($start2, $end1) <= 0
342
        )
343
        ||
344
        # End of range 2 is in the range 1.
345
        (
346
            DateTime->compare($end2, $start1) >= 0
347
            && DateTime->compare($end2, $end1) <= 0
348
        )
349
        ||
350
        # Range 2 start before and end after range 1.
351
        (
352
            DateTime->compare($start2, $start1) < 0
353
            && DateTime->compare($end2, $end1) > 0
354
        )
355
    ) {
356
        return 1;
357
    }
358
359
    return;
360
}
361
320
1;
362
1;
(-)a/circ/circulation.pl (+4 lines)
Lines 421-426 if (@$barcodes) { Link Here
421
        }
421
        }
422
        unless($confirm_required) {
422
        unless($confirm_required) {
423
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
423
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
424
            if ( $cancelreserve eq 'cancel' ) {
425
                CancelReserve({ reserve_id => $query->param('reserveid') });
426
            }
427
            $cancelreserve = $cancelreserve eq 'revert' ? 'revert' : undef;
424
            my $issue = AddIssue( $patron->unblessed, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, } );
428
            my $issue = AddIssue( $patron->unblessed, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, } );
425
            $template_params->{issue} = $issue;
429
            $template_params->{issue} = $issue;
426
            $session->clear('auto_renew');
430
            $session->clear('auto_renew');
(-)a/installer/data/mysql/atomicupdate/bug_15261-add_preventchechoutonsamereserveperiod_syspref.sql (+1 lines)
Line 0 Link Here
1
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('PreventCheckoutOnSameReservePeriod', '0', 'Prevent to checkout a document if a reserve on same period exists', NULL, 'YesNo');
(-)a/installer/data/mysql/atomicupdate/bug_15261-add_preventreservesonsameperiod_syspref.sql (+1 lines)
Line 0 Link Here
1
INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('PreventReservesOnSamePeriod', '0', 'Prevent to hold a document if a reserve on same period exists', NULL, 'YesNo');
(-)a/installer/data/mysql/sysprefs.sql (-1 / +3 lines)
Lines 616-620 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
616
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
616
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
617
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
617
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
618
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
618
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
619
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo')
619
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo'),
620
('PreventCheckoutOnSameReservePeriod','0','','Prevent to checkout a document if a reserve on same period exists','YesNo'),
621
('PreventReservesOnSamePeriod','0','','Prevent to hold a document if a reserve on same period exists','YesNo')
620
;
622
;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+12 lines)
Lines 476-481 Circulation: Link Here
476
                  yes: Block
476
                  yes: Block
477
                  no: Allow
477
                  no: Allow
478
            - his/her auto renewals.
478
            - his/her auto renewals.
479
        -
480
            - pref: PreventCheckoutOnSameReservePeriod
481
              choices:
482
                  yes: Do
483
                  no: "Don't"
484
            - If yes, checkouts periods can't overlap with a reserve period.
479
    Checkin Policy:
485
    Checkin Policy:
480
        -
486
        -
481
            - pref: BlockReturnOfWithdrawnItems
487
            - pref: BlockReturnOfWithdrawnItems
Lines 726-731 Circulation: Link Here
726
            - 'Example: "itemlost: 1" to set items.itemlost to 1 when the item is marked as lost'
732
            - 'Example: "itemlost: 1" to set items.itemlost to 1 when the item is marked as lost'
727
            - pref: UpdateItemWhenLostFromHoldList
733
            - pref: UpdateItemWhenLostFromHoldList
728
              type: textarea
734
              type: textarea
735
        -
736
            - pref: PreventReservesOnSamePeriod
737
              choices:
738
                  yes: Do
739
                  no: "Don't"
740
            - If yes, Reserves periods for the same document can't overlap.
729
    Interlibrary Loans:
741
    Interlibrary Loans:
730
        -
742
        -
731
            - pref: ILLModule
743
            - pref: ILLModule
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+2 lines)
Lines 213-218 Link Here
213
[% IF ( RESERVED ) %]
213
[% IF ( RESERVED ) %]
214
    <p>
214
    <p>
215
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
215
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
216
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
216
    <label for="cancelreserve">Cancel hold</label>
217
    <label for="cancelreserve">Cancel hold</label>
217
    </p>
218
    </p>
218
[% END %]
219
[% END %]
Lines 221-226 Link Here
221
<p>
222
<p>
222
    <label for="cancelreserve">Cancel hold</label>
223
    <label for="cancelreserve">Cancel hold</label>
223
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
224
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
225
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
224
    <label for="revertreserve">Revert waiting status</label>
226
    <label for="revertreserve">Revert waiting status</label>
225
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
227
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
226
</p>
228
</p>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/placerequest.tt (+66 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
    <title>Koha &rsaquo; Circulation &rsaquo; Holds &rsaquo; Confirm holds</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
</head>
5
<body id="circ_placerequest" class="catalog">
6
[% INCLUDE 'header.inc' %]
7
[% INCLUDE 'circ-search.inc' %]
8
9
<div id="breadcrumbs">
10
  <a href="/cgi-bin/koha/mainpage.pl">Home</a>
11
  &rsaquo;
12
  <a href="/cgi-bin/koha/catalogue/search.pl">Catalog</a>
13
  &rsaquo;
14
  Confirm holds
15
</div>
16
17
<div id="doc3" class="yui-t2">
18
19
  <div id="bd">
20
    <div id="yui-main">
21
      <div class="yui-b">
22
23
        <h1>Confirm holds</h1>
24
25
        <div class="alert">
26
          <p>
27
            Some of the reserves you are trying to do overlaps with existing reserves.
28
            Please confirm you want to proceed.
29
          </p>
30
        </div>
31
32
        <form method="post">
33
          <input type="hidden" name="borrowernumber" value="[% borrowernumber %]">
34
          [% IF multi_hold %]
35
            <input type="hidden" name="biblionumbers" value="[% biblionumbers%]">
36
            <input type="hidden" name="multi_hold" value="1">
37
          [% ELSE %]
38
            <input type="hidden" name="biblionumber" value="[% biblionumber%]">
39
          [% END %]
40
          <input type="hidden" name="reserve_date" value="[% reserve_date %]">
41
          <input type="hidden" name="expiration_date" value="[% expiration_date %]">
42
          <input type="hidden" name="pickup" value="[% pickup%]">
43
          <input type="hidden" name="notes" value="[% notes %]">
44
          <input type="hidden" name="confirm" value="1">
45
46
          [% FOREACH biblionumber IN overlap_reserves.keys %]
47
            [% input_id = "confirm_$biblionumber" %]
48
            <div>
49
              <input type="hidden" name="rank_[% biblionumber %]" value="[% overlap_reserves.$biblionumber.rank %]">
50
              [% IF (overlap_reserves.$biblionumber.checkitem) %]
51
                <input type="hidden" name="checkitem" value="[% overlap_reserves.$biblionumber.checkitem%]">
52
              [% END %]
53
              <input type="checkbox" name="confirm_biblionumbers" id="[% input_id %]"
54
                     value="[% biblionumber %]">
55
              <label for="[% input_id %]">Confirm hold for [% overlap_reserves.$biblionumber.title %]</label>
56
            </div>
57
          [% END %]
58
59
          <input type="submit" value="Continue">
60
        </form>
61
62
      </div>
63
    </div>
64
65
  </div>
66
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/opac/opac-reserve.pl (+9 lines)
Lines 277-282 if ( $query->param('place_reserve') ) { Link Here
277
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
277
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
278
            $itemNum = undef;
278
            $itemNum = undef;
279
        }
279
        }
280
281
        if ($canreserve) {
282
            if (C4::Context->preference("PreventReservesOnSamePeriod") &&
283
                ReservesOnSamePeriod($biblioNum, $itemNum, $startdate, $expiration_date)) {
284
                $canreserve = 0;
285
                $failed_holds++;
286
            }
287
        }
288
280
        my $notes = $query->param('notes_'.$biblioNum)||'';
289
        my $notes = $query->param('notes_'.$biblioNum)||'';
281
290
282
        if (   $maxreserves
291
        if (   $maxreserves
(-)a/reserve/placerequest.pl (-58 / +80 lines)
Lines 30-112 use C4::Output; Link Here
30
use C4::Reserves;
30
use C4::Reserves;
31
use C4::Circulation;
31
use C4::Circulation;
32
use C4::Members;
32
use C4::Members;
33
use C4::Auth qw/checkauth/;
33
use C4::Auth;
34
use Koha::Patrons;
34
use Koha::Patrons;
35
35
36
my $input = CGI->new();
36
my $input = CGI->new();
37
37
38
checkauth($input, 0, { reserveforothers => 'place_holds' }, 'intranet');
38
my ( $template, $borrowernumber, $cookie, $flags ) = get_template_and_user(
39
39
    {
40
my @bibitems       = $input->multi_param('biblioitem');
40
        template_name   => "reserve/placerequest.tt",
41
my @reqbib         = $input->multi_param('reqbib');
41
        query           => $input,
42
my $biblionumber   = $input->param('biblionumber');
42
        type            => "intranet",
43
my $borrowernumber = $input->param('borrowernumber');
43
        authnotrequired => 0,
44
my $notes          = $input->param('notes');
44
        flagsrequired   => { reserveforothers => 'place_holds' },
45
my $branch         = $input->param('pickup');
45
    }
46
my $startdate      = $input->param('reserve_date') || '';
46
);
47
my @rank           = $input->multi_param('rank-request');
47
48
my $type           = $input->param('type');
48
my $biblionumber=$input->param('biblionumber');
49
my $title          = $input->param('title');
49
my $borrowernumber=$input->param('borrowernumber');
50
my $checkitem      = $input->param('checkitem');
50
my $notes=$input->param('notes');
51
my $branch=$input->param('pickup');
52
my $startdate=$input->param('reserve_date') || '';
53
my @rank=$input->param('rank-request');
54
my $title=$input->param('title');
55
my $checkitem=$input->param('checkitem');
51
my $expirationdate = $input->param('expiration_date');
56
my $expirationdate = $input->param('expiration_date');
52
my $itemtype       = $input->param('itemtype') || undef;
57
my $itemtype       = $input->param('itemtype') || undef;
53
58
my $confirm = $input->param('confirm');
54
my $borrower = Koha::Patrons->find( $borrowernumber );
59
my @confirm_biblionumbers = $input->param('confirm_biblionumbers');
55
$borrower = $borrower->unblessed if $borrower;
56
60
57
my $multi_hold = $input->param('multi_hold');
61
my $multi_hold = $input->param('multi_hold');
58
my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/');
62
my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/');
59
my $bad_bibs = $input->param('bad_bibs');
63
my $bad_bibs = $input->param('bad_bibs');
60
my $holds_to_place_count = $input->param('holds_to_place_count') || 1;
64
my $holds_to_place_count = $input->param('holds_to_place_count') || 1;
61
65
66
my $borrower = Koha::Patrons->find( $borrowernumber );
67
$borrower = $borrower->unblessed if $borrower;
68
unless ($borrower) {
69
    print $input->header();
70
    print "Invalid borrower number please try again";
71
    exit;
72
}
73
62
my %bibinfos = ();
74
my %bibinfos = ();
63
my @biblionumbers = split '/', $biblionumbers;
75
my @biblionumbers = split '/', $biblionumbers;
64
foreach my $bibnum (@biblionumbers) {
76
foreach my $bibnum (@biblionumbers) {
65
    my %bibinfo = ();
77
    my %bibinfo;
66
    $bibinfo{title} = $input->param("title_$bibnum");
78
    $bibinfo{title} = $input->param("title_$bibnum");
79
67
    $bibinfo{rank} = $input->param("rank_$bibnum");
80
    $bibinfo{rank} = $input->param("rank_$bibnum");
68
    $bibinfos{$bibnum} = \%bibinfo;
81
    $bibinfos{$bibnum} = \%bibinfo;
69
}
82
}
70
83
71
my $found;
84
my $found;
72
85
73
if ( $type eq 'str8' && $borrower ) {
86
my $overlap_reserves = {};
74
87
foreach my $biblionumber (keys %bibinfos) {
75
    foreach my $biblionumber ( keys %bibinfos ) {
88
    next if ($confirm && !grep { $_ eq $biblionumber } @confirm_biblionumbers);
76
        my $count = @bibitems;
77
        @bibitems = sort @bibitems;
78
        my $i2 = 1;
79
        my @realbi;
80
        $realbi[0] = $bibitems[0];
81
        for ( my $i = 1 ; $i < $count ; $i++ ) {
82
            my $i3 = $i2 - 1;
83
            if ( $realbi[$i3] ne $bibitems[$i] ) {
84
                $realbi[$i2] = $bibitems[$i];
85
                $i2++;
86
            }
87
        }
88
89
89
        if ( defined $checkitem && $checkitem ne '' ) {
90
    my ($reserve_title, $reserve_rank);
90
            my $item = GetItem($checkitem);
91
    if ($multi_hold) {
91
            if ( $item->{'biblionumber'} ne $biblionumber ) {
92
        my $bibinfo = $bibinfos{$biblionumber};
92
                $biblionumber = $item->{'biblionumber'};
93
        $reserve_rank = $bibinfo->{rank};
93
            }
94
        $reserve_title = $bibinfo->{title};
94
        }
95
    } else {
96
        $reserve_rank = $rank[0];
97
        $reserve_title = $title;
98
    }
95
99
96
        if ($multi_hold) {
100
    if (defined $checkitem && $checkitem ne '') {
97
            my $bibinfo = $bibinfos{$biblionumber};
101
        my $item = GetItem($checkitem);
98
            AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,[$biblionumber],
102
        if ($item->{'biblionumber'} ne $biblionumber) {
99
                       $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found);
103
            $biblionumber = $item->{'biblionumber'};
100
        } else {
101
            # place a request on 1st available
102
            for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) {
103
                AddReserve( $branch, $borrower->{'borrowernumber'},
104
                    $biblionumber, \@realbi, $rank[0], $startdate, $expirationdate, $notes, $title,
105
                    $checkitem, $found, $itemtype );
106
            }
107
        }
104
        }
108
    }
105
    }
109
106
107
    if (!$confirm &&
108
        ReservesOnSamePeriod($biblionumber, $checkitem, $startdate, $expirationdate) &&
109
        C4::Context->preference("PreventReservesOnSamePeriod")) {
110
        $overlap_reserves->{$biblionumber} = {
111
            title => $reserve_title ,
112
            checkitem => $checkitem,
113
            rank => $reserve_rank
114
        };
115
        next;
116
    }
117
118
    AddReserve($branch, $borrower->{'borrowernumber'}, $biblionumber, undef,
119
        $reserve_rank, $startdate, $expirationdate, $notes, $reserve_title,
120
        $checkitem, $found);
121
}
122
123
if (scalar keys %$overlap_reserves) {
124
    $template->param(
125
        borrowernumber => $borrowernumber,
126
        biblionumbers => $biblionumbers,
127
        biblionumber => $biblionumber,
128
        overlap_reserves => $overlap_reserves,
129
        reserve_date => $startdate,
130
        expiration_date => $expirationdate,
131
        notes => $notes,
132
        rank_request => \@rank,
133
        pickup => $branch,
134
        multi_hold => $multi_hold,
135
    );
136
137
    output_html_with_http_headers $input, $cookie, $template->output;
138
} else {
110
    if ($multi_hold) {
139
    if ($multi_hold) {
111
        if ($bad_bibs) {
140
        if ($bad_bibs) {
112
            $biblionumbers .= $bad_bibs;
141
            $biblionumbers .= $bad_bibs;
Lines 116-127 if ( $type eq 'str8' && $borrower ) { Link Here
116
    else {
145
    else {
117
        print $input->redirect("request.pl?biblionumber=$biblionumber");
146
        print $input->redirect("request.pl?biblionumber=$biblionumber");
118
    }
147
    }
119
}
148
    exit;
120
elsif ( $borrowernumber eq '' ) {
121
    print $input->header();
122
    print "Invalid borrower number please try again";
123
124
    # Not sure that Dump() does HTML escaping. Use firebug or something to trace
125
    # instead.
126
    #print $input->Dump;
127
}
149
}
(-)a/t/db_dependent/Circulation/CanBookBeIssued.t (+107 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 1;
21
use C4::Members;
22
use C4::Reserves;
23
use C4::Circulation;
24
use C4::Branch;
25
use Koha::DateUtils;
26
27
use t::lib::TestBuilder;
28
29
my $schema  = Koha::Database->new->schema;
30
$schema->storage->txn_begin;
31
32
my $builder = t::lib::TestBuilder->new();
33
34
subtest 'Tests for CanBookBeIssued with overlap reserves' => sub {
35
    plan tests => 6;
36
37
    my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
38
    my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
39
40
    my $borrower = $builder->build({
41
        source => 'Borrower',
42
        value => {
43
            branchcode   => $branchcode,
44
            categorycode => $categorycode,
45
        }
46
    });
47
    my $borrowernumber = $borrower->{borrowernumber};
48
    $borrower = GetMemberDetails($borrowernumber);
49
50
    my $biblio = $builder->build({source => 'Biblio'});
51
    my $biblioitem = $builder->build({
52
        source => 'Biblioitem',
53
        value => {
54
            biblionumber => $biblio->{biblionumber},
55
        },
56
    });
57
    my $item = $builder->build({
58
        source => 'Item',
59
        value => {
60
            biblionumber => $biblio->{biblionumber},
61
            biblioitemnumber => $biblioitem->{biblioitemnumber},
62
            withdrawn => 0,
63
            itemlost => 0,
64
            notforloan => 0,
65
        },
66
    });
67
68
69
    my $startdate = dt_from_string();
70
    $startdate->add_duration(DateTime::Duration->new(days => 4));
71
    my $expdate = $startdate->clone();
72
    $expdate->add_duration(DateTime::Duration->new(days => 10));
73
74
    my $reserveid = AddReserve($branchcode, $borrowernumber,
75
        $item->{biblionumber}, undef,  1, $startdate->ymd(), $expdate->ymd,
76
        undef, undef, undef, undef);
77
78
    my $non_overlap_duedate = dt_from_string();
79
    $non_overlap_duedate->add_duration(DateTime::Duration->new(days => 2));
80
    my ($error, $question, $alerts ) =
81
        CanBookBeIssued($borrower, $item->{barcode}, $non_overlap_duedate, 1, 0);
82
83
    is_deeply($error, {}, "");
84
    is_deeply($question, {}, "");
85
    is_deeply($alerts, {}, "");
86
87
    my $overlap_duedate = dt_from_string();
88
    $overlap_duedate->add_duration(DateTime::Duration->new(days => 5));
89
    ($error, $question, $alerts ) =
90
        CanBookBeIssued($borrower, $item->{barcode}, $overlap_duedate, 1, 0);
91
92
    is_deeply($error, {}, "");
93
    my $expected = {
94
        RESERVED => 1,
95
        resfirstname => $borrower->{firstname},
96
        ressurname => $borrower->{surname},
97
        rescardnumber => $borrower->{cardnumber},
98
        resborrowernumber => $borrower->{borrowernumber},
99
        resbranchname => GetBranchName($branchcode),
100
        resreservedate => $startdate->ymd,
101
        resreserveid => $reserveid,
102
    };
103
    is_deeply($question, $expected, "");
104
    is_deeply($alerts, {}, "");
105
};
106
107
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Reserves/ReserveDate.t (-1 / +108 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 6;
21
use Test::Warn;
22
23
use MARC::Record;
24
use DateTime::Duration;
25
26
use C4::Biblio;
27
use C4::Items;
28
use C4::Members;
29
use C4::Circulation;
30
use Koha::Holds;
31
use t::lib::TestBuilder;
32
33
use Koha::DateUtils;
34
35
36
use_ok('C4::Reserves');
37
38
my $dbh = C4::Context->dbh;
39
40
# Start transaction
41
$dbh->{AutoCommit} = 0;
42
$dbh->{RaiseError} = 1;
43
44
my $builder = t::lib::TestBuilder->new();
45
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
46
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
47
48
my $borrower = $builder->build({
49
    source => 'Borrower',
50
    value => {
51
        branchcode   => $branchcode,
52
        categorycode => $categorycode,
53
    }
54
});
55
56
my $borrower2 = $builder->build({
57
    source => 'Borrower',
58
    value => {
59
        branchcode   => $branchcode,
60
        categorycode => $categorycode,
61
    }
62
});
63
64
my $borrowernumber = $borrower->{borrowernumber};
65
my $borrowernumber2 = $borrower2->{borrowernumber};
66
67
# Create a helper biblio
68
my $biblio = MARC::Record->new();
69
my $title = 'Alone in the Dark';
70
my $author = 'Karen Rose';
71
if( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
72
    $biblio->append_fields(
73
        MARC::Field->new('600', '', '1', a => $author),
74
        MARC::Field->new('200', '', '', a => $title),
75
    );
76
}
77
else {
78
    $biblio->append_fields(
79
        MARC::Field->new('100', '', '', a => $author),
80
        MARC::Field->new('245', '', '', a => $title),
81
    );
82
}
83
my ($bibnum, $bibitemnum);
84
($bibnum, $title, $bibitemnum) = AddBiblio($biblio, '');
85
86
my ($item_bibnum, $item_bibitemnum, $itemnumber) = AddItem({ homebranch => $branchcode, holdingbranch => $branchcode, barcode => '333' } , $bibnum);
87
88
C4::Context->set_preference('AllowHoldDateInFuture', 1);
89
90
AddReserve($branchcode, $borrowernumber, $bibnum,
91
           $bibitemnum,  1, '2015-11-01', '2015-11-20', undef,
92
           undef, undef, undef);
93
94
is(ReservesOnSamePeriod($bibnum, undef, '2015-11-25', '2015-11-30'), undef, "Period doesn't overlaps");
95
96
ok(ReservesOnSamePeriod($bibnum, undef, '2015-11-02', '2015-11-10'), "Period overlaps");
97
98
my ($item_bibnum2, $item_bibitemnum2, $itemnumber2) = AddItem({ homebranch => $branchcode, holdingbranch => $branchcode, barcode => '444' } , $bibnum);
99
is(ReservesOnSamePeriod($bibnum, undef, '2015-11-02', '2015-11-10'), undef, "Period overlaps but there is 2 items");
100
101
AddReserve($branchcode, $borrowernumber2, $bibnum,
102
           $bibitemnum,  1, '2016-02-01', '2016-02-10', undef,
103
           undef, $itemnumber, undef);
104
is(ReservesOnSamePeriod($bibnum, $itemnumber, '02/12/2015', '10/12/2015'), undef, "Period on item does not overlap (with metric date format)");
105
106
my $reserve = ReservesOnSamePeriod($bibnum, $itemnumber, '2016-01-31', '2016-02-05');
107
is($reserve->[0]->{itemnumber}, $itemnumber, 'Period on item overlaps');
108
$dbh->rollback;

Return to bug 15261