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

(-)a/C4/Circulation.pm (+23 lines)
Lines 1008-1013 sub CanBookBeIssued { Link Here
1008
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1008
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1009
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1009
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1010
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1010
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1011
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1011
                }
1012
                }
1012
                elsif ( $restype eq "Reserved" ) {
1013
                elsif ( $restype eq "Reserved" ) {
1013
                    # The item is on reserve for someone else.
1014
                    # The item is on reserve for someone else.
Lines 1018-1026 sub CanBookBeIssued { Link Here
1018
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1019
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1019
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1020
                    $needsconfirmation{'resbranchcode'} = $res->{branchcode};
1020
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1021
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1022
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1021
                }
1023
                }
1022
            }
1024
            }
1023
        }
1025
        }
1026
1027
        my $now = dt_from_string();
1028
        my $preventChechoutOnSameReservePeriod =
1029
            C4::Context->preference("PreventChechoutOnSameReservePeriod");
1030
        my $reserves_on_same_period =
1031
            ReservesOnSamePeriod($item->{biblionumber}, $item->{itemnumber}, $now->ymd, $duedate->ymd);
1032
        if ($preventChechoutOnSameReservePeriod && $reserves_on_same_period) {
1033
            my $reserve = $reserves_on_same_period->[0];
1034
            my $borrower = C4::Members::GetMember(borrowernumber => $reserve->{borrowernumber});
1035
            my $branchname = Koha::Libraries->find($reserve->{branchcode})->branchname;
1036
1037
            $needsconfirmation{RESERVED} = 1;
1038
            $needsconfirmation{resfirstname} = $borrower->{firstname};
1039
            $needsconfirmation{ressurname} = $borrower->{surname};
1040
            $needsconfirmation{rescardnumber} = $borrower->{cardnumber};
1041
            $needsconfirmation{resborrowernumber} = $borrower->{borrowernumber};
1042
            $needsconfirmation{resbranchname} = $branchname;
1043
            $needsconfirmation{resreservedate} = $reserve->{reservedate};
1044
            $needsconfirmation{resreserveid} = $reserve->{reserve_id};
1045
        }
1046
1024
    }
1047
    }
1025
1048
1026
    ## CHECK AGE RESTRICTION
1049
    ## 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 >= GetItemsCount($biblionumber)) {
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 403-408 if (@$barcodes) { Link Here
403
        }
403
        }
404
        unless($confirm_required) {
404
        unless($confirm_required) {
405
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
405
            my $switch_onsite_checkout = exists $messages->{ONSITE_CHECKOUT_WILL_BE_SWITCHED};
406
            if ( $cancelreserve eq 'cancel' ) {
407
                CancelReserve({ reserve_id => $query->param('reserveid') });
408
            }
409
            $cancelreserve = $cancelreserve eq 'revert' ? 'revert' : undef;
406
            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, } );
410
            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, } );
407
            $template_params->{issue} = $issue;
411
            $template_params->{issue} = $issue;
408
            $session->clear('auto_renew');
412
            $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 563-567 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
563
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
563
('XSLTListsDisplay','default','','Enable XSLT stylesheet control over lists pages display on intranet','Free'),
564
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
564
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
565
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
565
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
566
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo')
566
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo'),
567
('PreventChechoutOnSameReservePeriod','0','','Prevent to checkout a document if a reserve on same period exists','YesNo'),
568
('PreventReservesOnSamePeriod','0','','Prevent to hold a document if a reserve on same period exists','YesNo')
567
;
569
;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+12 lines)
Lines 438-443 Circulation: Link Here
438
                  yes: Block
438
                  yes: Block
439
                  no: Allow
439
                  no: Allow
440
            - renewing of items.
440
            - renewing of items.
441
        -
442
            - pref: PreventChechoutOnSameReservePeriod
443
              choices:
444
                  yes: Do
445
                  no: "Don't"
446
            - If yes, checkouts periods can't overlap with a reserve period.
441
    Checkin Policy:
447
    Checkin Policy:
442
        -
448
        -
443
            - pref: BlockReturnOfWithdrawnItems
449
            - pref: BlockReturnOfWithdrawnItems
Lines 647-652 Circulation: Link Here
647
              choices:
653
              choices:
648
                  homebranch: "home library"
654
                  homebranch: "home library"
649
                  holdingbranch: "holding library"
655
                  holdingbranch: "holding library"
656
        -
657
            - pref: PreventReservesOnSamePeriod
658
              choices:
659
                  yes: Do
660
                  no: "Don't"
661
            - If yes, Reserves periods for the same document can't overlap.
650
    Fines Policy:
662
    Fines Policy:
651
        -
663
        -
652
            - Calculate fines based on days overdue
664
            - 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 270-275 if ( $query->param('place_reserve') ) { Link Here
270
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
270
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
271
            $itemNum = undef;
271
            $itemNum = undef;
272
        }
272
        }
273
274
        if ($canreserve) {
275
            if (C4::Context->preference("PreventReservesOnSamePeriod") &&
276
                ReservesOnSamePeriod($biblioNum, $itemNum, $startdate, $expiration_date)) {
277
                $canreserve = 0;
278
                $failed_holds++;
279
            }
280
        }
281
273
        my $notes = $query->param('notes_'.$biblioNum)||'';
282
        my $notes = $query->param('notes_'.$biblioNum)||'';
274
283
275
        if (   $maxreserves
284
        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