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

(-)a/C4/Circulation.pm (+23 lines)
Lines 1006-1011 sub CanBookBeIssued { Link Here
1006
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1006
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1007
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1007
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1008
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1008
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1009
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1009
                }
1010
                }
1010
                elsif ( $restype eq "Reserved" ) {
1011
                elsif ( $restype eq "Reserved" ) {
1011
                    # The item is on reserve for someone else.
1012
                    # The item is on reserve for someone else.
Lines 1016-1024 sub CanBookBeIssued { Link Here
1016
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1017
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1017
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1018
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1018
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1019
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1020
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1019
                }
1021
                }
1020
            }
1022
            }
1021
        }
1023
        }
1024
1025
        my $now = dt_from_string();
1026
        my $preventChechoutOnSameReservePeriod =
1027
            C4::Context->preference("PreventChechoutOnSameReservePeriod");
1028
        my $reserves_on_same_period =
1029
            ReservesOnSamePeriod($item->{biblionumber}, $item->{itemnumber}, $now->ymd, $duedate->ymd);
1030
        if ($preventChechoutOnSameReservePeriod && $reserves_on_same_period) {
1031
            my $reserve = $reserves_on_same_period->[0];
1032
            my $borrower = C4::Members::GetMember(borrowernumber => $reserve->{borrowernumber});
1033
            my $branchname = Koha::Libraries->find($reserve->{branchcode})->branchname;
1034
1035
            $needsconfirmation{RESERVED} = 1;
1036
            $needsconfirmation{resfirstname} = $borrower->{firstname};
1037
            $needsconfirmation{ressurname} = $borrower->{surname};
1038
            $needsconfirmation{rescardnumber} = $borrower->{cardnumber};
1039
            $needsconfirmation{resborrowernumber} = $borrower->{borrowernumber};
1040
            $needsconfirmation{resbranchname} = $branchname;
1041
            $needsconfirmation{resreservedate} = $reserve->{reservedate};
1042
            $needsconfirmation{resreserveid} = $reserve->{reserve_id};
1043
        }
1044
1022
    }
1045
    }
1023
1046
1024
    ## CHECK AGE RESTRICTION
1047
    ## CHECK AGE RESTRICTION
(-)a/C4/Reserves.pm (+49 lines)
Lines 144-149 BEGIN { Link Here
144
        &SuspendAll
144
        &SuspendAll
145
145
146
        &GetReservesControlBranch
146
        &GetReservesControlBranch
147
		&ReservesOnSamePeriod
147
148
148
        IsItemOnHoldAndFound
149
        IsItemOnHoldAndFound
149
150
Lines 2532-2537 sub GetHoldRule { Link Here
2532
    return $sth->fetchrow_hashref();
2533
    return $sth->fetchrow_hashref();
2533
}
2534
}
2534
2535
2536
=head2 ReservesOnSamePeriod
2537
2538
    my $reserve = ReservesOnSamePeriod( $biblionumber, $itemnumber, $resdate, $expdate);
2539
2540
    Return the reserve that match the period ($resdate => $expdate),
2541
    undef if no reserve match.
2542
2543
=cut
2544
2545
sub ReservesOnSamePeriod {
2546
    my ($biblionumber, $itemnumber, $resdate, $expdate) = @_;
2547
2548
    unless ($resdate && $expdate) {
2549
        return;
2550
    }
2551
2552
    my $reserves = GetReservesFromBiblionumber({biblionumber => $biblionumber,
2553
                                                all_dates => 1});
2554
2555
    $resdate = output_pref({ str => $resdate, dateonly => 1, dateformat => 'iso' });
2556
    $expdate = output_pref({ str => $expdate, dateonly => 1, dateformat => 'iso' });
2557
2558
    my @reserves_overlaps;
2559
    foreach my $reserve (@$reserves) {
2560
2561
        unless ($reserve->{reservedate} && $reserve->{expirationdate}) {
2562
            next;
2563
        }
2564
2565
        if (date_ranges_overlap($resdate, $expdate,
2566
                                $reserve->{reservedate},
2567
                                $reserve->{expirationdate})) {
2568
2569
            # If reserve is item level and the requested periods overlap.
2570
            if ($itemnumber && $reserve->{itemnumber} == $itemnumber ) {
2571
                return [$reserve];
2572
            }
2573
            push @reserves_overlaps, $reserve;
2574
        }
2575
    }
2576
2577
    if ( @reserves_overlaps >= Koha::Items->search({ biblionumber => $biblionumber })->count() ) {
2578
        return \@reserves_overlaps;
2579
    }
2580
2581
    return;
2582
}
2583
2535
=head1 AUTHOR
2584
=head1 AUTHOR
2536
2585
2537
Koha Development Team <http://koha-community.org/>
2586
Koha Development Team <http://koha-community.org/>
(-)a/Koha/DateUtils.pm (-1 / +43 lines)
Lines 24-30 use Carp; 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 298-301 sub format_sqldatetime { Link Here
298
    return q{};
298
    return q{};
299
}
299
}
300
300
301
=head2 date_ranges_overlap
302
303
    $bool = date_ranges_overlap($start1, $end1, $start2, $end2);
304
305
    Tells if first range ($start1 => $end1) overlaps
306
    the second one ($start2 => $end2)
307
308
=cut
309
310
sub date_ranges_overlap {
311
    my ($start1, $end1, $start2, $end2) = @_;
312
313
    $start1 = dt_from_string( $start1, 'iso' );
314
    $end1 = dt_from_string( $end1, 'iso' );
315
    $start2 = dt_from_string( $start2, 'iso' );
316
    $end2 = dt_from_string( $end2, 'iso' );
317
318
    if (
319
        # Start of range 2 is in the range 1.
320
        (
321
            DateTime->compare($start2, $start1) >= 0
322
            && DateTime->compare($start2, $end1) <= 0
323
        )
324
        ||
325
        # End of range 2 is in the range 1.
326
        (
327
            DateTime->compare($end2, $start1) >= 0
328
            && DateTime->compare($end2, $end1) <= 0
329
        )
330
        ||
331
        # Range 2 start before and end after range 1.
332
        (
333
            DateTime->compare($start2, $start1) < 0
334
            && DateTime->compare($end2, $end1) > 0
335
        )
336
    ) {
337
        return 1;
338
    }
339
340
    return;
341
}
342
301
1;
343
1;
(-)a/circ/circulation.pl (+4 lines)
Lines 398-403 if (@$barcodes) { Link Here
398
        }
398
        }
399
        unless($confirm_required) {
399
        unless($confirm_required) {
400
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
400
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
401
            if ( $cancelreserve eq 'cancel' ) {
402
                CancelReserve({ reserve_id => $query->param('reserveid') });
403
            }
404
            $cancelreserve = $cancelreserve eq 'revert' ? 'revert' : undef;
401
            my $issue = AddIssue( $borrower, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, } );
405
            my $issue = AddIssue( $borrower, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew'), switch_onsite_checkout => $switch_onsite_checkout, } );
402
            $template_params->{issue} = $issue;
406
            $template_params->{issue} = $issue;
403
            $session->clear('auto_renew');
407
            $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 ('PreventChechoutOnSameReservePeriod', '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 570-574 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
570
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
570
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
571
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
571
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
572
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
572
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
573
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo')
573
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo'),
574
('PreventChechoutOnSameReservePeriod','0','','Prevent to checkout a document if a reserve on same period exists','YesNo'),
575
('PreventReservesOnSamePeriod','0','','Prevent to hold a document if a reserve on same period exists','YesNo')
574
;
576
;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+12 lines)
Lines 444-449 Circulation: Link Here
444
                  yes: Block
444
                  yes: Block
445
                  no: Allow
445
                  no: Allow
446
            - renewing of items.
446
            - renewing of items.
447
        -
448
            - pref: PreventChechoutOnSameReservePeriod
449
              choices:
450
                  yes: Do
451
                  no: "Don't"
452
            - If yes, checkouts periods can't overlap with a reserve period.
447
    Checkin Policy:
453
    Checkin Policy:
448
        -
454
        -
449
            - pref: BlockReturnOfWithdrawnItems
455
            - pref: BlockReturnOfWithdrawnItems
Lines 663-668 Circulation: Link Here
663
            - "Patron categories not affected by OPACHoldsIfAvailableAtPickup"
669
            - "Patron categories not affected by OPACHoldsIfAvailableAtPickup"
664
            - pref: OPACHoldsIfAvailableAtPickupExceptions
670
            - pref: OPACHoldsIfAvailableAtPickupExceptions
665
            - "(list of patron categories separated with a pipe '|')"
671
            - "(list of patron categories separated with a pipe '|')"
672
        -
673
            - pref: PreventReservesOnSamePeriod
674
              choices:
675
                  yes: Do
676
                  no: "Don't"
677
            - If yes, Reserves periods for the same document can't overlap.
666
    Fines Policy:
678
    Fines Policy:
667
        -
679
        -
668
            - Calculate fines based on days overdue
680
            - Calculate fines based on days overdue
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+2 lines)
Lines 333-338 $(document).ready(function() { Link Here
333
[% IF ( RESERVED ) %]
333
[% IF ( RESERVED ) %]
334
    <p>
334
    <p>
335
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
335
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
336
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
336
    <label for="cancelreserve">Cancel hold</label>
337
    <label for="cancelreserve">Cancel hold</label>
337
    </p>
338
    </p>
338
[% END %]
339
[% END %]
Lines 341-346 $(document).ready(function() { Link Here
341
<p>
342
<p>
342
    <label for="cancelreserve">Cancel hold</label>
343
    <label for="cancelreserve">Cancel hold</label>
343
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
344
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
345
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
344
    <label for="revertreserve">Revert waiting status</label>
346
    <label for="revertreserve">Revert waiting status</label>
345
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
347
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
346
</p>
348
</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 278-283 if ( $query->param('place_reserve') ) { Link Here
278
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
278
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
279
            $itemNum = undef;
279
            $itemNum = undef;
280
        }
280
        }
281
282
        if ($canreserve) {
283
            if (C4::Context->preference("PreventReservesOnSamePeriod") &&
284
                ReservesOnSamePeriod($biblioNum, $itemNum, $startdate, $expiration_date)) {
285
                $canreserve = 0;
286
                $failed_holds++;
287
            }
288
        }
289
281
        my $notes = $query->param('notes_'.$biblioNum)||'';
290
        my $notes = $query->param('notes_'.$biblioNum)||'';
282
291
283
        if (   $maxreserves
292
        if (   $maxreserves
(-)a/reserve/placerequest.pl (-59 / +81 lines)
Lines 31-76 use C4::Output; Link Here
31
use C4::Reserves;
31
use C4::Reserves;
32
use C4::Circulation;
32
use C4::Circulation;
33
use C4::Members;
33
use C4::Members;
34
use C4::Auth qw/checkauth/;
34
use C4::Auth;
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 = GetMember( 'borrowernumber' => $borrowernumber );
59
my @confirm_biblionumbers = $input->param('confirm_biblionumbers');
55
60
56
my $multi_hold = $input->param('multi_hold');
61
my $multi_hold = $input->param('multi_hold');
57
my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/');
62
my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/');
58
my $bad_bibs = $input->param('bad_bibs');
63
my $bad_bibs = $input->param('bad_bibs');
59
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;
60
65
66
my $borrower=GetMember('borrowernumber'=>$borrowernumber);
67
unless ($borrower) {
68
    print $input->header();
69
    print "Invalid borrower number please try again";
70
    exit;
71
}
72
61
my %bibinfos = ();
73
my %bibinfos = ();
62
my @biblionumbers = split '/', $biblionumbers;
74
my @biblionumbers = split '/', $biblionumbers;
63
foreach my $bibnum (@biblionumbers) {
75
foreach my $bibnum (@biblionumbers) {
64
    my %bibinfo = ();
76
    my %bibinfo;
65
    $bibinfo{title} = $input->param("title_$bibnum");
77
    $bibinfo{title} = $input->param("title_$bibnum");
78
66
    $bibinfo{rank} = $input->param("rank_$bibnum");
79
    $bibinfo{rank} = $input->param("rank_$bibnum");
67
    $bibinfos{$bibnum} = \%bibinfo;
80
    $bibinfos{$bibnum} = \%bibinfo;
68
}
81
}
69
82
70
my $found;
83
my $found;
71
84
72
# if we have an item selectionned, and the pickup branch is the same as the holdingbranch
85
# if we have an item selectionned, and the pickup branch is the same as the
73
# of the document, we force the value $rank and $found .
86
# holdingbranch of the document, we force the value $rank and $found .
74
if (defined $checkitem && $checkitem ne ''){
87
if (defined $checkitem && $checkitem ne ''){
75
    $holds_to_place_count = 1;
88
    $holds_to_place_count = 1;
76
    $rank[0] = '0' unless C4::Context->preference('ReservesNeedReturns');
89
    $rank[0] = '0' unless C4::Context->preference('ReservesNeedReturns');
Lines 81-123 if (defined $checkitem && $checkitem ne ''){ Link Here
81
    }
94
    }
82
}
95
}
83
96
84
if ( $type eq 'str8' && $borrower ) {
97
my $overlap_reserves = {};
85
98
foreach my $biblionumber (keys %bibinfos) {
86
    foreach my $biblionumber ( keys %bibinfos ) {
99
    next if ($confirm && !grep { $_ eq $biblionumber } @confirm_biblionumbers);
87
        my $count = @bibitems;
88
        @bibitems = sort @bibitems;
89
        my $i2 = 1;
90
        my @realbi;
91
        $realbi[0] = $bibitems[0];
92
        for ( my $i = 1 ; $i < $count ; $i++ ) {
93
            my $i3 = $i2 - 1;
94
            if ( $realbi[$i3] ne $bibitems[$i] ) {
95
                $realbi[$i2] = $bibitems[$i];
96
                $i2++;
97
            }
98
        }
99
100
100
        if ( defined $checkitem && $checkitem ne '' ) {
101
    my ($reserve_title, $reserve_rank);
101
            my $item = GetItem($checkitem);
102
    if ($multi_hold) {
102
            if ( $item->{'biblionumber'} ne $biblionumber ) {
103
        my $bibinfo = $bibinfos{$biblionumber};
103
                $biblionumber = $item->{'biblionumber'};
104
        $reserve_rank = $bibinfo->{rank};
104
            }
105
        $reserve_title = $bibinfo->{title};
105
        }
106
    } else {
107
        $reserve_rank = $rank[0];
108
        $reserve_title = $title;
109
    }
106
110
107
        if ($multi_hold) {
111
    if (defined $checkitem && $checkitem ne '') {
108
            my $bibinfo = $bibinfos{$biblionumber};
112
        my $item = GetItem($checkitem);
109
            AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,[$biblionumber],
113
        if ($item->{'biblionumber'} ne $biblionumber) {
110
                       $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found);
114
            $biblionumber = $item->{'biblionumber'};
111
        } else {
112
            # place a request on 1st available
113
            for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) {
114
                AddReserve( $branch, $borrower->{'borrowernumber'},
115
                    $biblionumber, \@realbi, $rank[0], $startdate, $expirationdate, $notes, $title,
116
                    $checkitem, $found, $itemtype );
117
            }
118
        }
115
        }
119
    }
116
    }
120
117
118
    if (!$confirm &&
119
        ReservesOnSamePeriod($biblionumber, $checkitem, $startdate, $expirationdate) &&
120
        C4::Context->preference("PreventReservesOnSamePeriod")) {
121
        $overlap_reserves->{$biblionumber} = {
122
            title => $reserve_title ,
123
            checkitem => $checkitem,
124
            rank => $reserve_rank
125
        };
126
        next;
127
    }
128
129
    AddReserve($branch, $borrower->{'borrowernumber'}, $biblionumber, undef,
130
        $reserve_rank, $startdate, $expirationdate, $notes, $reserve_title,
131
        $checkitem, $found);
132
}
133
134
if (scalar keys %$overlap_reserves) {
135
    $template->param(
136
        borrowernumber => $borrowernumber,
137
        biblionumbers => $biblionumbers,
138
        biblionumber => $biblionumber,
139
        overlap_reserves => $overlap_reserves,
140
        reserve_date => $startdate,
141
        expiration_date => $expirationdate,
142
        notes => $notes,
143
        rank_request => \@rank,
144
        pickup => $branch,
145
        multi_hold => $multi_hold,
146
    );
147
148
    output_html_with_http_headers $input, $cookie, $template->output;
149
} else {
121
    if ($multi_hold) {
150
    if ($multi_hold) {
122
        if ($bad_bibs) {
151
        if ($bad_bibs) {
123
            $biblionumbers .= $bad_bibs;
152
            $biblionumbers .= $bad_bibs;
Lines 127-138 if ( $type eq 'str8' && $borrower ) { Link Here
127
    else {
156
    else {
128
        print $input->redirect("request.pl?biblionumber=$biblionumber");
157
        print $input->redirect("request.pl?biblionumber=$biblionumber");
129
    }
158
    }
130
}
159
    exit;
131
elsif ( $borrower eq '' ) {
132
    print $input->header();
133
    print "Invalid borrower number please try again";
134
135
    # Not sure that Dump() does HTML escaping. Use firebug or something to trace
136
    # instead.
137
    #print $input->Dump;
138
}
160
}
(-)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::Branch;
27
use C4::Biblio;
28
use C4::Items;
29
use C4::Members;
30
use C4::Circulation;
31
use Koha::Holds;
32
use t::lib::TestBuilder;
33
34
use Koha::DateUtils;
35
36
37
use_ok('C4::Reserves');
38
39
my $dbh = C4::Context->dbh;
40
41
# Start transaction
42
$dbh->{AutoCommit} = 0;
43
$dbh->{RaiseError} = 1;
44
45
my $builder = t::lib::TestBuilder->new();
46
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
47
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
48
49
my $borrower = $builder->build({
50
    source => 'Borrower',
51
    value => {
52
        branchcode   => $branchcode,
53
        categorycode => $categorycode,
54
    }
55
});
56
57
my $borrower2 = $builder->build({
58
    source => 'Borrower',
59
    value => {
60
        branchcode   => $branchcode,
61
        categorycode => $categorycode,
62
    }
63
});
64
65
my $borrowernumber = $borrower->{borrowernumber};
66
my $borrowernumber2 = $borrower2->{borrowernumber};
67
68
# Create a helper biblio
69
my $biblio = MARC::Record->new();
70
my $title = 'Alone in the Dark';
71
my $author = 'Karen Rose';
72
if( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
73
    $biblio->append_fields(
74
        MARC::Field->new('600', '', '1', a => $author),
75
        MARC::Field->new('200', '', '', a => $title),
76
    );
77
}
78
else {
79
    $biblio->append_fields(
80
        MARC::Field->new('100', '', '', a => $author),
81
        MARC::Field->new('245', '', '', a => $title),
82
    );
83
}
84
my ($bibnum, $bibitemnum);
85
($bibnum, $title, $bibitemnum) = AddBiblio($biblio, '');
86
87
my ($item_bibnum, $item_bibitemnum, $itemnumber) = AddItem({ homebranch => $branchcode, holdingbranch => $branchcode, barcode => '333' } , $bibnum);
88
89
C4::Context->set_preference('AllowHoldDateInFuture', 1);
90
91
AddReserve($branchcode, $borrowernumber, $bibnum,
92
           $bibitemnum,  1, '2015-11-01', '2015-11-20', undef,
93
           undef, undef, undef);
94
95
is(ReservesOnSamePeriod($bibnum, undef, '2015-11-25', '2015-11-30'), undef, "Period doesn't overlaps");
96
97
ok(ReservesOnSamePeriod($bibnum, undef, '2015-11-02', '2015-11-10'), "Period overlaps");
98
99
my ($item_bibnum2, $item_bibitemnum2, $itemnumber2) = AddItem({ homebranch => $branchcode, holdingbranch => $branchcode, barcode => '444' } , $bibnum);
100
is(ReservesOnSamePeriod($bibnum, undef, '2015-11-02', '2015-11-10'), undef, "Period overlaps but there is 2 items");
101
102
AddReserve($branchcode, $borrowernumber2, $bibnum,
103
           $bibitemnum,  1, '2016-02-01', '2016-02-10', undef,
104
           undef, $itemnumber, undef);
105
is(ReservesOnSamePeriod($bibnum, $itemnumber, '02/12/2015', '10/12/2015'), undef, "Period on item does not overlap (with metric date format)");
106
107
ok(ReservesOnSamePeriod($bibnum, $itemnumber, '2016-01-31', '2016-02-05'), "Period on item overlaps");
108
$dbh->rollback;

Return to bug 15261