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

(-)a/Koha/CirculationRules.pm (-3 / +26 lines)
Lines 216-221 our $RULE_KINDS = { Link Here
216
    holds_pickup_period => {
216
    holds_pickup_period => {
217
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
217
        scope => [ 'branchcode', 'categorycode', 'itemtype' ],
218
    },
218
    },
219
    has_priority => {
220
        scope => [ 'branchcode', 'categorycode' ],
221
    },
219
    # Not included (deprecated?):
222
    # Not included (deprecated?):
220
    #   * accountsent
223
    #   * accountsent
221
    #   * reservecharge
224
    #   * reservecharge
Lines 248-253 sub get_effective_rule { Link Here
248
    $params->{categorycode} //= undef;
251
    $params->{categorycode} //= undef;
249
    $params->{branchcode}   //= undef;
252
    $params->{branchcode}   //= undef;
250
    $params->{itemtype}     //= undef;
253
    $params->{itemtype}     //= undef;
254
    $params->{has_priority} //= undef;
251
255
252
    my $rule_name    = $params->{rule_name};
256
    my $rule_name    = $params->{rule_name};
253
    my $categorycode = $params->{categorycode};
257
    my $categorycode = $params->{categorycode};
Lines 280-286 sub get_effective_rule { Link Here
280
        }
284
        }
281
    )->single;
285
    )->single;
282
286
283
    return $rule;
287
    $search_params->{has_priority} = 1;
288
289
    my $priority_rule = $self->search(
290
        $search_params,
291
        {
292
            order_by => $order_by,
293
            rows => 1,
294
        }
295
    )->single;
296
297
    return defined $priority_rule ? $priority_rule : $rule;
284
}
298
}
285
299
286
=head3 get_effective_rule_value
300
=head3 get_effective_rule_value
Lines 308-317 sub get_effective_rule_value { Link Here
308
    my $categorycode = $params->{categorycode};
322
    my $categorycode = $params->{categorycode};
309
    my $itemtype     = $params->{itemtype};
323
    my $itemtype     = $params->{itemtype};
310
    my $branchcode   = $params->{branchcode};
324
    my $branchcode   = $params->{branchcode};
325
    my $has_priority = $params->{has_priority};
311
326
312
    my $memory_cache = Koha::Cache::Memory::Lite->get_instance;
327
    my $memory_cache = Koha::Cache::Memory::Lite->get_instance;
313
    my $cache_key = sprintf "CircRules:%s:%s:%s:%s", $rule_name // q{},
328
    my $cache_key = sprintf "CircRules:%s:%s:%s:%s", $rule_name // q{},
314
      $categorycode // q{}, $branchcode // q{}, $itemtype // q{};
329
      $categorycode // q{}, $branchcode // q{}, $itemtype // q{} ,$has_priority // q{};
315
330
316
    my $cached       = $memory_cache->get_from_cache($cache_key);
331
    my $cached       = $memory_cache->get_from_cache($cache_key);
317
    return $cached if $cached;
332
    return $cached if $cached;
Lines 334-339 sub get_effective_rules { Link Here
334
    my $categorycode = $params->{categorycode};
349
    my $categorycode = $params->{categorycode};
335
    my $itemtype     = $params->{itemtype};
350
    my $itemtype     = $params->{itemtype};
336
    my $branchcode   = $params->{branchcode};
351
    my $branchcode   = $params->{branchcode};
352
    my $has_priority = $params->{has_priority};
337
353
338
    my $r;
354
    my $r;
339
    foreach my $rule (@$rules) {
355
    foreach my $rule (@$rules) {
Lines 343-348 sub get_effective_rules { Link Here
343
                categorycode => $categorycode,
359
                categorycode => $categorycode,
344
                itemtype     => $itemtype,
360
                itemtype     => $itemtype,
345
                branchcode   => $branchcode,
361
                branchcode   => $branchcode,
362
                has_priority => $has_priority,
346
            }
363
            }
347
        );
364
        );
348
365
Lines 386-391 sub set_rule { Link Here
386
    my $itemtype     = $params->{itemtype};
403
    my $itemtype     = $params->{itemtype};
387
    my $rule_name    = $params->{rule_name};
404
    my $rule_name    = $params->{rule_name};
388
    my $rule_value   = $params->{rule_value};
405
    my $rule_value   = $params->{rule_value};
406
    my $has_priority = $params->{has_priority};
407
389
    my $can_be_blank = defined $kind_info->{can_be_blank} ? $kind_info->{can_be_blank} : 1;
408
    my $can_be_blank = defined $kind_info->{can_be_blank} ? $kind_info->{can_be_blank} : 1;
390
    $rule_value = undef if defined $rule_value && $rule_value eq "" && !$can_be_blank;
409
    $rule_value = undef if defined $rule_value && $rule_value eq "" && !$can_be_blank;
391
    my $is_monetary = defined $kind_info->{is_monetary} ? $kind_info->{is_monetary} : 0;
410
    my $is_monetary = defined $kind_info->{is_monetary} ? $kind_info->{is_monetary} : 0;
Lines 401-406 sub set_rule { Link Here
401
            branchcode   => $branchcode,
420
            branchcode   => $branchcode,
402
            categorycode => $categorycode,
421
            categorycode => $categorycode,
403
            itemtype     => $itemtype,
422
            itemtype     => $itemtype,
423
            has_priority => $has_priority
404
        }
424
        }
405
    )->next();
425
    )->next();
406
426
Lines 422-427 sub set_rule { Link Here
422
                    itemtype     => $itemtype,
442
                    itemtype     => $itemtype,
423
                    rule_name    => $rule_name,
443
                    rule_name    => $rule_name,
424
                    rule_value   => $rule_value,
444
                    rule_value   => $rule_value,
445
                    has_priority => $has_priority,
425
                }
446
                }
426
            );
447
            );
427
            $rule->store();
448
            $rule->store();
Lines 447-453 sub set_rules { Link Here
447
    $set_params{branchcode} = $params->{branchcode} if exists $params->{branchcode};
468
    $set_params{branchcode} = $params->{branchcode} if exists $params->{branchcode};
448
    $set_params{categorycode} = $params->{categorycode} if exists $params->{categorycode};
469
    $set_params{categorycode} = $params->{categorycode} if exists $params->{categorycode};
449
    $set_params{itemtype} = $params->{itemtype} if exists $params->{itemtype};
470
    $set_params{itemtype} = $params->{itemtype} if exists $params->{itemtype};
450
    my $rules        = $params->{rules};
471
    $set_params{has_priority} = $params->{has_priority} if exists $params->{has_priority};
472
    my $rules = $params->{rules};
473
451
474
452
    my $rule_objects = [];
475
    my $rule_objects = [];
453
    while ( my ( $rule_name, $rule_value ) = each %$rules ) {
476
    while ( my ( $rule_name, $rule_value ) = each %$rules ) {
(-)a/Koha/Template/Plugin/CirculationRules.pm (+2 lines)
Lines 76-81 sub Search { Link Here
76
    $branchcode   = undef if $branchcode eq q{}   or $branchcode eq q{*};
76
    $branchcode   = undef if $branchcode eq q{}   or $branchcode eq q{*};
77
    $categorycode = undef if $categorycode eq q{} or $categorycode eq q{*};
77
    $categorycode = undef if $categorycode eq q{} or $categorycode eq q{*};
78
    $itemtype     = undef if $itemtype eq q{}     or $itemtype eq q{*};
78
    $itemtype     = undef if $itemtype eq q{}     or $itemtype eq q{*};
79
    my $has_priority = $params->{has_priority} // undef;
79
80
80
    my $rule = Koha::CirculationRules->search(
81
    my $rule = Koha::CirculationRules->search(
81
        {
82
        {
Lines 83-88 sub Search { Link Here
83
            categorycode => $categorycode,
84
            categorycode => $categorycode,
84
            itemtype     => $itemtype,
85
            itemtype     => $itemtype,
85
            rule_name    => $rule_name,
86
            rule_name    => $rule_name,
87
            has_priority => $has_priority
86
        }
88
        }
87
    )->next;
89
    )->next;
88
90
(-)a/admin/smart-rules.pl (-1 / +39 lines)
Lines 721-726 elsif ( $op eq 'cud-mod-refund-lost-item-fee-rule' ) { Link Here
721
            rules        => { waiting_hold_cancellation => undef },
721
            rules        => { waiting_hold_cancellation => undef },
722
        }
722
        }
723
    );
723
    );
724
} elsif ( $op eq 'cud-set-global-checkouts-limit' ) {
725
726
    my $categorycode  = $input->param('categorycode');
727
    my $itemtype  = $input->param('itemtype');
728
    my $maxissueqty = scalar $input->param('maxissueqty');
729
    my $maxonsiteissueqty = scalar $input->param('maxonsiteissueqty');
730
731
    my %checkout_rules;
732
    $checkout_rules{'maxissueqty'} = strip_non_numeric($maxissueqty);
733
    $checkout_rules{'maxonsiteissueqty'} = strip_non_numeric($maxonsiteissueqty);
734
735
    while (my ($rule_name, $rule_value) = each(%checkout_rules)) {
736
        if(defined $rule_value && $rule_value ne '') {
737
            Koha::CirculationRules->set_rule(
738
            {   categorycode => ( $categorycode eq '*' ) ? undef : $categorycode,
739
                itemtype => ( $itemtype eq '*' ) ? undef : $itemtype,
740
                branchcode   => undef,
741
                has_priority => 1,
742
                rule_name        => $rule_name,
743
                rule_value => $rule_value
744
            });
745
        }
746
    }
747
} elsif ( $op eq 'cud-delete-global-checkouts-limit' ) {
748
    my $categorycode  = $input->param('categorycode');
749
    my $itemtype  = $input->param('itemtype');
750
751
    Koha::CirculationRules->set_rules(
752
        {   categorycode => ( $categorycode eq '*' ) ? undef : $categorycode,
753
            itemtype => ( $itemtype eq '*' ) ? undef : $itemtype,
754
            branchcode   => undef,
755
            has_priority => 1,
756
            rules        => {
757
                maxissueqty       => undef,
758
                maxonsiteissueqty => undef,
759
            },
760
        }
761
    );
724
}
762
}
725
763
726
764
Lines 748-754 my @used_itemtypes = Link Here
748
    Koha::CirculationRules->search( { branchcode => $humanbranch }, { columns => ['itemtype'], distinct => 1, } )
786
    Koha::CirculationRules->search( { branchcode => $humanbranch }, { columns => ['itemtype'], distinct => 1, } )
749
    ->get_column('itemtype');
787
    ->get_column('itemtype');
750
788
751
my $all_rules = Koha::CirculationRules->search({ branchcode => $humanbranch });
789
my $all_rules = Koha::CirculationRules->search({ branchcode => $humanbranch, has_priority => undef });
752
my $definedbranch = $all_rules->count ? 1 : 0;
790
my $definedbranch = $all_rules->count ? 1 : 0;
753
791
754
my $rules = {};
792
my $rules = {};
(-)a/installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl (+13 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number  => "8137",
5
    description => "Add column has_priority",
6
    up          => sub {
7
        my ($args) = @_;
8
        my ( $dbh, $out ) = @$args{qw(dbh out)};
9
10
        $dbh->do('ALTER TABLE circulation_rules ADD IF NOT EXISTS has_priority INT(1) DEFAULT 0');
11
        say $out "Added column 'has_priority'";
12
    },
13
};
(-)a/installer/data/mysql/kohastructure.sql (+1 lines)
Lines 1863-1868 CREATE TABLE `circulation_rules` ( Link Here
1863
  `itemtype` varchar(10) DEFAULT NULL,
1863
  `itemtype` varchar(10) DEFAULT NULL,
1864
  `rule_name` varchar(32) NOT NULL,
1864
  `rule_name` varchar(32) NOT NULL,
1865
  `rule_value` varchar(32) NOT NULL,
1865
  `rule_value` varchar(32) NOT NULL,
1866
  `has_priority` tinyint(4) DEFAULT NULL,
1866
  PRIMARY KEY (`id`),
1867
  PRIMARY KEY (`id`),
1867
  UNIQUE KEY `branchcode` (`branchcode`,`categorycode`,`itemtype`,`rule_name`),
1868
  UNIQUE KEY `branchcode` (`branchcode`,`categorycode`,`itemtype`,`rule_name`),
1868
  KEY `circ_rules_ibfk_2` (`categorycode`),
1869
  KEY `circ_rules_ibfk_2` (`categorycode`),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-1 / +124 lines)
Lines 71-76 Link Here
71
                    or the specific rule's type, whichever is less.</p>
71
                    or the specific rule's type, whichever is less.</p>
72
                    <p>To modify a rule, create a new one with the same patron category and item type.</p>
72
                    <p>To modify a rule, create a new one with the same patron category and item type.</p>
73
                    <p>The circulation and fine rules are applied based on the CircControl system preference which is set to <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=CircControl">[% Koha.Preference('CircControl') | html %]</a> and the HomeOrHoldingBranch system preference which is set to <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=HomeOrHoldingBranch">[% Koha.Preference('HomeOrHoldingBranch') | html %]</a>.</p>
73
                    <p>The circulation and fine rules are applied based on the CircControl system preference which is set to <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=CircControl">[% Koha.Preference('CircControl') | html %]</a> and the HomeOrHoldingBranch system preference which is set to <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=HomeOrHoldingBranch">[% Koha.Preference('HomeOrHoldingBranch') | html %]</a>.</p>
74
                    <p>The “Global checkout limits” section is designed to create a limit for all librairies, thus preventing checkouts accumulation.</p>
74
                </div>
75
                </div>
75
76
76
                <div class="page-section">
77
                <div class="page-section">
Lines 884-889 Link Here
884
                </div>
885
                </div>
885
                [% END %]
886
                [% END %]
886
887
888
                <div id="global_checkouts_limit" class="page-section">
889
                    <h2>Global checkout limits</h2>
890
                    <p>Specify checkout limits for all librairies.</p>
891
                    <form id="set-global-checkouts-limit" method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
892
                        [% INCLUDE 'csrf-token.inc' %]
893
                        <input type="hidden" name="op" value="cud-set-global-checkouts-limit" />
894
                        <table>
895
                            <thead>
896
                                <tr>
897
                                    <th class="fixed_sort">Patron category</th>
898
                                    <th class="fixed_sort">Item type</th>
899
                                    <th class="noExport restricted-access">Actions</th>
900
                                    <th>Current checkouts allowed</th>
901
                                    <th>Current on-site checkouts allowed</th>
902
                                </tr>
903
                            </thead>
904
                            <tbody>
905
                            [% FOREACH c IN categorycodes %]
906
                                [% SET c = '' UNLESS c.defined %]
907
                                [% FOREACH i IN itemtypes %]
908
                                    [% SET i = '' UNLESS i.defined %]
909
                                    [% SET maxissueqty = CirculationRules.Search( '', c, i, 'maxissueqty', { want_rule => 1, has_priority => 1 } ) %]
910
                                    [% SET maxonsiteissueqty = CirculationRules.Search( '', c, i, 'maxonsiteissueqty', { want_rule => 1, has_priority => 1 } ) %]
911
                                    [% SET show_rule = maxissueqty || maxonsiteissueqty %]
912
                                    [% IF show_rule %]
913
                                        <tr>
914
                                            <td data-code="[% c | html %]">
915
                                                [% IF c == undef %]
916
                                                    <em>All</em>
917
                                                [% ELSE %]
918
                                                    [% Categories.GetName(c) | html %]
919
                                                [% END %]
920
                                            </td>
921
                                            <td data-code="[% i | html %]">
922
                                                [% IF i == undef %]
923
                                                    <em>All</em>
924
                                                [% ELSE %]
925
                                                    [% ItemTypes.GetDescription(i,1) | html %]
926
                                                [% END %]
927
                                            </td>
928
                                            <td class="actions restricted-access">
929
                                                <a href="#" class="editrule btn btn-default btn-xs"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a>
930
                                                <a href="#" class="delete-global-checkout-limits btn btn-default btn-xs" data-itemtype="[% i || '*' | html %]" data-categorycode="[% c || '*' | html %]" data-branch="*"><i class="fa fa-trash-can"></i> Delete</a>
931
                                            </td>
932
                                            <td>
933
                                                [% IF maxissueqty.rule_value && maxissueqty.rule_value != '' %]
934
                                                    [% maxissueqty.rule_value | html %]
935
                                                [% ELSE %]
936
                                                    <span>Not defined</span>
937
                                                [% END %]
938
                                            </td>
939
                                            <td>
940
                                                [% IF maxonsiteissueqty.rule_value && maxonsiteissueqty.rule_value != ''  %]
941
                                                    [% maxonsiteissueqty.rule_value | html %]
942
                                                [% ELSE %]
943
                                                    <span>Not defined</span>
944
                                                [% END %]
945
                                            </td>
946
                                        </tr>
947
                                    [% END %]
948
                                [% END %]
949
                            [% END %]
950
                            <tr class="noExport restricted-access" id="edit_row">
951
                                <td>
952
                                    <select name="categorycode" id="categorycode">
953
                                        <option value="*">All</option>
954
                                    [% FOREACH patron_category IN patron_categories%]
955
                                        <option value="[% patron_category.categorycode | html %]">[% patron_category.description | html %]</option>
956
                                    [% END %]
957
                                    </select>
958
                                </td>
959
                                <td>
960
                                    <select name="itemtype" id="matrixitemtype" style="width:13em;">
961
                                        <option value="*">All</option>
962
                                        [% FOREACH itemtypeloo IN itemtypeloop %]
963
                                            [% NEXT IF itemtypeloo.parent_type %]
964
                                            [% SET children = itemtypeloo.children_with_localization %]
965
                                            [% IF children.count %]
966
                                                <optgroup label="[% itemtypeloo.translated_description | html %]">
967
                                                    <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %] (All)</option>
968
                                                    [% FOREACH child IN children %]
969
                                                        <option value="[% child.itemtype | html %]">[% child.translated_description | html %]</option>
970
                                                    [% END %]
971
                                                </optgroup>
972
                                            [% ELSE %]
973
                                                <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %]</option>
974
                                            [% END %]
975
                                        [% END %]
976
                                    </select>
977
                                </td>
978
                                <td class="actions">
979
                                    <button type="submit" class="btn btn-primary btn-xs"><i class="fa fa-save"></i> Save</button>
980
                                    <button name="cancel" class="clear_edit btn btn-default btn-xs"><i class="fa fa-undo"></i> Clear</button>
981
                                </td>
982
                                <td><input type="text" name="maxissueqty" id="maxissueqty" size="3" /></td>
983
                                <td><input type="text" name="maxonsiteissueqty" id="maxonsiteissueqty" size="3" /></td>
984
                            </tr>
985
                            </tbody>
986
                        </table>
987
                    </form>
988
                </div>
989
887
                <div id="waiting-hold-cancel-category" class="page-section">
990
                <div id="waiting-hold-cancel-category" class="page-section">
888
                [% IF humanbranch %]
991
                [% IF humanbranch %]
889
                    <h2>Waiting hold cancellation policy for [% Branches.GetName( humanbranch ) | html %]</h2>
992
                    <h2>Waiting hold cancellation policy for [% Branches.GetName( humanbranch ) | html %]</h2>
Lines 1678-1683 Link Here
1678
                return f.submit();
1781
                return f.submit();
1679
            });
1782
            });
1680
1783
1784
            $(".delete-global-checkout-limits").on("click", function(e){
1785
                e.preventDefault();
1786
                if ( !confirmDelete(MSG_CONFIRM_DELETE) ) {
1787
                    return false;
1788
                }
1789
                let f = $("#delete_form");
1790
                f.find("[name='op']").val('cud-delete-global-checkouts-limit');
1791
                f.find("[name='itemtype']").val($(this).data('itemtype'));
1792
                f.find("[name='categorycode']").val($(this).data('categorycode'));
1793
                f.find("[name='branch']").val($(this).data('branch'));
1794
                return f.submit();
1795
            });
1796
1797
            if($("#branch").val() != '*') {
1798
                var rowCount = $("#default-circulation-rules tbody tr").length;
1799
                if(rowCount == 1){
1800
                    $("#global_checkouts_limit").remove();
1801
                } else {
1802
	                $("#global_checkouts_limit .restricted-access").remove();
1803
                }
1804
	        }
1681
        });
1805
        });
1682
    </script>
1806
    </script>
1683
[% END %]
1807
[% END %]
1684
- 

Return to bug 8137