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

(-)a/C4/Circulation.pm (+23 lines)
Lines 1073-1078 sub CanBookBeIssued { Link Here
1073
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1073
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1074
                    $needsconfirmation{'resbranchname'} = $branchname;
1074
                    $needsconfirmation{'resbranchname'} = $branchname;
1075
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1075
                    $needsconfirmation{'reswaitingdate'} = $res->{'waitingdate'};
1076
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1076
                }
1077
                }
1077
                elsif ( $restype eq "Reserved" ) {
1078
                elsif ( $restype eq "Reserved" ) {
1078
                    # The item is on reserve for someone else.
1079
                    # The item is on reserve for someone else.
Lines 1083-1091 sub CanBookBeIssued { Link Here
1083
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1084
                    $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
1084
                    $needsconfirmation{'resbranchname'} = $branchname;
1085
                    $needsconfirmation{'resbranchname'} = $branchname;
1085
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1086
                    $needsconfirmation{'resreservedate'} = $res->{'reservedate'};
1087
                    $needsconfirmation{resreserveid} = $res->{reserve_id};
1086
                }
1088
                }
1087
            }
1089
            }
1088
        }
1090
        }
1091
1092
        my $now = dt_from_string();
1093
        my $preventChechoutOnSameReservePeriod =
1094
            C4::Context->preference("PreventChechoutOnSameReservePeriod");
1095
        my $reserves_on_same_period =
1096
            ReservesOnSamePeriod($item->{biblionumber}, $item->{itemnumber}, $now->ymd, $duedate->ymd);
1097
        if ($preventChechoutOnSameReservePeriod && $reserves_on_same_period) {
1098
            my $reserve = $reserves_on_same_period->[0];
1099
            my $borrower = C4::Members::GetMember(borrowernumber => $reserve->{borrowernumber});
1100
            my $branchname = GetBranchName( $reserve->{branchcode} );
1101
1102
            $needsconfirmation{RESERVED} = 1;
1103
            $needsconfirmation{resfirstname} = $borrower->{firstname};
1104
            $needsconfirmation{ressurname} = $borrower->{surname};
1105
            $needsconfirmation{rescardnumber} = $borrower->{cardnumber};
1106
            $needsconfirmation{resborrowernumber} = $borrower->{borrowernumber};
1107
            $needsconfirmation{resbranchname} = $branchname;
1108
            $needsconfirmation{resreservedate} = $reserve->{reservedate};
1109
            $needsconfirmation{resreserveid} = $reserve->{reserve_id};
1110
        }
1111
1089
    }
1112
    }
1090
1113
1091
    ## CHECK AGE RESTRICTION
1114
    ## CHECK AGE RESTRICTION
(-)a/C4/Installer/PerlDependencies.pm (-1 / +1 lines)
Lines 806-812 our $PERL_DEPS = { Link Here
806
        'usage'    => 'Enhanced Content - Tagging',
806
        'usage'    => 'Enhanced Content - Tagging',
807
        'required' => '0',
807
        'required' => '0',
808
        'min_ver'  => '0.07'
808
        'min_ver'  => '0.07'
809
    },
809
    }
810
};
810
};
811
811
812
1;
812
1;
(-)a/C4/Reserves.pm (+49 lines)
Lines 139-144 BEGIN { Link Here
139
        &SuspendAll
139
        &SuspendAll
140
140
141
        &GetReservesControlBranch
141
        &GetReservesControlBranch
142
		&ReservesOnSamePeriod
142
143
143
        IsItemOnHoldAndFound
144
        IsItemOnHoldAndFound
144
    );
145
    );
Lines 2482-2487 sub IsItemOnHoldAndFound { Link Here
2482
    return $found;
2483
    return $found;
2483
}
2484
}
2484
2485
2486
=head2 ReservesOnSamePeriod
2487
2488
    my $reserve = ReservesOnSamePeriod( $biblionumber, $itemnumber, $resdate, $expdate);
2489
2490
    Return the reserve that match the period ($resdate => $expdate),
2491
    undef if no reserve match.
2492
2493
=cut
2494
2495
sub ReservesOnSamePeriod {
2496
    my ($biblionumber, $itemnumber, $resdate, $expdate) = @_;
2497
2498
    unless ($resdate && $expdate) {
2499
        return;
2500
    }
2501
2502
    my $reserves = GetReservesFromBiblionumber({biblionumber => $biblionumber,
2503
                                                all_dates => 1});
2504
2505
    $resdate = output_pref({ str => $resdate, dateonly => 1, dateformat => 'iso' });
2506
    $expdate = output_pref({ str => $expdate, dateonly => 1, dateformat => 'iso' });
2507
2508
    my @reserves_overlaps;
2509
    foreach my $reserve (@$reserves) {
2510
2511
        unless ($reserve->{reservedate} && $reserve->{expirationdate}) {
2512
            next;
2513
        }
2514
2515
        if (date_ranges_overlap($resdate, $expdate,
2516
                                $reserve->{reservedate},
2517
                                $reserve->{expirationdate})) {
2518
2519
            # If reserve is item level and the requested periods overlap.
2520
            if ($itemnumber && $reserve->{itemnumber} == $itemnumber ) {
2521
                return [$reserve];
2522
            }
2523
            push @reserves_overlaps, $reserve;
2524
        }
2525
    }
2526
2527
    if (@reserves_overlaps >= GetItemsCount($biblionumber)) {
2528
        return \@reserves_overlaps;
2529
    }
2530
2531
    return;
2532
}
2533
2485
=head1 AUTHOR
2534
=head1 AUTHOR
2486
2535
2487
Koha Development Team <http://koha-community.org/>
2536
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 295-298 sub format_sqldatetime { Link Here
295
    return q{};
295
    return q{};
296
}
296
}
297
297
298
=head2 date_ranges_overlap
299
300
    $bool = date_ranges_overlap($start1, $end1, $start2, $end2);
301
302
    Tells if first range ($start1 => $end1) overlaps
303
    the second one ($start2 => $end2)
304
305
=cut
306
307
sub date_ranges_overlap {
308
    my ($start1, $end1, $start2, $end2) = @_;
309
310
    $start1 = dt_from_string( $start1, 'iso' );
311
    $end1 = dt_from_string( $end1, 'iso' );
312
    $start2 = dt_from_string( $start2, 'iso' );
313
    $end2 = dt_from_string( $end2, 'iso' );
314
315
    if (
316
        # Start of range 2 is in the range 1.
317
        (
318
            DateTime->compare($start2, $start1) >= 0
319
            && DateTime->compare($start2, $end1) <= 0
320
        )
321
        ||
322
        # End of range 2 is in the range 1.
323
        (
324
            DateTime->compare($end2, $start1) >= 0
325
            && DateTime->compare($end2, $end1) <= 0
326
        )
327
        ||
328
        # Range 2 start before and end after range 1.
329
        (
330
            DateTime->compare($start2, $start1) < 0
331
            && DateTime->compare($end2, $end1) > 0
332
        )
333
    ) {
334
        return 1;
335
    }
336
337
    return;
338
}
339
298
1;
340
1;
(-)a/circ/circulation.pl (+4 lines)
Lines 404-409 if (@$barcodes) { Link Here
404
            }
404
            }
405
        }
405
        }
406
        unless($confirm_required) {
406
        unless($confirm_required) {
407
            if ( $cancelreserve eq 'cancel' ) {
408
                CancelReserve({ reserve_id => $query->param('reserveid') });
409
            }
410
            $cancelreserve = $cancelreserve eq 'revert' ? 'revert' : undef;
407
            my $issue = AddIssue( $borrower, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew') } );
411
            my $issue = AddIssue( $borrower, $barcode, $datedue, $cancelreserve, undef, undef, { onsite_checkout => $onsite_checkout, auto_renew => $session->param('auto_renew') } );
408
            $template_params->{issue} = $issue;
412
            $template_params->{issue} = $issue;
409
            $session->clear('auto_renew');
413
            $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 535-539 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
535
('XSLTDetailsDisplay','default','','Enable XSL stylesheet control over details page display on intranet','Free'),
535
('XSLTDetailsDisplay','default','','Enable XSL stylesheet control over details page display on intranet','Free'),
536
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
536
('XSLTResultsDisplay','default','','Enable XSL stylesheet control over results page display on intranet','Free'),
537
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
537
('z3950AuthorAuthFields','701,702,700',NULL,'Define the MARC biblio fields for Personal Name Authorities to fill biblio.author','free'),
538
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo')
538
('z3950NormalizeAuthor','0','','If ON, Personal Name Authorities will replace authors in biblio.author','YesNo'),
539
('PreventChechoutOnSameReservePeriod','0','','Prevent to checkout a document if a reserve on same period exists','YesNo'),
540
('PreventReservesOnSamePeriod','0','','Prevent to hold a document if a reserve on same period exists','YesNo')
539
;
541
;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+12 lines)
Lines 426-431 Circulation: Link Here
426
                  yes: Block
426
                  yes: Block
427
                  no: Allow
427
                  no: Allow
428
            - renewing of items.
428
            - renewing of items.
429
        -
430
            - pref: PreventChechoutOnSameReservePeriod
431
              choices:
432
                  yes: Do
433
                  no: "Don't"
434
            - If yes, checkouts periods can't overlap with a reserve period.
429
    Checkin Policy:
435
    Checkin Policy:
430
        -
436
        -
431
            - pref: BlockReturnOfWithdrawnItems
437
            - pref: BlockReturnOfWithdrawnItems
Lines 635-640 Circulation: Link Here
635
              choices:
641
              choices:
636
                  homebranch: "home library"
642
                  homebranch: "home library"
637
                  holdingbranch: "holding library"
643
                  holdingbranch: "holding library"
644
        -
645
            - pref: PreventReservesOnSamePeriod
646
              choices:
647
                  yes: Do
648
                  no: "Don't"
649
            - If yes, Reserves periods for the same document can't overlap.
638
    Fines Policy:
650
    Fines Policy:
639
        -
651
        -
640
            - Calculate fines based on days overdue
652
            - Calculate fines based on days overdue
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (+2 lines)
Lines 349-354 $(document).ready(function() { Link Here
349
[% IF ( RESERVED ) %]
349
[% IF ( RESERVED ) %]
350
    <p>
350
    <p>
351
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
351
    <input type="checkbox" id="cancelreserve" name="cancelreserve" value="cancel" />
352
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
352
    <label for="cancelreserve">Cancel hold</label>
353
    <label for="cancelreserve">Cancel hold</label>
353
    </p>
354
    </p>
354
[% END %]
355
[% END %]
Lines 357-362 $(document).ready(function() { Link Here
357
<p>
358
<p>
358
    <label for="cancelreserve">Cancel hold</label>
359
    <label for="cancelreserve">Cancel hold</label>
359
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
360
    <input type="radio" value="cancel" name="cancelreserve" id="cancelreserve" /><br />
361
    <input type="hidden" name="reserveid" value="[% resreserveid %]" />
360
    <label for="revertreserve">Revert waiting status</label>
362
    <label for="revertreserve">Revert waiting status</label>
361
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
363
    <input type="radio" value="revert" name="cancelreserve" id="revertreserve" checked="checked"/>
362
</p>
364
</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 274-279 if ( $query->param('place_reserve') ) { Link Here
274
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
274
            # Inserts a null into the 'itemnumber' field of 'reserves' table.
275
            $itemNum = undef;
275
            $itemNum = undef;
276
        }
276
        }
277
278
        if ($canreserve) {
279
            if (C4::Context->preference("PreventReservesOnSamePeriod") &&
280
                ReservesOnSamePeriod($biblioNum, $itemNum, $startdate, $expiration_date)) {
281
                $canreserve = 0;
282
                $failed_holds++;
283
            }
284
        }
285
277
        my $notes = $query->param('notes_'.$biblioNum)||'';
286
        my $notes = $query->param('notes_'.$biblioNum)||'';
278
287
279
        if (   $maxreserves
288
        if (   $maxreserves
(-)a/reserve/placerequest.pl (-55 / +81 lines)
Lines 31-75 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
64
65
my $borrower=GetMember('borrowernumber'=>$borrowernumber);
66
unless ($borrower) {
67
    print $input->header();
68
    print "Invalid borrower number please try again";
69
    exit;
70
}
71
60
my %bibinfos = ();
72
my %bibinfos = ();
61
my @biblionumbers = split '/', $biblionumbers;
73
my @biblionumbers = split '/', $biblionumbers;
62
foreach my $bibnum (@biblionumbers) {
74
foreach my $bibnum (@biblionumbers) {
63
    my %bibinfo = ();
75
    my %bibinfo;
64
    $bibinfo{title} = $input->param("title_$bibnum");
76
    $bibinfo{title} = $input->param("title_$bibnum");
77
65
    $bibinfo{rank} = $input->param("rank_$bibnum");
78
    $bibinfo{rank} = $input->param("rank_$bibnum");
66
    $bibinfos{$bibnum} = \%bibinfo;
79
    $bibinfos{$bibnum} = \%bibinfo;
67
}
80
}
68
81
69
my $found;
82
my $found;
70
83
71
# if we have an item selectionned, and the pickup branch is the same as the holdingbranch
84
# if we have an item selectionned, and the pickup branch is the same as the
72
# of the document, we force the value $rank and $found .
85
# holdingbranch of the document, we force the value $rank and $found .
73
if (defined $checkitem && $checkitem ne ''){
86
if (defined $checkitem && $checkitem ne ''){
74
    $rank[0] = '0' unless C4::Context->preference('ReservesNeedReturns');
87
    $rank[0] = '0' unless C4::Context->preference('ReservesNeedReturns');
75
    my $item = $checkitem;
88
    my $item = $checkitem;
Lines 79-119 if (defined $checkitem && $checkitem ne ''){ Link Here
79
    }
92
    }
80
}
93
}
81
94
82
if ($type eq 'str8' && $borrower){
95
my $overlap_reserves = {};
83
96
foreach my $biblionumber (keys %bibinfos) {
84
    foreach my $biblionumber (keys %bibinfos) {
97
    next if ($confirm && !grep { $_ eq $biblionumber } @confirm_biblionumbers);
85
        my $count=@bibitems;
86
        @bibitems=sort @bibitems;
87
        my $i2=1;
88
        my @realbi;
89
        $realbi[0]=$bibitems[0];
90
        for (my $i=1;$i<$count;$i++) {
91
            my $i3=$i2-1;
92
            if ($realbi[$i3] ne $bibitems[$i]) {
93
                $realbi[$i2]=$bibitems[$i];
94
                $i2++;
95
            }
96
        }
97
98
    if (defined $checkitem && $checkitem ne ''){
99
		my $item = GetItem($checkitem);
100
        	if ($item->{'biblionumber'} ne $biblionumber) {
101
                	$biblionumber = $item->{'biblionumber'};
102
        	}
103
	}
104
105
98
99
    my ($reserve_title, $reserve_rank);
100
    if ($multi_hold) {
101
        my $bibinfo = $bibinfos{$biblionumber};
102
        $reserve_rank = $bibinfo->{rank};
103
        $reserve_title = $bibinfo->{title};
104
    } else {
105
        $reserve_rank = $rank[0];
106
        $reserve_title = $title;
107
    }
106
108
107
        if ($multi_hold) {
109
    if (defined $checkitem && $checkitem ne '') {
108
            my $bibinfo = $bibinfos{$biblionumber};
110
        my $item = GetItem($checkitem);
109
            AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,[$biblionumber],
111
        if ($item->{'biblionumber'} ne $biblionumber) {
110
                       $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found);
112
            $biblionumber = $item->{'biblionumber'};
111
        } else {
112
            # place a request on 1st available
113
            AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,\@realbi,$rank[0],$startdate,$expirationdate,$notes,$title,$checkitem,$found, $itemtype);
114
        }
113
        }
115
    }
114
    }
116
115
116
    if (!$confirm &&
117
        ReservesOnSamePeriod($biblionumber, $checkitem, $startdate, $expirationdate) &&
118
        C4::Context->preference("PreventReservesOnSamePeriod")) {
119
        $overlap_reserves->{$biblionumber} = {
120
            title => $reserve_title ,
121
            checkitem => $checkitem,
122
            rank => $reserve_rank
123
        };
124
        next;
125
    }
126
127
    AddReserve($branch, $borrower->{'borrowernumber'}, $biblionumber, undef,
128
        $reserve_rank, $startdate, $expirationdate, $notes, $reserve_title,
129
        $checkitem, $found);
130
}
131
132
if (scalar keys %$overlap_reserves) {
133
    $template->param(
134
        borrowernumber => $borrowernumber,
135
        biblionumbers => $biblionumbers,
136
        biblionumber => $biblionumber,
137
        overlap_reserves => $overlap_reserves,
138
        reserve_date => $startdate,
139
        expiration_date => $expirationdate,
140
        notes => $notes,
141
        rank_request => \@rank,
142
        pickup => $branch,
143
        multi_hold => $multi_hold,
144
    );
145
146
    output_html_with_http_headers $input, $cookie, $template->output;
147
} else {
117
    if ($multi_hold) {
148
    if ($multi_hold) {
118
        if ($bad_bibs) {
149
        if ($bad_bibs) {
119
            $biblionumbers .= $bad_bibs;
150
            $biblionumbers .= $bad_bibs;
Lines 122-131 if ($type eq 'str8' && $borrower){ Link Here
122
    } else {
153
    } else {
123
        print $input->redirect("request.pl?biblionumber=$biblionumber");
154
        print $input->redirect("request.pl?biblionumber=$biblionumber");
124
    }
155
    }
125
} elsif ($borrower eq ''){
156
    exit;
126
	print $input->header();
127
	print "Invalid borrower number please try again";
128
# Not sure that Dump() does HTML escaping. Use firebug or something to trace
129
# instead.
130
#	print $input->Dump;
131
}
157
}
(-)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