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

(-)a/C4/Circulation.pm (-15 / +36 lines)
Lines 127-132 use Koha::Library::FloatLimits; Link Here
127
use Koha::Patron::Quotas;
127
use Koha::Patron::Quotas;
128
use Koha::Patron::Quota;
128
use Koha::Patron::Quota;
129
use Koha::Patron::Quota::Usage;
129
use Koha::Patron::Quota::Usage;
130
use Koha::Patron::Quota::Usages;
130
use Carp            qw( carp );
131
use Carp            qw( carp );
131
use List::MoreUtils qw( any );
132
use List::MoreUtils qw( any );
132
use Scalar::Util    qw( looks_like_number blessed );
133
use Scalar::Util    qw( looks_like_number blessed );
Lines 1376-1386 sub CanBookBeIssued { Link Here
1376
1377
1377
    # CHECK FOR QUOTAS
1378
    # CHECK FOR QUOTAS
1378
    if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) {
1379
    if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) {
1379
        unless ( $quota->has_available_quota ) {
1380
        if (ref($quota) eq 'ARRAY') {
1381
            # Multiple available quotas found - need confirmation from user
1382
            $needsconfirmation{QUOTA_SELECT} = $quota;
1383
        }
1384
        elsif (!$quota->has_available_quota) {
1380
            if ( C4::Context->preference("AllowQuotaOverride") ) {
1385
            if ( C4::Context->preference("AllowQuotaOverride") ) {
1381
                $needsconfirmation{QUOTA_EXCEEDED} = {
1386
                $needsconfirmation{QUOTA_EXCEEDED} = {
1382
                    available => $quota->available_quota,
1387
                    available => $quota->available_quota,
1383
                    total => $quota->allocation,
1388
                    total => $quota->allocation, 
1384
                    used => $quota->used,
1389
                    used => $quota->used,
1385
                };
1390
                };
1386
            }
1391
            }
Lines 1638-1643 sub AddIssue { Link Here
1638
    my $recall_id              = $params && $params->{recall_id};
1643
    my $recall_id              = $params && $params->{recall_id};
1639
    my $confirmations          = $params->{confirmations};
1644
    my $confirmations          = $params->{confirmations};
1640
    my $forced                 = $params->{forced};
1645
    my $forced                 = $params->{forced};
1646
    my $selected_quota_id      = $params && $params->{selected_quota_id};
1641
    my $dbh                    = C4::Context->dbh;
1647
    my $dbh                    = C4::Context->dbh;
1642
    my $barcodecheck           = CheckValidBarcode($barcode);
1648
    my $barcodecheck           = CheckValidBarcode($barcode);
1643
1649
Lines 2023-2031 sub AddIssue { Link Here
2023
                if C4::Context->preference('RealTimeHoldsQueue');
2029
                if C4::Context->preference('RealTimeHoldsQueue');
2024
2030
2025
            # Check quotas and record usage if needed
2031
            # Check quotas and record usage if needed
2026
            if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) {
2032
            my $quota;
2027
                # Update patron's used quota value
2033
            if ($selected_quota_id) {
2028
                $quota->add_usage({
2034
                $quota = Koha::Patron::Quotas->find($selected_quota_id);
2035
            } else {
2036
                $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber); 
2037
            }
2038
2039
            if ($quota) {
2040
              # Update patron's used quota value
2041
              $quota->add_usage({
2029
                    patron_id => $patron->patron_id, 
2042
                    patron_id => $patron->patron_id, 
2030
                    issue_id => $issue->issue_id,
2043
                    issue_id => $issue->issue_id,
2031
                });
2044
                });
Lines 3403-3412 sub CanBookBeRenewed { Link Here
3403
        }
3416
        }
3404
    }
3417
    }
3405
3418
3406
    # CHECK FOR QUOTAS  
3419
    # # CHECK FOR QUOTAS  
3407
    if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) {
3420
    if (my $quota_usage = Koha::Patron::Quota::Usages->find({ issue_id => $issue->issue_id })) {
3408
        unless ( $quota->has_available_quota ) {
3421
        
3409
            return ( 0, "QUOTA_EXCEEDED" );
3422
        # Get current active quota for the patron
3423
        if (my $active_quota = Koha::Patron::Quotas->get_active_quota($quota_usage->patron_id)) {
3424
            
3425
            if (!$active_quota->has_available_quota) {
3426
                return (0, "QUOTA_EXCEEDED");
3427
            }
3410
        }
3428
        }
3411
    }
3429
    }
3412
3430
Lines 3525-3536 sub AddRenewal { Link Here
3525
    my $circ_library = Koha::Libraries->find( _GetCircControlBranch( $item_object, $patron ) );
3543
    my $circ_library = Koha::Libraries->find( _GetCircControlBranch( $item_object, $patron ) );
3526
3544
3527
    # Check quotas and record usage if needed
3545
    # Check quotas and record usage if needed
3528
    if ( my $quota = Koha::Patron::Quotas->get_patron_quota($patron->borrowernumber) ) {
3546
    if (my $quota_usage = Koha::Patron::Quota::Usages->find({ issue_id => $issue->issue_id })) {
3529
        # Update patron's used quota value
3547
        # Get current active quota for the patron
3530
        $quota->add_usage({
3548
        if (my $active_quota = Koha::Patron::Quotas->get_active_quota($quota_usage->patron_id)) {
3531
            patron_id => $patron->patron_id, 
3549
            # Update patron's used quota value
3532
            issue_id => $issue->issue_id,
3550
            $active_quota->add_usage({
3533
        });
3551
                patron_id => $patron->patron_id,
3552
                issue_id  => $issue->issue_id,
3553
            });
3554
        }
3534
    }
3555
    }
3535
3556
3536
    my $schema = Koha::Database->schema;
3557
    my $schema = Koha::Database->schema;
(-)a/Koha/Patron/Quotas.pm (-24 / +56 lines)
Lines 1-9 Link Here
1
package Koha::Patron::Quotas;
1
package Koha::Patron::Quotas;
2
2
3
use base qw(Koha::Objects);
3
use Modern::Perl;
4
use Modern::Perl;
4
use Koha::Patron::Quota;
5
use Koha::Patron::Quota;
5
use Koha::Patrons;
6
use Koha::Patrons;
6
use base qw(Koha::Objects);
7
7
8
=head1 NAME
8
=head1 NAME
9
9
Lines 25-71 Searches for any applicable quota for the given patron. Returns: Link Here
25
=cut
25
=cut
26
26
27
sub get_patron_quota {
27
sub get_patron_quota {
28
    my ($self, $patron_id) = @_;
28
    my ( $self, $patron_id ) = @_;
29
    
29
30
    my $patron_quota = undef;
30
    my @available_quotas;
31
    my $first_found_quota = undef;
31
    my $first_found_quota = undef;
32
32
33
    # First check all guarantor quotas if enabled
33
    # First check patron's own quota
34
    if (C4::Context->preference('UseGuarantorQuota')) {
34
    my $patron_quota = $self->search(
35
        my $patron = Koha::Patrons->find($patron_id);
35
        {
36
            patron_id  => $patron_id,
37
            start_date => { '<=' => \'CURRENT_DATE' },
38
            end_date   => { '>=' => \'CURRENT_DATE' }
39
        }
40
    )->single;
41
42
    if ( $patron_quota && $patron_quota->has_available_quota ) {
43
        push @available_quotas, $patron_quota;
44
    }
45
    $first_found_quota ||= $patron_quota if $patron_quota;
46
47
    # Then check all guarantor quotas if enabled
48
    if ( C4::Context->preference('UseGuarantorQuota') ) {
49
        my $patron     = Koha::Patrons->find($patron_id);
36
        my @guarantors = $patron->guarantor_relationships->guarantors->as_list;
50
        my @guarantors = $patron->guarantor_relationships->guarantors->as_list;
37
51
38
        foreach my $guarantor (@guarantors) {
52
        foreach my $guarantor (@guarantors) {
39
            my $guarantor_quota = $self->search(
53
            my $guarantor_quota = $self->search(
40
                {
54
                {
41
                    patron_id => $guarantor->borrowernumber,
55
                    patron_id  => $guarantor->borrowernumber,
42
                    start_date => { '<=' => \'CURRENT_DATE' },
56
                    start_date => { '<=' => \'CURRENT_DATE' },
43
                    end_date   => { '>=' => \'CURRENT_DATE' }
57
                    end_date   => { '>=' => \'CURRENT_DATE' }
44
                }
58
                }
45
            )->single;
59
            )->single;
46
            
60
            
47
            if ($guarantor_quota) {
61
            if ($guarantor_quota) {
48
                # Return immediately if guarantor quota has availability
62
49
                if ($guarantor_quota->has_available_quota) {
50
                    return $guarantor_quota;
51
                }
52
                # Store first found quota in case we need it later
63
                # Store first found quota in case we need it later
53
                $first_found_quota ||= $guarantor_quota;
64
                $first_found_quota ||= $guarantor_quota;
65
66
                # Collect available guarantor quotas
67
                if ( $guarantor_quota->has_available_quota ) {
68
                    push @available_quotas, $guarantor_quota;
69
                }
54
            }
70
            }
55
        }
71
        }
56
    }
72
    }
57
73
58
    # Check patron's own quota if no available guarantor quota was found
74
    # Return single quota if only one available, array of quotas if multiple available,
59
    $patron_quota = $self->search(
75
    # first found quota if none available
60
        {
76
    return $available_quotas[0] if @available_quotas == 1;
61
            patron_id => $patron_id,
77
    return \@available_quotas   if @available_quotas > 1;
62
            start_date => { '<=' => \'CURRENT_DATE' },
78
    return $first_found_quota;
63
            end_date   => { '>=' => \'CURRENT_DATE' }
64
        }
65
    )->single;
66
67
    # Return patron quota if exists, otherwise first found guarantor quota
68
    return $patron_quota || $first_found_quota;
69
}
79
}
70
80
71
=head3 create_quota
81
=head3 create_quota
Lines 107-112 sub get_active_quotas { Link Here
107
    );
117
    );
108
}
118
}
109
119
120
=head2 get_active_quota
121
122
  my $active_quota = Koha::Patron::Quotas->get_active_quota($patron_id);
123
124
Returns the currently active quota for a patron if one exists.
125
Active means start_date <= NOW() and end_date >= NOW().
126
Returns undef if no active quota found.
127
128
=cut
129
130
sub get_active_quota {
131
    my ( $self, $patron_id ) = @_;
132
133
    return Koha::Patron::Quotas->search(
134
        {
135
            patron_id  => $patron_id,
136
            start_date => { '<=' => \'CURRENT_DATE' },
137
            end_date   => { '>=' => \'CURRENT_DATE' }
138
        }
139
    )->single;
140
}
141
110
=head2 Internal methods
142
=head2 Internal methods
111
143
112
=head3 _type
144
=head3 _type
Lines 119-125 sub _type { Link Here
119
151
120
=head3 object_class
152
=head3 object_class
121
153
122
Returns the package name for patron quota objects
154
Returns the package name for koha patron quota objects
123
155
124
=cut
156
=cut
125
157
(-)a/circ/circulation.pl (-1 / +3 lines)
Lines 187-192 if ( $restoreduedatespec && $restoreduedatespec eq "highholds_empty" ) { Link Here
187
my $issueconfirmed = $query->param('issueconfirmed');
187
my $issueconfirmed = $query->param('issueconfirmed');
188
my $cancelreserve  = $query->param('cancelreserve');
188
my $cancelreserve  = $query->param('cancelreserve');
189
my $cancel_recall  = $query->param('cancel_recall');
189
my $cancel_recall  = $query->param('cancel_recall');
190
my $selected_quota_id = $query->param('selected_quota_id');
190
my $recall_id      = $query->param('recall_id');
191
my $recall_id      = $query->param('recall_id');
191
my $debt_confirmed = $query->param('debt_confirmed') || 0;     # Don't show the debt error dialog twice
192
my $debt_confirmed = $query->param('debt_confirmed') || 0;     # Don't show the debt error dialog twice
192
my $charges        = $query->param('charges')        || q{};
193
my $charges        = $query->param('charges')        || q{};
Lines 559-565 if ( @$barcodes && $op eq 'cud-checkout' ) { Link Here
559
                        cancel_recall          => $cancel_recall,
560
                        cancel_recall          => $cancel_recall,
560
                        recall_id              => $recall_id,
561
                        recall_id              => $recall_id,
561
                        confirmations          => [ grep { /^[A-Z_]+$/ } keys %{$needsconfirmation} ],
562
                        confirmations          => [ grep { /^[A-Z_]+$/ } keys %{$needsconfirmation} ],
562
                        forced                 => [ keys %{$issuingimpossible} ]
563
                        forced                 => [ keys %{$issuingimpossible} ],
564
                        selected_quota_id      => $selected_quota_id
563
                    }
565
                    }
564
                );
566
                );
565
                $template_params->{issue} = $issue;
567
                $template_params->{issue} = $issue;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt (-3 / +21 lines)
Lines 157-163 Link Here
157
157
158
                [%IF ( QUOTA_EXCEEDED ) %]
158
                [%IF ( QUOTA_EXCEEDED ) %]
159
                    <li class="needsconfirm age_restriction">
159
                    <li class="needsconfirm age_restriction">
160
                        Quota Exceeded [% QUOTA_EXCEEDED | html %].
160
                        Quota Exceeded. Available: [% QUOTA_EXCEEDED.available | html %] / [% QUOTA_EXCEEDED.total | html %].
161
                        [% IF CAN_user_circulate_force_checkout %]
161
                        [% IF CAN_user_circulate_force_checkout %]
162
                            Check out anyway?
162
                            Check out anyway?
163
                        [% END %]
163
                        [% END %]
Lines 401-406 Link Here
401
                            [% END %]
401
                            [% END %]
402
                        [% END %]
402
                        [% END %]
403
403
404
                        [% IF ( QUOTA_SELECT ) %]
405
                            <p>
406
                                <label for="selected_quota_id">Select quota to use:</label>
407
                                <select name="selected_quota_id" id="selected_quota_id" required>
408
                                    <option value="">Select a quota</option>
409
                                    [% FOREACH quota IN QUOTA_SELECT %]
410
                                        <option value="[% quota.id | html %]">
411
                                            [% IF quota.patron_id != patron.borrowernumber %]
412
                                                Guarantor ([% INCLUDE 'patron-title.inc' patron = quota.patron %]) -
413
                                            [% ELSE %]
414
                                                This patron ([% INCLUDE 'patron-title.inc' patron = quota.patron %]) -
415
                                            [% END %]
416
                                            Available: [% quota.available_quota | html %] / [% quota.allocation | html %]
417
                                        </option>
418
                                    [% END %]
419
                                </select>
420
                            </p>
421
                        [% END %]
422
404
                        <input type="hidden" name="barcode" value="[% barcode | html %]" />
423
                        <input type="hidden" name="barcode" value="[% barcode | html %]" />
405
                        <input type="hidden" name="borrowernumber" value="[% patron.borrowernumber | html %]" />
424
                        <input type="hidden" name="borrowernumber" value="[% patron.borrowernumber | html %]" />
406
                        <input type="hidden" name="issueconfirmed" value="1" />
425
                        <input type="hidden" name="issueconfirmed" value="1" />
Lines 662-668 Link Here
662
                [% END %]
681
                [% END %]
663
682
664
                [%IF ( QUOTA_EXCEEDED ) %]
683
                [%IF ( QUOTA_EXCEEDED ) %]
665
                    <li>Quota Exceeded [% QUOTA_EXCEEDED | html %].</li>
684
                    <li>Quota Exceeded. Available: [% QUOTA_EXCEEDED.available | html %] / [% QUOTA_EXCEEDED.total | html %].</li>
666
                [% END %]
685
                [% END %]
667
686
668
                [% IF ( EXPIRED ) %]
687
                [% IF ( EXPIRED ) %]
669
- 

Return to bug 38924