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

(-)a/Koha/CirculationRules.pm (-4 / +25 lines)
Lines 227-233 our $RULE_KINDS = { Link Here
227
    bookings_trail_period => {
227
    bookings_trail_period => {
228
        scope => [ 'branchcode', 'itemtype' ],
228
        scope => [ 'branchcode', 'itemtype' ],
229
    },
229
    },
230
230
    has_priority => {
231
        scope => [ 'branchcode', 'categorycode' ],
232
    },
231
    # Not included (deprecated?):
233
    # Not included (deprecated?):
232
    #   * accountsent
234
    #   * accountsent
233
    #   * reservecharge
235
    #   * reservecharge
Lines 260-265 sub get_effective_rule { Link Here
260
    $params->{categorycode} //= undef;
262
    $params->{categorycode} //= undef;
261
    $params->{branchcode}   //= undef;
263
    $params->{branchcode}   //= undef;
262
    $params->{itemtype}     //= undef;
264
    $params->{itemtype}     //= undef;
265
    $params->{has_priority} //= undef;
263
266
264
    my $rule_name    = $params->{rule_name};
267
    my $rule_name    = $params->{rule_name};
265
    my $categorycode = $params->{categorycode};
268
    my $categorycode = $params->{categorycode};
Lines 290-296 sub get_effective_rule { Link Here
290
        }
293
        }
291
    )->single;
294
    )->single;
292
295
293
    return $rule;
296
    $search_params->{has_priority} = 1;
297
298
    my $priority_rule = $self->search(
299
        $search_params,
300
        {
301
            order_by => $order_by,
302
            rows => 1,
303
        }
304
    )->single;
305
306
    return defined $priority_rule ? $priority_rule : $rule;
294
}
307
}
295
308
296
=head3 get_effective_rule_value
309
=head3 get_effective_rule_value
Lines 318-327 sub get_effective_rule_value { Link Here
318
    my $categorycode = $params->{categorycode};
331
    my $categorycode = $params->{categorycode};
319
    my $itemtype     = $params->{itemtype};
332
    my $itemtype     = $params->{itemtype};
320
    my $branchcode   = $params->{branchcode};
333
    my $branchcode   = $params->{branchcode};
334
    my $has_priority = $params->{has_priority};
321
335
322
    my $memory_cache = Koha::Cache::Memory::Lite->get_instance;
336
    my $memory_cache = Koha::Cache::Memory::Lite->get_instance;
323
    my $cache_key    = sprintf "CircRules:%s:%s:%s:%s", $rule_name // q{},
337
    my $cache_key = sprintf "CircRules:%s:%s:%s:%s", $rule_name // q{},
324
        $categorycode // q{}, $branchcode // q{}, $itemtype // q{};
338
      $categorycode // q{}, $branchcode // q{}, $itemtype // q{} ,$has_priority // q{};
325
339
326
    my $cached = $memory_cache->get_from_cache($cache_key);
340
    my $cached = $memory_cache->get_from_cache($cache_key);
327
    return $cached if $cached;
341
    return $cached if $cached;
Lines 344-349 sub get_effective_rules { Link Here
344
    my $categorycode = $params->{categorycode};
358
    my $categorycode = $params->{categorycode};
345
    my $itemtype     = $params->{itemtype};
359
    my $itemtype     = $params->{itemtype};
346
    my $branchcode   = $params->{branchcode};
360
    my $branchcode   = $params->{branchcode};
361
    my $has_priority = $params->{has_priority};
347
362
348
    my $r;
363
    my $r;
349
    foreach my $rule (@$rules) {
364
    foreach my $rule (@$rules) {
Lines 353-358 sub get_effective_rules { Link Here
353
                categorycode => $categorycode,
368
                categorycode => $categorycode,
354
                itemtype     => $itemtype,
369
                itemtype     => $itemtype,
355
                branchcode   => $branchcode,
370
                branchcode   => $branchcode,
371
                has_priority => $has_priority,
356
            }
372
            }
357
        );
373
        );
358
374
Lines 394-399 sub set_rule { Link Here
394
    my $itemtype     = $params->{itemtype};
410
    my $itemtype     = $params->{itemtype};
395
    my $rule_name    = $params->{rule_name};
411
    my $rule_name    = $params->{rule_name};
396
    my $rule_value   = $params->{rule_value};
412
    my $rule_value   = $params->{rule_value};
413
    my $has_priority = $params->{has_priority};
414
397
    my $can_be_blank = defined $kind_info->{can_be_blank} ? $kind_info->{can_be_blank} : 1;
415
    my $can_be_blank = defined $kind_info->{can_be_blank} ? $kind_info->{can_be_blank} : 1;
398
    $rule_value = undef if defined $rule_value && $rule_value eq "" && !$can_be_blank;
416
    $rule_value = undef if defined $rule_value && $rule_value eq "" && !$can_be_blank;
399
    my $is_monetary = defined $kind_info->{is_monetary} ? $kind_info->{is_monetary} : 0;
417
    my $is_monetary = defined $kind_info->{is_monetary} ? $kind_info->{is_monetary} : 0;
Lines 409-414 sub set_rule { Link Here
409
            branchcode   => $branchcode,
427
            branchcode   => $branchcode,
410
            categorycode => $categorycode,
428
            categorycode => $categorycode,
411
            itemtype     => $itemtype,
429
            itemtype     => $itemtype,
430
            has_priority => $has_priority
412
        }
431
        }
413
    )->next();
432
    )->next();
414
433
Lines 429-434 sub set_rule { Link Here
429
                    itemtype     => $itemtype,
448
                    itemtype     => $itemtype,
430
                    rule_name    => $rule_name,
449
                    rule_name    => $rule_name,
431
                    rule_value   => $rule_value,
450
                    rule_value   => $rule_value,
451
                    has_priority => $has_priority,
432
                }
452
                }
433
            );
453
            );
434
            $rule->store();
454
            $rule->store();
Lines 458-463 sub set_rules { Link Here
458
    $set_params{branchcode}   = $params->{branchcode}   if exists $params->{branchcode};
478
    $set_params{branchcode}   = $params->{branchcode}   if exists $params->{branchcode};
459
    $set_params{categorycode} = $params->{categorycode} if exists $params->{categorycode};
479
    $set_params{categorycode} = $params->{categorycode} if exists $params->{categorycode};
460
    $set_params{itemtype}     = $params->{itemtype}     if exists $params->{itemtype};
480
    $set_params{itemtype}     = $params->{itemtype}     if exists $params->{itemtype};
481
    $set_params{has_priority} = $params->{has_priority} if exists $params->{has_priority};
461
    my $rules = $params->{rules};
482
    my $rules = $params->{rules};
462
483
463
    my $rule_objects = [];
484
    my $rule_objects = [];
(-)a/Koha/Schema/Result/CirculationRule.pm (-2 / +9 lines)
Lines 62-67 __PACKAGE__->table("circulation_rules"); Link Here
62
  is_nullable: 0
62
  is_nullable: 0
63
  size: 32
63
  size: 32
64
64
65
=head2 has_priority
66
67
  data_type: 'tinyint'
68
  is_nullable: 1
69
65
=cut
70
=cut
66
71
67
__PACKAGE__->add_columns(
72
__PACKAGE__->add_columns(
Lines 77-82 __PACKAGE__->add_columns( Link Here
77
  { data_type => "varchar", is_nullable => 0, size => 32 },
82
  { data_type => "varchar", is_nullable => 0, size => 32 },
78
  "rule_value",
83
  "rule_value",
79
  { data_type => "varchar", is_nullable => 0, size => 32 },
84
  { data_type => "varchar", is_nullable => 0, size => 32 },
85
  "has_priority",
86
  { data_type => "tinyint", is_nullable => 1 },
80
);
87
);
81
88
82
=head1 PRIMARY KEY
89
=head1 PRIMARY KEY
Lines 177-184 __PACKAGE__->belongs_to( Link Here
177
);
184
);
178
185
179
186
180
# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-10-05 14:29:17
187
# Created by DBIx::Class::Schema::Loader v0.07051 @ 2024-12-20 12:51:01
181
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:QHMqvrtX0ohJe70PHUYZ0Q
188
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:P5S9o9p6aJ38EOkLQQOW0Q
182
189
183
=head2 koha_objects_class
190
=head2 koha_objects_class
184
191
(-)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 755-760 elsif ( $op eq 'cud-add' ) { Link Here
755
            rules        => { waiting_hold_cancellation => undef },
755
            rules        => { waiting_hold_cancellation => undef },
756
        }
756
        }
757
    );
757
    );
758
} elsif ( $op eq 'cud-set-global-checkout-limits' ) {
759
760
    my $categorycode  = $input->param('categorycode');
761
    my $itemtype  = $input->param('itemtype');
762
    my $maxissueqty = scalar $input->param('maxissueqty');
763
    my $maxonsiteissueqty = scalar $input->param('maxonsiteissueqty');
764
765
    my %checkout_rules;
766
    $checkout_rules{'maxissueqty'} = strip_non_numeric($maxissueqty);
767
    $checkout_rules{'maxonsiteissueqty'} = strip_non_numeric($maxonsiteissueqty);
768
769
    while (my ($rule_name, $rule_value) = each(%checkout_rules)) {
770
        if(defined $rule_value && $rule_value ne '') {
771
            Koha::CirculationRules->set_rule(
772
            {   categorycode => ( $categorycode eq '*' ) ? undef : $categorycode,
773
                itemtype => ( $itemtype eq '*' ) ? undef : $itemtype,
774
                branchcode   => undef,
775
                has_priority => 1,
776
                rule_name        => $rule_name,
777
                rule_value => $rule_value
778
            });
779
        }
780
    }
781
} elsif ( $op eq 'cud-delete-global-checkout-limits' ) {
782
    my $categorycode  = $input->param('categorycode');
783
    my $itemtype  = $input->param('itemtype');
784
785
    Koha::CirculationRules->set_rules(
786
        {   categorycode => ( $categorycode eq '*' ) ? undef : $categorycode,
787
            itemtype => ( $itemtype eq '*' ) ? undef : $itemtype,
788
            branchcode   => undef,
789
            has_priority => 1,
790
            rules        => {
791
                maxissueqty       => undef,
792
                maxonsiteissueqty => undef,
793
            },
794
        }
795
    );
758
}
796
}
759
797
760
my $refundLostItemFeeRule =
798
my $refundLostItemFeeRule =
Lines 783-789 my @used_itemtypes = Link Here
783
    Koha::CirculationRules->search( { branchcode => $humanbranch }, { columns => ['itemtype'], distinct => 1, } )
821
    Koha::CirculationRules->search( { branchcode => $humanbranch }, { columns => ['itemtype'], distinct => 1, } )
784
    ->get_column('itemtype');
822
    ->get_column('itemtype');
785
823
786
my $all_rules     = Koha::CirculationRules->search( { branchcode => $humanbranch } );
824
my $all_rules = Koha::CirculationRules->search({ branchcode => $humanbranch, has_priority => undef });
787
my $definedbranch = $all_rules->count ? 1 : 0;
825
my $definedbranch = $all_rules->count ? 1 : 0;
788
826
789
my $rules = {};
827
my $rules = {};
(-)a/installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl (+15 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
        if ( !column_exists( 'circulation_rules', 'has_priority' ) ) {
11
            $dbh->do('ALTER TABLE circulation_rules ADD IF NOT EXISTS has_priority TINYINT(1) DEFAULT NULL');
12
            say $out "Added column 'circulation_rules.has_priority'";
13
        }
14
    },
15
};
(-)a/installer/data/mysql/kohastructure.sql (+1 lines)
Lines 1878-1883 CREATE TABLE `circulation_rules` ( Link Here
1878
  `itemtype` varchar(10) DEFAULT NULL,
1878
  `itemtype` varchar(10) DEFAULT NULL,
1879
  `rule_name` varchar(32) NOT NULL,
1879
  `rule_name` varchar(32) NOT NULL,
1880
  `rule_value` varchar(32) NOT NULL,
1880
  `rule_value` varchar(32) NOT NULL,
1881
  `has_priority` tinyint(1) DEFAULT NULL,
1881
  PRIMARY KEY (`id`),
1882
  PRIMARY KEY (`id`),
1882
  UNIQUE KEY `branchcode` (`branchcode`,`categorycode`,`itemtype`,`rule_name`),
1883
  UNIQUE KEY `branchcode` (`branchcode`,`categorycode`,`itemtype`,`rule_name`),
1883
  KEY `circ_rules_ibfk_2` (`categorycode`),
1884
  KEY `circ_rules_ibfk_2` (`categorycode`),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-1 / +125 lines)
Lines 83-88 Link Here
83
            <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
83
            <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
84
            <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=HomeOrHoldingBranch">[% Koha.Preference('HomeOrHoldingBranch') | html %]</a>.</p
84
            <a href="/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=HomeOrHoldingBranch">[% Koha.Preference('HomeOrHoldingBranch') | html %]</a>.</p
85
        >
85
        >
86
        <p>The “Global checkout limits” section is designed to create a limit for all librairies, thus preventing checkouts accumulation.</p>
86
    </div>
87
    </div>
87
88
88
    <div class="page-section">
89
    <div class="page-section">
Lines 890-895 Link Here
890
        </div>
891
        </div>
891
    [% END %]
892
    [% END %]
892
893
894
    <div id="global_checkout_limits" class="page-section">
895
        <h2>Global checkout limits</h2>
896
        <p>Specify checkout limits for all librairies.</p>
897
        <form id="set-global-checkouts-limit" method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
898
            [% INCLUDE 'csrf-token.inc' %]
899
            <input type="hidden" name="op" value="cud-set-global-checkout-limits" />
900
            <table>
901
                <thead>
902
                    <tr>
903
                        <th class="fixed_sort">Patron category</th>
904
                        <th class="fixed_sort">Item type</th>
905
                        <th class="noExport restricted-access">Actions</th>
906
                        <th>Current checkouts allowed</th>
907
                        <th>Current on-site checkouts allowed</th>
908
                    </tr>
909
                </thead>
910
                <tbody>
911
                [% FOREACH c IN categorycodes %]
912
                    [% SET c = '' UNLESS c.defined %]
913
                    [% FOREACH i IN itemtypes %]
914
                        [% SET i = '' UNLESS i.defined %]
915
                        [% SET maxissueqty = CirculationRules.Search( '', c, i, 'maxissueqty', { want_rule => 1, has_priority => 1 } ) %]
916
                        [% SET maxonsiteissueqty = CirculationRules.Search( '', c, i, 'maxonsiteissueqty', { want_rule => 1, has_priority => 1 } ) %]
917
                        [% SET show_rule = maxissueqty || maxonsiteissueqty %]
918
                        [% IF show_rule %]
919
                            <tr>
920
                                <td data-code="[% c | html %]">
921
                                    [% IF c == undef %]
922
                                        <em>All</em>
923
                                    [% ELSE %]
924
                                        [% Categories.GetName(c) | html %]
925
                                    [% END %]
926
                                </td>
927
                                <td data-code="[% i | html %]">
928
                                    [% IF i == undef %]
929
                                        <em>All</em>
930
                                    [% ELSE %]
931
                                        [% ItemTypes.GetDescription(i,1) | html %]
932
                                    [% END %]
933
                                </td>
934
                                <td class="actions restricted-access">
935
                                    <a href="#" class="editrule btn btn-default btn-xs"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a>
936
                                    <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>
937
                                </td>
938
                                <td>
939
                                    [% IF maxissueqty.rule_value && maxissueqty.rule_value != '' %]
940
                                        [% maxissueqty.rule_value | html %]
941
                                    [% ELSE %]
942
                                        <span>Not defined</span>
943
                                    [% END %]
944
                                </td>
945
                                <td>
946
                                    [% IF maxonsiteissueqty.rule_value && maxonsiteissueqty.rule_value != ''  %]
947
                                        [% maxonsiteissueqty.rule_value | html %]
948
                                    [% ELSE %]
949
                                        <span>Not defined</span>
950
                                    [% END %]
951
                                </td>
952
                            </tr>
953
                        [% END %]
954
                    [% END %]
955
                [% END %]
956
                <tr class="noExport restricted-access" id="edit_row">
957
                    <td>
958
                        <select name="categorycode" id="categorycode">
959
                            <option value="*">All</option>
960
                        [% FOREACH patron_category IN patron_categories%]
961
                            <option value="[% patron_category.categorycode | html %]">[% patron_category.description | html %]</option>
962
                        [% END %]
963
                        </select>
964
                    </td>
965
                    <td>
966
                        <select name="itemtype" id="matrixitemtype" style="width:13em;">
967
                            <option value="*">All</option>
968
                            [% FOREACH itemtypeloo IN itemtypeloop %]
969
                                [% NEXT IF itemtypeloo.parent_type %]
970
                                [% SET children = itemtypeloo.children_with_localization %]
971
                                [% IF children.count %]
972
                                    <optgroup label="[% itemtypeloo.translated_description | html %]">
973
                                        <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %] (All)</option>
974
                                        [% FOREACH child IN children %]
975
                                            <option value="[% child.itemtype | html %]">[% child.translated_description | html %]</option>
976
                                        [% END %]
977
                                    </optgroup>
978
                                [% ELSE %]
979
                                    <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %]</option>
980
                                [% END %]
981
                            [% END %]
982
                        </select>
983
                    </td>
984
                    <td class="actions">
985
                        <button type="submit" class="btn btn-primary btn-xs"><i class="fa fa-save"></i> Save</button>
986
                        <button name="cancel" class="clear_edit btn btn-default btn-xs"><i class="fa fa-undo"></i> Clear</button>
987
                    </td>
988
                    <td><input type="text" name="maxissueqty" id="maxissueqty" size="3" /></td>
989
                    <td><input type="text" name="maxonsiteissueqty" id="maxonsiteissueqty" size="3" /></td>
990
                </tr>
991
                </tbody>
992
            </table>
993
        </form>
994
    </div>
995
893
    <div id="waiting-hold-cancel-category" class="page-section">
996
    <div id="waiting-hold-cancel-category" class="page-section">
894
        [% IF humanbranch %]
997
        [% IF humanbranch %]
895
            <h2>Waiting hold cancellation policy for [% Branches.GetName( humanbranch ) | html %]</h2>
998
            <h2>Waiting hold cancellation policy for [% Branches.GetName( humanbranch ) | html %]</h2>
Lines 1713-1718 Link Here
1713
                f.find("[name='branch']").val($(this).data("branch"));
1816
                f.find("[name='branch']").val($(this).data("branch"));
1714
                return f.submit();
1817
                return f.submit();
1715
            });
1818
            });
1819
1820
            $(".delete-global-checkout-limits").on("click", function(e){
1821
                e.preventDefault();
1822
                if ( !confirmDelete(MSG_CONFIRM_DELETE) ) {
1823
                    return false;
1824
                }
1825
                let f = $("#delete_form");
1826
                f.find("[name='op']").val('cud-delete-global-checkout-limits');
1827
                f.find("[name='itemtype']").val($(this).data('itemtype'));
1828
                f.find("[name='categorycode']").val($(this).data('categorycode'));
1829
                f.find("[name='branch']").val($(this).data('branch'));
1830
                return f.submit();
1831
            });
1832
1833
            if($("#branch").val() != '*') {
1834
                var rowCount = $("#default-circulation-rules tbody tr").length;
1835
                if(rowCount == 1){
1836
                    $("#global_checkout_limits").remove();
1837
                } else {
1838
	                $("#global_checkout_limits .restricted-access").remove();
1839
                }
1840
	        }
1716
        });
1841
        });
1717
    </script>
1842
    </script>
1718
[% END %]
1843
[% END %]
1719
- 

Return to bug 8137