Bugzilla – Attachment 173605 Details for
Bug 8137
Checkout limit for all libraries
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 8137: Add 'global checkout limits' table
Bug-8137-Add-global-checkout-limits-table.patch (text/plain), 20.06 KB, created by
Thibaud Guillot (thibaud_g)
on 2024-10-29 09:34:45 UTC
(
hide
)
Description:
Bug 8137: Add 'global checkout limits' table
Filename:
MIME Type:
Creator:
Thibaud Guillot (thibaud_g)
Created:
2024-10-29 09:34:45 UTC
Size:
20.06 KB
patch
obsolete
>From 380c419e5375ac1da4ac893f9aee90e40cf21fc5 Mon Sep 17 00:00:00 2001 >From: Thibaud Guillot <thibaud.guillot@biblibre.com> >Date: Fri, 23 Feb 2024 10:14:40 +0100 >Subject: [PATCH] Bug 8137: Add 'global checkout limits' table > >The aim here is to avoid the accumulation of checkouts possibilities through the rules of the various branches, in order to have a global quota. > >Test plan: > >1) Apply this patch >2) Run updatedatabase script and rebuild schema, restart_all.. >3) On circulation rules page you will find a new table "Global checkout > limits". >4) If you enter values, they will overwrite the existing values, > creating limits for all branches combined. >5) Test it by set a "current checkouts allowed" to 2 on "standard rules section" > and set a "global" maxissueqty to 1. > Normally 1 is the new limit for now. >6) You can also add a "current checkouts allowed" on other branches and > see that you can't accumulate checkouts (you can also delete "global" > values and see that if you have 3 on a branch and 2 on other, you can > perform 5 checkouts in total. >7) Note that on specific branch circulation rules page the table cannot > be modified, but just shown as a reminder. If main matrix is empty on >specific branch the table is hidden by default (cause if none values >it's referred to standard rules). > >Sponsored-by: BibLibre >Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com> >--- > Koha/CirculationRules.pm | 28 +++- > Koha/Template/Plugin/CirculationRules.pm | 2 + > admin/smart-rules.pl | 40 +++++- > .../Bug_8137-add-column-has_priority.pl | 15 +++ > installer/data/mysql/kohastructure.sql | 1 + > .../prog/en/modules/admin/smart-rules.tt | 124 ++++++++++++++++++ > 6 files changed, 206 insertions(+), 4 deletions(-) > create mode 100644 installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl > >diff --git a/Koha/CirculationRules.pm b/Koha/CirculationRules.pm >index d558c1e781..b108399967 100644 >--- a/Koha/CirculationRules.pm >+++ b/Koha/CirculationRules.pm >@@ -221,6 +221,8 @@ our $RULE_KINDS = { > }, > bookings_trail_period => { > scope => [ 'branchcode', 'itemtype' ], >+ has_priority => { >+ scope => [ 'branchcode', 'categorycode' ], > }, > # Not included (deprecated?): > # * accountsent >@@ -254,6 +256,7 @@ sub get_effective_rule { > $params->{categorycode} //= undef; > $params->{branchcode} //= undef; > $params->{itemtype} //= undef; >+ $params->{has_priority} //= undef; > > my $rule_name = $params->{rule_name}; > my $categorycode = $params->{categorycode}; >@@ -286,7 +289,17 @@ sub get_effective_rule { > } > )->single; > >- return $rule; >+ $search_params->{has_priority} = 1; >+ >+ my $priority_rule = $self->search( >+ $search_params, >+ { >+ order_by => $order_by, >+ rows => 1, >+ } >+ )->single; >+ >+ return defined $priority_rule ? $priority_rule : $rule; > } > > =head3 get_effective_rule_value >@@ -314,10 +327,11 @@ sub get_effective_rule_value { > my $categorycode = $params->{categorycode}; > my $itemtype = $params->{itemtype}; > my $branchcode = $params->{branchcode}; >+ my $has_priority = $params->{has_priority}; > > my $memory_cache = Koha::Cache::Memory::Lite->get_instance; > my $cache_key = sprintf "CircRules:%s:%s:%s:%s", $rule_name // q{}, >- $categorycode // q{}, $branchcode // q{}, $itemtype // q{}; >+ $categorycode // q{}, $branchcode // q{}, $itemtype // q{} ,$has_priority // q{}; > > my $cached = $memory_cache->get_from_cache($cache_key); > return $cached if $cached; >@@ -340,6 +354,7 @@ sub get_effective_rules { > my $categorycode = $params->{categorycode}; > my $itemtype = $params->{itemtype}; > my $branchcode = $params->{branchcode}; >+ my $has_priority = $params->{has_priority}; > > my $r; > foreach my $rule (@$rules) { >@@ -349,6 +364,7 @@ sub get_effective_rules { > categorycode => $categorycode, > itemtype => $itemtype, > branchcode => $branchcode, >+ has_priority => $has_priority, > } > ); > >@@ -392,6 +408,8 @@ sub set_rule { > my $itemtype = $params->{itemtype}; > my $rule_name = $params->{rule_name}; > my $rule_value = $params->{rule_value}; >+ my $has_priority = $params->{has_priority}; >+ > my $can_be_blank = defined $kind_info->{can_be_blank} ? $kind_info->{can_be_blank} : 1; > $rule_value = undef if defined $rule_value && $rule_value eq "" && !$can_be_blank; > my $is_monetary = defined $kind_info->{is_monetary} ? $kind_info->{is_monetary} : 0; >@@ -407,6 +425,7 @@ sub set_rule { > branchcode => $branchcode, > categorycode => $categorycode, > itemtype => $itemtype, >+ has_priority => $has_priority > } > )->next(); > >@@ -428,6 +447,7 @@ sub set_rule { > itemtype => $itemtype, > rule_name => $rule_name, > rule_value => $rule_value, >+ has_priority => $has_priority, > } > ); > $rule->store(); >@@ -453,7 +473,9 @@ sub set_rules { > $set_params{branchcode} = $params->{branchcode} if exists $params->{branchcode}; > $set_params{categorycode} = $params->{categorycode} if exists $params->{categorycode}; > $set_params{itemtype} = $params->{itemtype} if exists $params->{itemtype}; >- my $rules = $params->{rules}; >+ $set_params{has_priority} = $params->{has_priority} if exists $params->{has_priority}; >+ my $rules = $params->{rules}; >+ > > my $rule_objects = []; > while ( my ( $rule_name, $rule_value ) = each %$rules ) { >diff --git a/Koha/Template/Plugin/CirculationRules.pm b/Koha/Template/Plugin/CirculationRules.pm >index 5e00e45638..5187bc3df6 100644 >--- a/Koha/Template/Plugin/CirculationRules.pm >+++ b/Koha/Template/Plugin/CirculationRules.pm >@@ -76,6 +76,7 @@ sub Search { > $branchcode = undef if $branchcode eq q{} or $branchcode eq q{*}; > $categorycode = undef if $categorycode eq q{} or $categorycode eq q{*}; > $itemtype = undef if $itemtype eq q{} or $itemtype eq q{*}; >+ my $has_priority = $params->{has_priority} // undef; > > my $rule = Koha::CirculationRules->search( > { >@@ -83,6 +84,7 @@ sub Search { > categorycode => $categorycode, > itemtype => $itemtype, > rule_name => $rule_name, >+ has_priority => $has_priority > } > )->next; > >diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl >index 6a0895448f..0782f61d72 100755 >--- a/admin/smart-rules.pl >+++ b/admin/smart-rules.pl >@@ -749,6 +749,44 @@ elsif ( $op eq 'cud-mod-refund-lost-item-fee-rule' ) { > rules => { waiting_hold_cancellation => undef }, > } > ); >+} elsif ( $op eq 'cud-set-global-checkout-limits' ) { >+ >+ my $categorycode = $input->param('categorycode'); >+ my $itemtype = $input->param('itemtype'); >+ my $maxissueqty = scalar $input->param('maxissueqty'); >+ my $maxonsiteissueqty = scalar $input->param('maxonsiteissueqty'); >+ >+ my %checkout_rules; >+ $checkout_rules{'maxissueqty'} = strip_non_numeric($maxissueqty); >+ $checkout_rules{'maxonsiteissueqty'} = strip_non_numeric($maxonsiteissueqty); >+ >+ while (my ($rule_name, $rule_value) = each(%checkout_rules)) { >+ if(defined $rule_value && $rule_value ne '') { >+ Koha::CirculationRules->set_rule( >+ { categorycode => ( $categorycode eq '*' ) ? undef : $categorycode, >+ itemtype => ( $itemtype eq '*' ) ? undef : $itemtype, >+ branchcode => undef, >+ has_priority => 1, >+ rule_name => $rule_name, >+ rule_value => $rule_value >+ }); >+ } >+ } >+} elsif ( $op eq 'cud-delete-global-checkout-limits' ) { >+ my $categorycode = $input->param('categorycode'); >+ my $itemtype = $input->param('itemtype'); >+ >+ Koha::CirculationRules->set_rules( >+ { categorycode => ( $categorycode eq '*' ) ? undef : $categorycode, >+ itemtype => ( $itemtype eq '*' ) ? undef : $itemtype, >+ branchcode => undef, >+ has_priority => 1, >+ rules => { >+ maxissueqty => undef, >+ maxonsiteissueqty => undef, >+ }, >+ } >+ ); > } > > >@@ -776,7 +814,7 @@ my @used_itemtypes = > Koha::CirculationRules->search( { branchcode => $humanbranch }, { columns => ['itemtype'], distinct => 1, } ) > ->get_column('itemtype'); > >-my $all_rules = Koha::CirculationRules->search({ branchcode => $humanbranch }); >+my $all_rules = Koha::CirculationRules->search({ branchcode => $humanbranch, has_priority => undef }); > my $definedbranch = $all_rules->count ? 1 : 0; > > my $rules = {}; >diff --git a/installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl b/installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl >new file mode 100644 >index 0000000000..ae6dbec72d >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/Bug_8137-add-column-has_priority.pl >@@ -0,0 +1,15 @@ >+use Modern::Perl; >+ >+return { >+ bug_number => "8137", >+ description => "Add column has_priority", >+ up => sub { >+ my ($args) = @_; >+ my ( $dbh, $out ) = @$args{qw(dbh out)}; >+ >+ if ( !column_exists( 'circulation_rules', 'has_priority' ) ) { >+ $dbh->do('ALTER TABLE circulation_rules ADD IF NOT EXISTS has_priority INT(1) DEFAULT NULL'); >+ say $out "Added column 'circulation_rules.has_priority'"; >+ } >+ }, >+}; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index 1d394f32fa..08300d9b8b 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -1868,6 +1868,7 @@ CREATE TABLE `circulation_rules` ( > `itemtype` varchar(10) DEFAULT NULL, > `rule_name` varchar(32) NOT NULL, > `rule_value` varchar(32) NOT NULL, >+ `has_priority` tinyint(1) DEFAULT NULL, > PRIMARY KEY (`id`), > UNIQUE KEY `branchcode` (`branchcode`,`categorycode`,`itemtype`,`rule_name`), > KEY `circ_rules_ibfk_2` (`categorycode`), >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt >index 0b143b0cea..bfcc9b614c 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt >@@ -71,6 +71,7 @@ > or the specific rule's type, whichever is less.</p> > <p>To modify a rule, create a new one with the same patron category and item type.</p> > <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> >+ <p>The âGlobal checkout limitsâ section is designed to create a limit for all librairies, thus preventing checkouts accumulation.</p> > </div> > > <div class="page-section"> >@@ -900,6 +901,108 @@ > </div> > [% END %] > >+ <div id="global_checkout_limits" class="page-section"> >+ <h2>Global checkout limits</h2> >+ <p>Specify checkout limits for all librairies.</p> >+ <form id="set-global-checkouts-limit" method="post" action="/cgi-bin/koha/admin/smart-rules.pl"> >+ [% INCLUDE 'csrf-token.inc' %] >+ <input type="hidden" name="op" value="cud-set-global-checkout-limits" /> >+ <table> >+ <thead> >+ <tr> >+ <th class="fixed_sort">Patron category</th> >+ <th class="fixed_sort">Item type</th> >+ <th class="noExport restricted-access">Actions</th> >+ <th>Current checkouts allowed</th> >+ <th>Current on-site checkouts allowed</th> >+ </tr> >+ </thead> >+ <tbody> >+ [% FOREACH c IN categorycodes %] >+ [% SET c = '' UNLESS c.defined %] >+ [% FOREACH i IN itemtypes %] >+ [% SET i = '' UNLESS i.defined %] >+ [% SET maxissueqty = CirculationRules.Search( '', c, i, 'maxissueqty', { want_rule => 1, has_priority => 1 } ) %] >+ [% SET maxonsiteissueqty = CirculationRules.Search( '', c, i, 'maxonsiteissueqty', { want_rule => 1, has_priority => 1 } ) %] >+ [% SET show_rule = maxissueqty || maxonsiteissueqty %] >+ [% IF show_rule %] >+ <tr> >+ <td data-code="[% c | html %]"> >+ [% IF c == undef %] >+ <em>All</em> >+ [% ELSE %] >+ [% Categories.GetName(c) | html %] >+ [% END %] >+ </td> >+ <td data-code="[% i | html %]"> >+ [% IF i == undef %] >+ <em>All</em> >+ [% ELSE %] >+ [% ItemTypes.GetDescription(i,1) | html %] >+ [% END %] >+ </td> >+ <td class="actions restricted-access"> >+ <a href="#" class="editrule btn btn-default btn-xs"><i class="fa-solid fa-pencil" aria-hidden="true"></i> Edit</a> >+ <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> >+ </td> >+ <td> >+ [% IF maxissueqty.rule_value && maxissueqty.rule_value != '' %] >+ [% maxissueqty.rule_value | html %] >+ [% ELSE %] >+ <span>Not defined</span> >+ [% END %] >+ </td> >+ <td> >+ [% IF maxonsiteissueqty.rule_value && maxonsiteissueqty.rule_value != '' %] >+ [% maxonsiteissueqty.rule_value | html %] >+ [% ELSE %] >+ <span>Not defined</span> >+ [% END %] >+ </td> >+ </tr> >+ [% END %] >+ [% END %] >+ [% END %] >+ <tr class="noExport restricted-access" id="edit_row"> >+ <td> >+ <select name="categorycode" id="categorycode"> >+ <option value="*">All</option> >+ [% FOREACH patron_category IN patron_categories%] >+ <option value="[% patron_category.categorycode | html %]">[% patron_category.description | html %]</option> >+ [% END %] >+ </select> >+ </td> >+ <td> >+ <select name="itemtype" id="matrixitemtype" style="width:13em;"> >+ <option value="*">All</option> >+ [% FOREACH itemtypeloo IN itemtypeloop %] >+ [% NEXT IF itemtypeloo.parent_type %] >+ [% SET children = itemtypeloo.children_with_localization %] >+ [% IF children.count %] >+ <optgroup label="[% itemtypeloo.translated_description | html %]"> >+ <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %] (All)</option> >+ [% FOREACH child IN children %] >+ <option value="[% child.itemtype | html %]">[% child.translated_description | html %]</option> >+ [% END %] >+ </optgroup> >+ [% ELSE %] >+ <option value="[% itemtypeloo.itemtype | html %]">[% itemtypeloo.translated_description | html %]</option> >+ [% END %] >+ [% END %] >+ </select> >+ </td> >+ <td class="actions"> >+ <button type="submit" class="btn btn-primary btn-xs"><i class="fa fa-save"></i> Save</button> >+ <button name="cancel" class="clear_edit btn btn-default btn-xs"><i class="fa fa-undo"></i> Clear</button> >+ </td> >+ <td><input type="text" name="maxissueqty" id="maxissueqty" size="3" /></td> >+ <td><input type="text" name="maxonsiteissueqty" id="maxonsiteissueqty" size="3" /></td> >+ </tr> >+ </tbody> >+ </table> >+ </form> >+ </div> >+ > <div id="waiting-hold-cancel-category" class="page-section"> > [% IF humanbranch %] > <h2>Waiting hold cancellation policy for [% Branches.GetName( humanbranch ) | html %]</h2> >@@ -1711,6 +1814,27 @@ > return f.submit(); > }); > >+ $(".delete-global-checkout-limits").on("click", function(e){ >+ e.preventDefault(); >+ if ( !confirmDelete(MSG_CONFIRM_DELETE) ) { >+ return false; >+ } >+ let f = $("#delete_form"); >+ f.find("[name='op']").val('cud-delete-global-checkout-limits'); >+ f.find("[name='itemtype']").val($(this).data('itemtype')); >+ f.find("[name='categorycode']").val($(this).data('categorycode')); >+ f.find("[name='branch']").val($(this).data('branch')); >+ return f.submit(); >+ }); >+ >+ if($("#branch").val() != '*') { >+ var rowCount = $("#default-circulation-rules tbody tr").length; >+ if(rowCount == 1){ >+ $("#global_checkout_limits").remove(); >+ } else { >+ $("#global_checkout_limits .restricted-access").remove(); >+ } >+ } > }); > </script> > [% END %] >-- >2.25.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 8137
:
9705
|
9706
|
11079
|
64703
|
64704
|
64791
|
64891
|
72831
|
72832
|
107207
|
107208
|
107209
|
107459
|
111368
|
111369
|
111370
|
112640
|
113797
|
113882
|
114531
|
114532
|
114533
|
114534
|
116676
|
116677
|
116678
|
116679
|
116680
|
145476
|
145477
|
145478
|
145479
|
145480
|
152040
|
152041
|
152042
|
152043
|
152044
|
152045
|
156316
|
156317
|
156318
|
156319
|
156320
|
156321
|
156322
|
159712
|
162367
|
167208
|
167923
|
168119
|
169084
|
169696
|
169700
|
169727
|
169927
|
169928
|
170411
|
173605
|
173608
|
175837
|
175838
|
177464