From 5e9090c9bc6372bd295d138b896d3af0dc59164c Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Thu, 13 Jul 2017 10:03:54 -0400 Subject: [PATCH] Bug 18936 - Convert issuingrules fields to circulation_rules --- C4/Circulation.pm | 354 ++++++++++++--------- C4/Overdues.pm | 37 ++- C4/Reserves.pm | 44 ++- Koha/Biblio.pm | 14 +- Koha/CirculationRules.pm | 45 ++- Koha/IssuingRule.pm | 42 --- Koha/IssuingRules.pm | 136 -------- Koha/Item.pm | 15 +- Koha/Schema/Result/Issuingrule.pm | 307 ------------------ admin/smart-rules.pl | 101 +++--- installer/data/mysql/atomicupdate/bug_18936.perl | 45 +++ .../prog/en/modules/admin/smart-rules.tt | 267 +++++++++------- t/db_dependent/ArticleRequests.t | 49 ++- t/db_dependent/Circulation.t | 348 +++++++++++++++----- t/db_dependent/Circulation/CalcDateDue.t | 23 +- t/db_dependent/Circulation/CalcFine.t | 34 +- t/db_dependent/Circulation/GetHardDueDate.t | 329 +++++++------------ .../Circulation/IssuingRules/maxsuspensiondays.t | 31 +- t/db_dependent/Circulation/Returns.t | 21 +- t/db_dependent/Circulation/SwitchOnSiteCheckouts.t | 21 +- t/db_dependent/Circulation/TooMany.t | 20 +- t/db_dependent/Circulation/issue.t | 31 +- t/db_dependent/DecreaseLoanHighHolds.t | 18 +- t/db_dependent/Fines.t | 35 +- t/db_dependent/Holds.t | 85 +++-- .../Holds/DisallowHoldIfItemsAvailable.t | 17 +- t/db_dependent/Koha/IssuingRules.t | 88 +++-- t/db_dependent/Koha/Objects.t | 9 +- t/db_dependent/Reserves.t | 44 ++- t/db_dependent/Reserves/MultiplePerRecord.t | 105 +++--- t/db_dependent/TestBuilder.t | 4 +- t/db_dependent/api/v1/holds.t | 17 +- 32 files changed, 1337 insertions(+), 1399 deletions(-) delete mode 100644 Koha/IssuingRule.pm delete mode 100644 Koha/IssuingRules.pm delete mode 100644 Koha/Schema/Result/Issuingrule.pm create mode 100644 installer/data/mysql/atomicupdate/bug_18936.perl diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 210cc5726d..8d12c0a9ff 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -45,7 +45,6 @@ use Koha::Biblioitems; use Koha::DateUtils; use Koha::Calendar; use Koha::Checkouts; -use Koha::IssuingRules; use Koha::Items; use Koha::Patrons; use Koha::Patron::Debarments; @@ -421,18 +420,20 @@ sub TooMany { # specific rule if (C4::Context->preference('item-level_itypes')) { $count_query .= " WHERE items.itype NOT IN ( - SELECT itemtype FROM issuingrules + SELECT itemtype FROM circulation_rules WHERE branchcode = ? AND (categorycode = ? OR categorycode = ?) AND itemtype <> '*' + AND rule_name = 'maxissueqty' ) "; - } else { - $count_query .= " JOIN biblioitems USING (biblionumber) + } else { + $count_query .= " JOIN biblioitems USING (biblionumber) WHERE biblioitems.itemtype NOT IN ( - SELECT itemtype FROM issuingrules + SELECT itemtype FROM circulation_rules WHERE branchcode = ? AND (categorycode = ? OR categorycode = ?) AND itemtype <> '*' + AND rule_name = 'maxissueqty' ) "; } push @bind_params, $maxissueqty_rule->branchcode; @@ -1343,14 +1344,16 @@ sub AddIssue { # If automatic renewal wasn't selected while issuing, set the value according to the issuing rule. unless ($auto_renew) { - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { categorycode => $borrower->{categorycode}, + my $rule = Koha::CirculationRules->get_effective_rule( + { + categorycode => $borrower->{categorycode}, itemtype => $item->{itype}, - branchcode => $branch + branchcode => $branch, + rule_name => 'auto_renew' } ); - $auto_renew = $issuing_rule->auto_renew if $issuing_rule; + $auto_renew = $rule->rule_value if $rule; } # Record in the database the fact that the book was issued. @@ -1471,67 +1474,77 @@ Get loan length for an itemtype, a borrower type and a branch =cut sub GetLoanLength { - my ( $borrowertype, $itemtype, $branchcode ) = @_; - my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare(qq{ - SELECT issuelength, lengthunit, renewalperiod - FROM issuingrules - WHERE categorycode=? - AND itemtype=? - AND branchcode=? - AND issuelength IS NOT NULL - }); + my ( $categorycode, $itemtype, $branchcode ) = @_; - # try to find issuelength & return the 1st available. - # check with borrowertype, itemtype and branchcode, then without one of those parameters - $sth->execute( $borrowertype, $itemtype, $branchcode ); - my $loanlength = $sth->fetchrow_hashref; - - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( $borrowertype, '*', $branchcode ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( '*', $itemtype, $branchcode ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( '*', '*', $branchcode ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( $borrowertype, $itemtype, '*' ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( $borrowertype, '*', '*' ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( '*', $itemtype, '*' ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - $sth->execute( '*', '*', '*' ); - $loanlength = $sth->fetchrow_hashref; - return $loanlength - if defined($loanlength) && defined $loanlength->{issuelength}; - - # if no rule is set => 0 day (hardcoded) - return { - issuelength => 0, + # Set search precedences + my @params = ( + { + categorycode => $categorycode, + itemtype => $itemtype, + branchcode => $branchcode, + }, + { + categorycode => $categorycode, + itemtype => '*', + branchcode => $branchcode, + }, + { + categorycode => '*', + itemtype => $itemtype, + branchcode => $branchcode, + }, + { + categorycode => '*', + itemtype => '*', + branchcode => $branchcode, + }, + { + categorycode => $categorycode, + itemtype => $itemtype, + branchcode => '*', + }, + { + categorycode => $categorycode, + itemtype => '*', + branchcode => '*', + }, + { + categorycode => '*', + itemtype => $itemtype, + branchcode => '*', + }, + { + categorycode => '*', + itemtype => '*', + branchcode => '*', + }, + ); + + # Initialize default values + my $rules = { + issuelength => 0, renewalperiod => 0, - lengthunit => 'days', + lengthunit => 'days', }; + # Search for rules! + foreach my $rule_name (qw( issuelength renewalperiod lengthunit )) { + foreach my $params (@params) { + my $rule = Koha::CirculationRules->search( + { + rule_name => $rule_name, + %$params, + } + )->next(); + + if ($rule) { + $rules->{$rule_name} = $rule->rule_value; + last; + } + } + } + + return $rules; } @@ -1546,19 +1559,21 @@ Get the Hard Due Date and it's comparison for an itemtype, a borrower type and a sub GetHardDueDate { my ( $borrowertype, $itemtype, $branchcode ) = @_; - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { categorycode => $borrowertype, + my $rules = Koha::CirculationRules->get_effective_rules( + { + categorycode => $borrowertype, itemtype => $itemtype, - branchcode => $branchcode + branchcode => $branchcode, + rules => [ 'hardduedate', 'hardduedatecompare' ], } ); - - if ( defined( $issuing_rule ) ) { - if ( $issuing_rule->hardduedate ) { - return (dt_from_string($issuing_rule->hardduedate, 'iso'),$issuing_rule->hardduedatecompare); - } else { - return (undef, undef); + if ( defined( $rules->{hardduedate} ) ) { + if ( $rules->{hardduedate} ) { + return ( dt_from_string( $rules->{hardduedate}, 'iso' ), $rules->{hardduedatecompare} ); + } + else { + return ( undef, undef ); } } } @@ -2229,14 +2244,20 @@ sub _debar_user_on_return { my $branchcode = _GetCircControlBranch( $item, $borrower ); my $circcontrol = C4::Context->preference('CircControl'); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( + my $issuing_rule = Koha::CirculationRules->get_effective_rules( { categorycode => $borrower->{categorycode}, itemtype => $item->{itype}, - branchcode => $branchcode + branchcode => $branchcode, + rules => [ + 'finedays', + 'lengthunit', + 'firstremind', + 'maxsuspensiondays', + ] } ); - my $finedays = $issuing_rule ? $issuing_rule->finedays : undef; - my $unit = $issuing_rule ? $issuing_rule->lengthunit : undef; + my $finedays = $issuing_rule ? $issuing_rule->{finedays} : undef; + my $unit = $issuing_rule ? $issuing_rule->{lengthunit} : undef; my $chargeable_units = C4::Overdues::get_chargeable_units($unit, $dt_due, $return_date, $branchcode); if ($finedays) { @@ -2247,7 +2268,7 @@ sub _debar_user_on_return { # grace period is measured in the same units as the loan my $grace = - DateTime::Duration->new( $unit => $issuing_rule->firstremind ); + DateTime::Duration->new( $unit => $issuing_rule->{firstremind} ); my $deltadays = DateTime::Duration->new( days => $chargeable_units @@ -2257,7 +2278,7 @@ sub _debar_user_on_return { # If the max suspension days is < than the suspension days # the suspension days is limited to this maximum period. - my $max_sd = $issuing_rule->maxsuspensiondays; + my $max_sd = $issuing_rule->{maxsuspensiondays}; if ( defined $max_sd ) { $max_sd = DateTime::Duration->new( days => $max_sd ); $suspension_days = $max_sd @@ -2680,15 +2701,23 @@ sub CanBookBeRenewed { return ( 1, undef ) if $override_limit; my $branchcode = _GetCircControlBranch( $item, $patron->unblessed ); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { categorycode => $patron->categorycode, + my $issuing_rule = Koha::CirculationRules->get_effective_rules( + { + categorycode => $patron->categorycode, itemtype => $item->{itype}, - branchcode => $branchcode + branchcode => $branchcode, + rules => [ + 'renewalsallowed', + 'no_auto_renewal_after', + 'no_auto_renewal_after_hard_limit', + 'lengthunit', + 'norenewalbefore', + ] } ); return ( 0, "too_many" ) - if not $issuing_rule or $issuing_rule->renewalsallowed <= $issue->renewals; + if not $issuing_rule->{renewalsallowed} or $issuing_rule->{renewalsallowed} <= $issue->renewals; my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing'); my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing'); @@ -2708,23 +2737,23 @@ sub CanBookBeRenewed { return ( 0, 'auto_account_expired' ); } - if ( defined $issuing_rule->no_auto_renewal_after - and $issuing_rule->no_auto_renewal_after ne "" ) { + if ( defined $issuing_rule->{no_auto_renewal_after} + and $issuing_rule->{no_auto_renewal_after} ne "" ) { # Get issue_date and add no_auto_renewal_after # If this is greater than today, it's too late for renewal. my $maximum_renewal_date = dt_from_string($issue->issuedate, 'sql'); $maximum_renewal_date->add( - $issuing_rule->lengthunit => $issuing_rule->no_auto_renewal_after + $issuing_rule->{lengthunit} => $issuing_rule->{no_auto_renewal_after} ); my $now = dt_from_string; if ( $now >= $maximum_renewal_date ) { return ( 0, "auto_too_late" ); } } - if ( defined $issuing_rule->no_auto_renewal_after_hard_limit - and $issuing_rule->no_auto_renewal_after_hard_limit ne "" ) { + if ( defined $issuing_rule->{no_auto_renewal_after_hard_limit} + and $issuing_rule->{no_auto_renewal_after_hard_limit} ne "" ) { # If no_auto_renewal_after_hard_limit is >= today, it's also too late for renewal - if ( dt_from_string >= dt_from_string( $issuing_rule->no_auto_renewal_after_hard_limit ) ) { + if ( dt_from_string >= dt_from_string( $issuing_rule->{no_auto_renewal_after_hard_limit} ) ) { return ( 0, "auto_too_late" ); } } @@ -2738,17 +2767,17 @@ sub CanBookBeRenewed { } } - if ( defined $issuing_rule->norenewalbefore - and $issuing_rule->norenewalbefore ne "" ) + if ( defined $issuing_rule->{norenewalbefore} + and $issuing_rule->{norenewalbefore} ne "" ) { # Calculate soonest renewal by subtracting 'No renewal before' from due date my $soonestrenewal = dt_from_string( $issue->date_due, 'sql' )->subtract( - $issuing_rule->lengthunit => $issuing_rule->norenewalbefore ); + $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} ); # Depending on syspref reset the exact time, only check the date if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date' - and $issuing_rule->lengthunit eq 'days' ) + and $issuing_rule->{lengthunit} eq 'days' ) { $soonestrenewal->truncate( to => 'day' ); } @@ -2956,14 +2985,16 @@ sub GetRenewCount { # $item and $borrower should be calculated my $branchcode = _GetCircControlBranch($item, $patron->unblessed); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { categorycode => $patron->categorycode, + my $rule = Koha::CirculationRules->get_effective_rule( + { + categorycode => $patron->categorycode, itemtype => $item->{itype}, - branchcode => $branchcode + branchcode => $branchcode, + rule_name => 'renewalsallowed', } ); - $renewsallowed = $issuing_rule ? $issuing_rule->renewalsallowed : 0; + $renewsallowed = $rule ? $rule->rule_value : 0; $renewsleft = $renewsallowed - $renewcount; if($renewsleft < 0){ $renewsleft = 0; } return ( $renewcount, $renewsallowed, $renewsleft ); @@ -3001,25 +3032,29 @@ sub GetSoonestRenewDate { or return; my $branchcode = _GetCircControlBranch( $item, $patron->unblessed ); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( + my $issuing_rule = Koha::CirculationRules->get_effective_rules( { categorycode => $patron->categorycode, itemtype => $item->{itype}, - branchcode => $branchcode + branchcode => $branchcode, + rules => [ + 'norenewalbefore', + 'lengthunit', + ] } ); my $now = dt_from_string; return $now unless $issuing_rule; - if ( defined $issuing_rule->norenewalbefore - and $issuing_rule->norenewalbefore ne "" ) + if ( defined $issuing_rule->{norenewalbefore} + and $issuing_rule->{norenewalbefore} ne "" ) { my $soonestrenewal = dt_from_string( $itemissue->date_due )->subtract( - $issuing_rule->lengthunit => $issuing_rule->norenewalbefore ); + $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} ); if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date' - and $issuing_rule->lengthunit eq 'days' ) + and $issuing_rule->{lengthunit} eq 'days' ) { $soonestrenewal->truncate( to => 'day' ); } @@ -3060,30 +3095,36 @@ sub GetLatestAutoRenewDate { or return; my $branchcode = _GetCircControlBranch( $item, $patron->unblessed ); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { categorycode => $patron->categorycode, + my $circulation_rules = Koha::CirculationRules->get_effective_rules( + { + categorycode => $patron->categorycode, itemtype => $item->{itype}, - branchcode => $branchcode + branchcode => $branchcode, + rules => [ + 'no_auto_renewal_after', + 'no_auto_renewal_after_hard_limit', + 'lengthunit', + ] } ); - return unless $issuing_rule; + return unless $circulation_rules; return - if ( not $issuing_rule->no_auto_renewal_after - or $issuing_rule->no_auto_renewal_after eq '' ) - and ( not $issuing_rule->no_auto_renewal_after_hard_limit - or $issuing_rule->no_auto_renewal_after_hard_limit eq '' ); + if ( not $circulation_rules->{no_auto_renewal_after} + or $circulation_rules->{no_auto_renewal_after} eq '' ) + and ( not $circulation_rules->{no_auto_renewal_after_hard_limit} + or $circulation_rules->{no_auto_renewal_after_hard_limit} eq '' ); my $maximum_renewal_date; - if ( $issuing_rule->no_auto_renewal_after ) { + if ( $circulation_rules->{no_auto_renewal_after} ) { $maximum_renewal_date = dt_from_string($itemissue->issuedate); $maximum_renewal_date->add( - $issuing_rule->lengthunit => $issuing_rule->no_auto_renewal_after + $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after} ); } - if ( $issuing_rule->no_auto_renewal_after_hard_limit ) { - my $dt = dt_from_string( $issuing_rule->no_auto_renewal_after_hard_limit ); + if ( $circulation_rules->{no_auto_renewal_after_hard_limit} ) { + my $dt = dt_from_string( $circulation_rules->{no_auto_renewal_after_hard_limit} ); $maximum_renewal_date = $dt if not $maximum_renewal_date or $maximum_renewal_date > $dt; } return $maximum_renewal_date; @@ -3130,19 +3171,10 @@ sub GetIssuingCharges { $item_type = $item_data->{itemtype}; $charge = $item_data->{rentalcharge}; my $branch = C4::Context::mybranch(); - my $discount_query = q|SELECT rentaldiscount, - issuingrules.itemtype, issuingrules.branchcode - FROM borrowers - LEFT JOIN issuingrules ON borrowers.categorycode = issuingrules.categorycode - WHERE borrowers.borrowernumber = ? - AND (issuingrules.itemtype = ? OR issuingrules.itemtype = '*') - AND (issuingrules.branchcode = ? OR issuingrules.branchcode = '*')|; - my $discount_sth = $dbh->prepare($discount_query); - $discount_sth->execute( $borrowernumber, $item_type, $branch ); - my $discount_rules = $discount_sth->fetchall_arrayref({}); - if (@{$discount_rules}) { + my $patron = Koha::Patrons->find( $borrowernumber ); + my $discount = _get_discount_from_rule($patron->categorycode, $branch, $item_type); + if ($discount) { # We may have multiple rules so get the most specific - my $discount = _get_discount_from_rule($discount_rules, $branch, $item_type); $charge = ( $charge * ( 100 - $discount ) ) / 100; } if ($charge) { @@ -3155,37 +3187,43 @@ sub GetIssuingCharges { # Select most appropriate discount rule from those returned sub _get_discount_from_rule { - my ($rules_ref, $branch, $itemtype) = @_; - my $discount; + my ($categorycode, $branchcode, $itemtype) = @_; - if (@{$rules_ref} == 1) { # only 1 applicable rule use it - $discount = $rules_ref->[0]->{rentaldiscount}; - return (defined $discount) ? $discount : 0; - } - # could have up to 4 does one match $branch and $itemtype - my @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq $itemtype } @{$rules_ref}; - if (@d) { - $discount = $d[0]->{rentaldiscount}; - return (defined $discount) ? $discount : 0; - } - # do we have item type + all branches - @d = grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq $itemtype } @{$rules_ref}; - if (@d) { - $discount = $d[0]->{rentaldiscount}; - return (defined $discount) ? $discount : 0; - } - # do we all item types + this branch - @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq q{*} } @{$rules_ref}; - if (@d) { - $discount = $d[0]->{rentaldiscount}; - return (defined $discount) ? $discount : 0; - } - # so all and all (surely we wont get here) - @d = grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq q{*} } @{$rules_ref}; - if (@d) { - $discount = $d[0]->{rentaldiscount}; - return (defined $discount) ? $discount : 0; + # Set search precedences + my @params = ( + { + branchcode => $branchcode, + itemtype => $itemtype, + categorycode => $categorycode, + }, + { + branchcode => '*', + categorycode => $categorycode, + itemtype => $itemtype, + }, + { + branchcode => $branchcode, + categorycode => $categorycode, + itemtype => '*', + }, + { + branchcode => '*', + categorycode => $categorycode, + itemtype => '*', + }, + ); + + foreach my $params (@params) { + my $rule = Koha::CirculationRules->search( + { + rule_name => 'rentaldiscount', + %$params, + } + )->next(); + + return $rule->rule_value if $rule; } + # none of the above return 0; } diff --git a/C4/Overdues.pm b/C4/Overdues.pm index 6b75e3898a..0d21e05ab0 100644 --- a/C4/Overdues.pm +++ b/C4/Overdues.pm @@ -36,7 +36,6 @@ use C4::Debug; use Koha::DateUtils; use Koha::Account::Lines; use Koha::Account::Offsets; -use Koha::IssuingRules; use Koha::Libraries; use vars qw(@ISA @EXPORT); @@ -243,28 +242,44 @@ sub CalcFine { my $start_date = $due_dt->clone(); # get issuingrules (fines part will be used) my $itemtype = $item->{itemtype} || $item->{itype}; - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule({ categorycode => $bortype, itemtype => $itemtype, branchcode => $branchcode }); + my $issuing_rule = Koha::CirculationRules->get_effective_rules( + { + categorycode => $bortype, + itemtype => $itemtype, + branchcode => $branchcode, + rules => [ + 'lengthunit', + 'firstremind', + 'chargeperiod', + 'chargeperiod_charge_at', + 'fine', + 'overduefinescap', + 'cap_fine_to_replacement_price', + 'chargename', + ] + } + ); return unless $issuing_rule; # If not rule exist, there is no fine - my $fine_unit = $issuing_rule->lengthunit || 'days'; + my $fine_unit = $issuing_rule->{lengthunit} || 'days'; my $chargeable_units = get_chargeable_units($fine_unit, $start_date, $end_date, $branchcode); - my $units_minus_grace = $chargeable_units - $issuing_rule->firstremind; + my $units_minus_grace = $chargeable_units - $issuing_rule->{firstremind}; my $amount = 0; - if ( $issuing_rule->chargeperiod && ( $units_minus_grace > 0 ) ) { + if ( $issuing_rule->{chargeperiod} && ( $units_minus_grace > 0 ) ) { my $units = C4::Context->preference('FinesIncludeGracePeriod') ? $chargeable_units : $units_minus_grace; - my $charge_periods = $units / $issuing_rule->chargeperiod; + my $charge_periods = $units / $issuing_rule->{chargeperiod}; # If chargeperiod_charge_at = 1, we charge a fine at the start of each charge period # if chargeperiod_charge_at = 0, we charge at the end of each charge period - $charge_periods = $issuing_rule->chargeperiod_charge_at == 1 ? ceil($charge_periods) : floor($charge_periods); - $amount = $charge_periods * $issuing_rule->fine; + $charge_periods = $issuing_rule->{chargeperiod_charge_at} == 1 ? ceil($charge_periods) : floor($charge_periods); + $amount = $charge_periods * $issuing_rule->{fine}; } # else { # a zero (or null) chargeperiod or negative units_minus_grace value means no charge. } - $amount = $issuing_rule->overduefinescap if $issuing_rule->overduefinescap && $amount > $issuing_rule->overduefinescap; - $amount = $item->{replacementprice} if ( $issuing_rule->cap_fine_to_replacement_price && $item->{replacementprice} && $amount > $item->{replacementprice} ); + $amount = $issuing_rule->{overduefinescap} if $issuing_rule->{overduefinescap} && $amount > $issuing_rule->{overduefinescap}; + $amount = $item->{replacementprice} if ( $issuing_rule->{cap_fine_to_replacement_price} && $item->{replacementprice} && $amount > $item->{replacementprice} ); $debug and warn sprintf("CalcFine returning (%s, %s, %s, %s)", $amount, $issuing_rule->chargename, $units_minus_grace, $chargeable_units); - return ($amount, $issuing_rule->chargename, $units_minus_grace, $chargeable_units); + return ($amount, $issuing_rule->{chargename}, $units_minus_grace, $chargeable_units); # FIXME: chargename is NEVER populated anywhere. } diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 547952ed7a..2ea7610cd9 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -44,7 +44,6 @@ use Koha::Hold; use Koha::Old::Hold; use Koha::Holds; use Koha::Libraries; -use Koha::IssuingRules; use Koha::Items; use Koha::ItemTypes; use Koha::Patrons; @@ -2072,24 +2071,39 @@ patron category, itemtype, and library. sub GetHoldRule { my ( $categorycode, $itemtype, $branchcode ) = @_; - my $dbh = C4::Context->dbh; - - my $sth = $dbh->prepare( - q{ - SELECT categorycode, itemtype, branchcode, reservesallowed, holds_per_record - FROM issuingrules - WHERE (categorycode in (?,'*') ) - AND (itemtype IN (?,'*')) - AND (branchcode IN (?,'*')) - ORDER BY categorycode DESC, - itemtype DESC, - branchcode DESC + my $reservesallowed = Koha::CirculationRules->get_effective_rule( + { + itemtype => $itemtype, + categorycode => $categorycode, + branchcode => $branchcode, + rule_name => 'reservesallowed', + order_by => { + -desc => [ 'categorycode', 'itemtype', 'branchcode' ] + } } ); + return unless $reservesallowed;; - $sth->execute( $categorycode, $itemtype, $branchcode ); + my $rules; + $rules->{reservesallowed} = $reservesallowed->rule_value; + $rules->{itemtype} = $reservesallowed->itemtype; + $rules->{categorycode} = $reservesallowed->categorycode; + $rules->{branchcode} = $reservesallowed->branchcode; + + my $holds_per_record = Koha::CirculationRules->get_effective_rule( + { + itemtype => $itemtype, + categorycode => $categorycode, + branchcode => $branchcode, + rule_name => 'holds_per_record', + order_by => { + -desc => [ 'categorycode', 'itemtype', 'branchcode' ] + } + } + ); + $rules->{holds_per_record} = $holds_per_record->rule_value if $holds_per_record; - return $sth->fetchrow_hashref(); + return $rules; } =head1 AUTHOR diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index d226304267..e214236781 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -32,7 +32,7 @@ use Koha::Items; use Koha::Biblioitems; use Koha::ArticleRequests; use Koha::ArticleRequest::Status; -use Koha::IssuingRules; +use Koha::CirculationRules; use Koha::Subscriptions; =head1 NAME @@ -141,10 +141,16 @@ sub article_request_type_for_bib { my $borrowertype = $borrower->categorycode; my $itemtype = $self->itemtype(); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule({ categorycode => $borrowertype, itemtype => $itemtype }); + my $rule = Koha::CirculationRules->get_effective_rule( + { + rule_name => 'article_requests', + categorycode => $borrowertype, + itemtype => $itemtype, + } + ); - return q{} unless $issuing_rule; - return $issuing_rule->article_requests || q{} + return q{} unless $rule; + return $rule->rule_value || q{} } =head3 article_request_type_for_items diff --git a/Koha/CirculationRules.pm b/Koha/CirculationRules.pm index 2ab806bef4..8b6fd77bcd 100644 --- a/Koha/CirculationRules.pm +++ b/Koha/CirculationRules.pm @@ -1,7 +1,6 @@ package Koha::CirculationRules; -# Copyright Vaara-kirjastot 2015 -# Copyright Koha Development Team 2016 +# Copyright ByWater Solutions 2017 # # This file is part of Koha. # @@ -28,7 +27,7 @@ use base qw(Koha::Objects); =head1 NAME -Koha::IssuingRules - Koha IssuingRule Object set class +Koha::CirculationRules - Koha CirculationRule Object set class =head1 API @@ -43,11 +42,18 @@ Koha::IssuingRules - Koha IssuingRule Object set class sub get_effective_rule { my ( $self, $params ) = @_; + $params->{categorycode} = '*' if exists($params->{categorycode}) && !defined($params->{categorycode}); + $params->{branchcode} = '*' if exists($params->{branchcode}) && !defined($params->{branchcode}); + $params->{itemtype} = '*' if exists($params->{itemtype}) && !defined($params->{itemtype}); + my $rule_name = $params->{rule_name}; my $categorycode = $params->{categorycode}; my $itemtype = $params->{itemtype}; my $branchcode = $params->{branchcode}; + my $order_by = $params->{order_by} + // { -desc => [ 'branchcode', 'categorycode', 'itemtype' ] }; + croak q{No rule name passed in!} unless $rule_name; my $search_params; @@ -60,9 +66,7 @@ sub get_effective_rule { my $rule = $self->search( $search_params, { - order_by => { - -desc => [ 'branchcode', 'categorycode', 'itemtype' ] - }, + order_by => $order_by, rows => 1, } )->single; @@ -70,6 +74,35 @@ sub get_effective_rule { return $rule; } +=head3 get_effective_rule + +=cut + +sub get_effective_rules { + my ( $self, $params ) = @_; + + my $rules = $params->{rules}; + my $categorycode = $params->{categorycode}; + my $itemtype = $params->{itemtype}; + my $branchcode = $params->{branchcode}; + + my $r; + foreach my $rule (@$rules) { + my $effective_rule = $self->get_effective_rule( + { + rule_name => $rule, + categorycode => $categorycode, + itemtype => $itemtype, + branchcode => $branchcode, + } + ); + + $r->{$rule} = $effective_rule->rule_value if $effective_rule; + } + + return $r; +} + =head3 set_rule =cut diff --git a/Koha/IssuingRule.pm b/Koha/IssuingRule.pm deleted file mode 100644 index 9d81db82ab..0000000000 --- a/Koha/IssuingRule.pm +++ /dev/null @@ -1,42 +0,0 @@ -package Koha::IssuingRule; - -# Copyright Vaara-kirjastot 2015 -# -# This file is part of Koha. -# -# Koha is free software; you can redistribute it and/or modify it under the -# terms of the GNU General Public License as published by the Free Software -# Foundation; either version 3 of the License, or (at your option) any later -# version. -# -# Koha is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with Koha; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -use Modern::Perl; -use Koha::Database; -use base qw(Koha::Object); - -=head1 NAME - -Koha::Hold - Koha Hold object class - -=head1 API - -=head2 Class Methods - -=cut - -=head3 type - -=cut - -sub _type { - return 'Issuingrule'; -} - -1; \ No newline at end of file diff --git a/Koha/IssuingRules.pm b/Koha/IssuingRules.pm deleted file mode 100644 index e0fffd1727..0000000000 --- a/Koha/IssuingRules.pm +++ /dev/null @@ -1,136 +0,0 @@ -package Koha::IssuingRules; - -# Copyright Vaara-kirjastot 2015 -# Copyright Koha Development Team 2016 -# -# This file is part of Koha. -# -# Koha is free software; you can redistribute it and/or modify it under the -# terms of the GNU General Public License as published by the Free Software -# Foundation; either version 3 of the License, or (at your option) any later -# version. -# -# Koha is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with Koha; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -use Modern::Perl; - -use Koha::Database; - -use Koha::IssuingRule; - -use base qw(Koha::Objects); - -=head1 NAME - -Koha::IssuingRules - Koha IssuingRule Object set class - -=head1 API - -=head2 Class Methods - -=cut - -sub get_effective_issuing_rule { - my ( $self, $params ) = @_; - - my $default = '*'; - my $categorycode = $params->{categorycode}; - my $itemtype = $params->{itemtype}; - my $branchcode = $params->{branchcode}; - - my $search_categorycode = $default; - my $search_itemtype = $default; - my $search_branchcode = $default; - - if ($categorycode) { - $search_categorycode = { 'in' => [ $categorycode, $default ] }; - } - if ($itemtype) { - $search_itemtype = { 'in' => [ $itemtype, $default ] }; - } - if ($branchcode) { - $search_branchcode = { 'in' => [ $branchcode, $default ] }; - } - - my $rule = $self->search({ - categorycode => $search_categorycode, - itemtype => $search_itemtype, - branchcode => $search_branchcode, - }, { - order_by => { - -desc => ['branchcode', 'categorycode', 'itemtype'] - }, - rows => 1, - })->single; - return $rule; -} - -=head3 get_opacitemholds_policy - -my $can_place_a_hold_at_item_level = Koha::IssuingRules->get_opacitemholds_policy( { patron => $patron, item => $item } ); - -Return 'Y' or 'F' if the patron can place a hold on this item according to the issuing rules -and the "Item level holds" (opacitemholds). -Can be 'N' - Don't allow, 'Y' - Allow, and 'F' - Force - -=cut - -sub get_opacitemholds_policy { - my ( $class, $params ) = @_; - - my $item = $params->{item}; - my $patron = $params->{patron}; - - return unless $item or $patron; - - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { - categorycode => $patron->categorycode, - itemtype => $item->effective_itemtype, - branchcode => $item->homebranch, - } - ); - - return $issuing_rule ? $issuing_rule->opacitemholds : undef; -} - -=head3 get_onshelfholds_policy - - my $on_shelf_holds = Koha::IssuingRules->get_onshelfholds_policy({ item => $item, patron => $patron }); - -=cut - -sub get_onshelfholds_policy { - my ( $class, $params ) = @_; - my $item = $params->{item}; - my $itemtype = $item->effective_itemtype; - my $patron = $params->{patron}; - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( - { - ( $patron ? ( categorycode => $patron->categorycode ) : () ), - itemtype => $itemtype, - branchcode => $item->holdingbranch - } - ); - return $issuing_rule ? $issuing_rule->onshelfholds : undef; -} - -=head3 type - -=cut - -sub _type { - return 'Issuingrule'; -} - -sub object_class { - return 'Koha::IssuingRule'; -} - -1; diff --git a/Koha/Item.pm b/Koha/Item.pm index bea05f8317..84d8ddbf1a 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -26,7 +26,7 @@ use Koha::DateUtils qw( dt_from_string ); use C4::Context; use Koha::Checkouts; -use Koha::IssuingRules; +use Koha::CirculationRules; use Koha::Item::Transfer; use Koha::Patrons; use Koha::Libraries; @@ -209,10 +209,17 @@ sub article_request_type { : undef; my $borrowertype = $borrower->categorycode; my $itemtype = $self->effective_itemtype(); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule({ categorycode => $borrowertype, itemtype => $itemtype, branchcode => $branchcode }); + my $rule = Koha::CirculationRules->get_effective_rule( + { + rule_name => 'article_requests', + categorycode => $borrowertype, + itemtype => $itemtype, + branchcode => $branchcode + } + ); - return q{} unless $issuing_rule; - return $issuing_rule->article_requests || q{} + return q{} unless $rule; + return $rule->rule_value || q{} } =head3 current_holds diff --git a/Koha/Schema/Result/Issuingrule.pm b/Koha/Schema/Result/Issuingrule.pm deleted file mode 100644 index b1abf36646..0000000000 --- a/Koha/Schema/Result/Issuingrule.pm +++ /dev/null @@ -1,307 +0,0 @@ -use utf8; -package Koha::Schema::Result::Issuingrule; - -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - -=head1 NAME - -Koha::Schema::Result::Issuingrule - -=cut - -use strict; -use warnings; - -use base 'DBIx::Class::Core'; - -=head1 TABLE: C - -=cut - -__PACKAGE__->table("issuingrules"); - -=head1 ACCESSORS - -=head2 categorycode - - data_type: 'varchar' - default_value: (empty string) - is_nullable: 0 - size: 10 - -=head2 itemtype - - data_type: 'varchar' - default_value: (empty string) - is_nullable: 0 - size: 10 - -=head2 restrictedtype - - data_type: 'tinyint' - is_nullable: 1 - -=head2 rentaldiscount - - data_type: 'decimal' - is_nullable: 1 - size: [28,6] - -=head2 reservecharge - - data_type: 'decimal' - is_nullable: 1 - size: [28,6] - -=head2 fine - - data_type: 'decimal' - is_nullable: 1 - size: [28,6] - -=head2 finedays - - data_type: 'integer' - is_nullable: 1 - -=head2 maxsuspensiondays - - data_type: 'integer' - is_nullable: 1 - -=head2 firstremind - - data_type: 'integer' - is_nullable: 1 - -=head2 chargeperiod - - data_type: 'integer' - is_nullable: 1 - -=head2 chargeperiod_charge_at - - data_type: 'tinyint' - default_value: 0 - is_nullable: 0 - -=head2 accountsent - - data_type: 'integer' - is_nullable: 1 - -=head2 chargename - - data_type: 'varchar' - is_nullable: 1 - size: 100 - -=head2 issuelength - - data_type: 'integer' - is_nullable: 1 - -=head2 lengthunit - - data_type: 'varchar' - default_value: 'days' - is_nullable: 1 - size: 10 - -=head2 hardduedate - - data_type: 'date' - datetime_undef_if_invalid: 1 - is_nullable: 1 - -=head2 hardduedatecompare - - data_type: 'tinyint' - default_value: 0 - is_nullable: 0 - -=head2 renewalsallowed - - data_type: 'smallint' - default_value: 0 - is_nullable: 0 - -=head2 renewalperiod - - data_type: 'integer' - is_nullable: 1 - -=head2 norenewalbefore - - data_type: 'integer' - is_nullable: 1 - -=head2 auto_renew - - data_type: 'tinyint' - default_value: 0 - is_nullable: 1 - -=head2 no_auto_renewal_after - - data_type: 'integer' - is_nullable: 1 - -=head2 no_auto_renewal_after_hard_limit - - data_type: 'date' - datetime_undef_if_invalid: 1 - is_nullable: 1 - -=head2 reservesallowed - - data_type: 'smallint' - default_value: 0 - is_nullable: 0 - -=head2 holds_per_record - - data_type: 'smallint' - default_value: 1 - is_nullable: 0 - -=head2 branchcode - - data_type: 'varchar' - default_value: (empty string) - is_nullable: 0 - size: 10 - -=head2 overduefinescap - - data_type: 'decimal' - is_nullable: 1 - size: [28,6] - -=head2 cap_fine_to_replacement_price - - data_type: 'tinyint' - default_value: 0 - is_nullable: 0 - -=head2 onshelfholds - - data_type: 'tinyint' - default_value: 0 - is_nullable: 0 - -=head2 opacitemholds - - data_type: 'char' - default_value: 'N' - is_nullable: 0 - size: 1 - -=head2 article_requests - - data_type: 'enum' - default_value: 'no' - extra: {list => ["no","yes","bib_only","item_only"]} - is_nullable: 0 - -=cut - -__PACKAGE__->add_columns( - "categorycode", - { data_type => "varchar", default_value => "", is_nullable => 0, size => 10 }, - "itemtype", - { data_type => "varchar", default_value => "", is_nullable => 0, size => 10 }, - "restrictedtype", - { data_type => "tinyint", is_nullable => 1 }, - "rentaldiscount", - { data_type => "decimal", is_nullable => 1, size => [28, 6] }, - "reservecharge", - { data_type => "decimal", is_nullable => 1, size => [28, 6] }, - "fine", - { data_type => "decimal", is_nullable => 1, size => [28, 6] }, - "finedays", - { data_type => "integer", is_nullable => 1 }, - "maxsuspensiondays", - { data_type => "integer", is_nullable => 1 }, - "firstremind", - { data_type => "integer", is_nullable => 1 }, - "chargeperiod", - { data_type => "integer", is_nullable => 1 }, - "chargeperiod_charge_at", - { data_type => "tinyint", default_value => 0, is_nullable => 0 }, - "accountsent", - { data_type => "integer", is_nullable => 1 }, - "chargename", - { data_type => "varchar", is_nullable => 1, size => 100 }, - "issuelength", - { data_type => "integer", is_nullable => 1 }, - "lengthunit", - { - data_type => "varchar", - default_value => "days", - is_nullable => 1, - size => 10, - }, - "hardduedate", - { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, - "hardduedatecompare", - { data_type => "tinyint", default_value => 0, is_nullable => 0 }, - "renewalsallowed", - { data_type => "smallint", default_value => 0, is_nullable => 0 }, - "renewalperiod", - { data_type => "integer", is_nullable => 1 }, - "norenewalbefore", - { data_type => "integer", is_nullable => 1 }, - "auto_renew", - { data_type => "tinyint", default_value => 0, is_nullable => 1 }, - "no_auto_renewal_after", - { data_type => "integer", is_nullable => 1 }, - "no_auto_renewal_after_hard_limit", - { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, - "reservesallowed", - { data_type => "smallint", default_value => 0, is_nullable => 0 }, - "holds_per_record", - { data_type => "smallint", default_value => 1, is_nullable => 0 }, - "branchcode", - { data_type => "varchar", default_value => "", is_nullable => 0, size => 10 }, - "overduefinescap", - { data_type => "decimal", is_nullable => 1, size => [28, 6] }, - "cap_fine_to_replacement_price", - { data_type => "tinyint", default_value => 0, is_nullable => 0 }, - "onshelfholds", - { data_type => "tinyint", default_value => 0, is_nullable => 0 }, - "opacitemholds", - { data_type => "char", default_value => "N", is_nullable => 0, size => 1 }, - "article_requests", - { - data_type => "enum", - default_value => "no", - extra => { list => ["no", "yes", "bib_only", "item_only"] }, - is_nullable => 0, - }, -); - -=head1 PRIMARY KEY - -=over 4 - -=item * L - -=item * L - -=item * L - -=back - -=cut - -__PACKAGE__->set_primary_key("branchcode", "categorycode", "itemtype"); - - -# Created by DBIx::Class::Schema::Loader v0.07042 @ 2017-07-03 15:35:15 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dxv4gdxTEP+dd6MY0Y/lcw - - -# You can replace this text with custom code or comments, and it will be preserved on regeneration -1; diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl index bf8f326cca..d127ce7ae8 100755 --- a/admin/smart-rules.pl +++ b/admin/smart-rules.pl @@ -26,8 +26,6 @@ use C4::Koha; use C4::Debug; use Koha::DateUtils; use Koha::Database; -use Koha::IssuingRule; -use Koha::IssuingRules; use Koha::Logger; use Koha::RefundLostItemFeeRules; use Koha::Libraries; @@ -69,8 +67,41 @@ if ($op eq 'delete') { my $categorycode = $input->param('categorycode'); $debug and warn "deleting $1 $2 $branch"; - my $sth_Idelete = $dbh->prepare("delete from issuingrules where branchcode=? and categorycode=? and itemtype=?"); - $sth_Idelete->execute($branch, $categorycode, $itemtype); + Koha::CirculationRules->set_rules( + { + categorycode => $categorycode, + branchcode => $branch, + itemtype => $itemtype, + rules => { + restrictedtype => undef, + rentaldiscount => undef, + fine => undef, + finedays => undef, + maxsuspensiondays => undef, + firstremind => undef, + chargeperiod => undef, + chargeperiod_charge_at => undef, + accountsent => undef, + issuelength => undef, + lengthunit => undef, + hardduedate => undef, + hardduedatecompare => undef, + renewalsallowed => undef, + renewalperiod => undef, + norenewalbefore => undef, + auto_renew => undef, + no_auto_renewal_after => undef, + no_auto_renewal_after_hard_limit => undef, + reservesallowed => undef, + holds_per_record => undef, + overduefinescap => undef, + cap_fine_to_replacement_price => undef, + onshelfholds => undef, + opacitemholds => undef, + article_requests => undef, + } + } + ); } elsif ($op eq 'delete-branch-cat') { my $categorycode = $input->param('categorycode'); @@ -271,13 +302,6 @@ elsif ($op eq 'add') { article_requests => $article_requests, }; - my $issuingrule = Koha::IssuingRules->find({categorycode => $bor, itemtype => $itemtype, branchcode => $br}); - if ($issuingrule) { - $issuingrule->set($params)->store(); - } else { - Koha::IssuingRule->new()->set($params)->store(); - } - Koha::CirculationRules->set_rules( { categorycode => $bor, @@ -286,6 +310,7 @@ elsif ($op eq 'add') { rules => { maxissueqty => $maxissueqty, maxonsiteissueqty => $maxonsiteissueqty, + %$params, } } ); @@ -522,62 +547,16 @@ $template->param( my $patron_categories = Koha::Patron::Categories->search({}, { order_by => ['description'] }); -my @row_loop; my $itemtypes = Koha::ItemTypes->search_with_localization; -my $sth2 = $dbh->prepare(" - SELECT issuingrules.*, - itemtypes.description AS humanitemtype, - categories.description AS humancategorycode, - COALESCE( localization.translation, itemtypes.description ) AS translated_description - FROM issuingrules - LEFT JOIN itemtypes - ON (itemtypes.itemtype = issuingrules.itemtype) - LEFT JOIN categories - ON (categories.categorycode = issuingrules.categorycode) - LEFT JOIN localization ON issuingrules.itemtype = localization.code - AND localization.entity = 'itemtypes' - AND localization.lang = ? - WHERE issuingrules.branchcode = ? -"); -$sth2->execute($language, $branch); - -while (my $row = $sth2->fetchrow_hashref) { - $row->{'current_branch'} ||= $row->{'branchcode'}; - $row->{humanitemtype} ||= $row->{itemtype}; - $row->{default_translated_description} = 1 if $row->{humanitemtype} eq '*'; - $row->{'humancategorycode'} ||= $row->{'categorycode'}; - $row->{'default_humancategorycode'} = 1 if $row->{'humancategorycode'} eq '*'; - $row->{'fine'} = sprintf('%.2f', $row->{'fine'}); - if ($row->{'hardduedate'} && $row->{'hardduedate'} ne '0000-00-00') { - my $harddue_dt = eval { dt_from_string( $row->{'hardduedate'} ) }; - $row->{'hardduedate'} = eval { output_pref( { dt => $harddue_dt, dateonly => 1 } ) } if ( $harddue_dt ); - $row->{'hardduedatebefore'} = 1 if ($row->{'hardduedatecompare'} == -1); - $row->{'hardduedateexact'} = 1 if ($row->{'hardduedatecompare'} == 0); - $row->{'hardduedateafter'} = 1 if ($row->{'hardduedatecompare'} == 1); - } else { - $row->{'hardduedate'} = 0; - } - if ($row->{no_auto_renewal_after_hard_limit}) { - my $dt = eval { dt_from_string( $row->{no_auto_renewal_after_hard_limit} ) }; - $row->{no_auto_renewal_after_hard_limit} = eval { output_pref( { dt => $dt, dateonly => 1 } ) } if $dt; - } - - push @row_loop, $row; -} - -my @sorted_row_loop = sort by_category_and_itemtype @row_loop; - $template->param(show_branch_cat_rule_form => 1); $template->param( patron_categories => $patron_categories, - itemtypeloop => $itemtypes, - rules => \@sorted_row_loop, - humanbranch => ($branch ne '*' ? $branch : ''), - current_branch => $branch, - definedbranch => scalar(@sorted_row_loop)>0 - ); + itemtypeloop => $itemtypes, + humanbranch => ( $branch ne '*' ? $branch : '' ), + current_branch => $branch, +); output_html_with_http_headers $input, $cookie, $template->output; exit 0; diff --git a/installer/data/mysql/atomicupdate/bug_18936.perl b/installer/data/mysql/atomicupdate/bug_18936.perl new file mode 100644 index 0000000000..61b5fb9c6a --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_18936.perl @@ -0,0 +1,45 @@ +$DBversion = 'XXX'; # will be replaced by the RM +if( CheckVersion( $DBversion ) ) { + my @columns = qw( + restrictedtype + rentaldiscount + fine + finedays + maxsuspensiondays + firstremind + chargeperiod + chargeperiod_charge_at + accountsent + issuelength + lengthunit + hardduedate + hardduedatecompare + renewalsallowed + renewalperiod + norenewalbefore + auto_renew + no_auto_renewal_after + no_auto_renewal_after_hard_limit + reservesallowed + holds_per_record + overduefinescap + cap_fine_to_replacement_price + onshelfholds + opacitemholds + article_requests + ); + + if ( column_exists( 'issuingrules', 'categorycode' ) ) { + foreach my $column ( @columns ) { + $dbh->do(" + INSERT INTO circulation_rules ( categorycode, branchcode, itemtype, rule_name, rule_value ) + SELECT categorycode, branchcode, itemtype, 'column', $column + FROM issuingrules + "); + } + $dbh->do("DROP TABLE issuingrules"); + } + + SetVersion( $DBversion ); + print "Upgrade to $DBversion done (Bug 18930 - Move lost item refund rules to circulation_rules table)\n"; +} 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 37aded35d0..de226c526f 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 @@ -1,14 +1,23 @@ +[% USE KohaDates %] [% USE Branches %] [% USE Categories %] +[% USE ItemTypes %] [% USE CirculationRules %] [% SET footerjs = 1 %] -[% SET branchcode = humanbranch %] +[% SET branchcode = humanbranch || '*' %] -[% SET categorycodes = ['*'] %] +[% SET categorycodes = [] %] [% FOREACH pc IN patron_categories %] [% categorycodes.push( pc.id ) %] [% END %] +[% categorycodes.push('*') %] + +[% SET itemtypes = [] %] +[% FOREACH i IN itemtypeloop %] + [% itemtypes.push( i.itemtype ) %] +[% END %] +[% itemtypes.push('*') %] [% INCLUDE 'doc-head-open.inc' %] Koha › Administration › Circulation and fine rules @@ -104,117 +113,149 @@ - [% FOREACH rule IN rules %] - - [% IF ( rule.default_humancategorycode ) %] - All - [% ELSE %] - [% rule.humancategorycode %] - [% END %] - - [% IF rule.default_translated_description %] - All - [% ELSE %] - [% rule.translated_description %] - [% END %] - - - Edit - Delete - - - - [% SET rule_value = CirculationRules.Get( rule.branchcode, rule.categorycode, rule.itemtype, 'maxissueqty' ) %] - [% IF rule_value %] - [% rule_value %] - [% ELSE %] - Unlimited - [% END %] - - - [% SET rule_value = CirculationRules.Get( rule.branchcode, rule.categorycode, rule.itemtype, 'maxonsiteissueqty' ) %] - [% IF rule_value %] - [% rule_value %] - [% ELSE %] - Unlimited - [% END %] - - [% rule.issuelength %] - - [% rule.lengthunit %] - - - [% IF ( rule.hardduedate ) %] - [% IF ( rule.hardduedatebefore ) %] - before [% rule.hardduedate %] - - [% ELSIF ( rule.hardduedateexact ) %] - on [% rule.hardduedate %] - - [% ELSIF ( rule.hardduedateafter ) %] - after [% rule.hardduedate %] - - [% END %] - [% ELSE %] - None defined - [% END %] - - [% rule.fine %] - [% rule.chargeperiod %] - [% IF rule.chargeperiod_charge_at %]Start of interval[% ELSE %]End of interval[% END %] - [% rule.firstremind %] - [% rule.overduefinescap FILTER format("%.2f") %] - - [% IF rule.cap_fine_to_replacement_price %] - - [% ELSE %] - - [% END %] - - [% rule.finedays %] - [% rule.maxsuspensiondays %] - [% rule.renewalsallowed %] - [% rule.renewalperiod %] - [% rule.norenewalbefore %] - - [% IF ( rule.auto_renew ) %] - Yes - [% ELSE %] - No - [% END %] - - [% rule.no_auto_renewal_after %] - [% rule.no_auto_renewal_after_hard_limit %] - [% rule.reservesallowed %] - [% rule.holds_per_record %] - - [% IF rule.onshelfholds == 1 %] - Yes - [% ELSIF rule.onshelfholds == 2 %] - If all unavailable - [% ELSE %] - If any unavailable - [% END %] - [% IF rule.opacitemholds == 'F'%]Force[% ELSIF rule.opacitemholds == 'Y'%]Allow[% ELSE %]Don't allow[% END %] - - [% IF rule.article_requests == 'no' %] - No - [% ELSIF rule.article_requests == 'yes' %] - Yes - [% ELSIF rule.article_requests == 'bib_only' %] - Record only - [% ELSIF rule.article_requests == 'item_only' %] - Item only - [% END %] - - [% rule.rentaldiscount %] - - Edit - Delete - - - - [% END %] + [% SET row_count = 0 %] + [% FOREACH c IN categorycodes %] + [% FOREACH i IN itemtypes %] + [% SET maxissueqty = CirculationRules.Get( branchcode, c, i, 'maxissueqty' ) %] + [% SET maxonsiteissueqty = CirculationRules.Get( branchcode, c, i, 'maxonsiteissueqty' ) %] + [% SET issuelength = CirculationRules.Get( branchcode, c, i, 'issuelength' ) %] + [% SET lengthunit = CirculationRules.Get( branchcode, c, i, 'lengthunit' ) %] + [% SET hardduedate = CirculationRules.Get( branchcode, c, i, 'hardduedate' ) %] + [% SET hardduedatecompare = CirculationRules.Get( branchcode, c, i, 'hardduedatecompare' ) %] + [% SET fine = CirculationRules.Get( branchcode, c, i, 'fine' ) %] + [% SET chargeperiod = CirculationRules.Get( branchcode, c, i, 'chargeperiod' ) %] + [% SET chargeperiod_charge_at = CirculationRules.Get( branchcode, c, i, 'chargeperiod_charge_at' ) %] + [% SET firstremind = CirculationRules.Get( branchcode, c, i, 'firstremind' ) %] + [% SET overduefinescap = CirculationRules.Get( branchcode, c, i, 'overduefinescap' ) %] + [% SET cap_fine_to_replacement_price = CirculationRules.Get( branchcode, c, i, 'cap_fine_to_replacement_price' ) %] + [% SET finedays = CirculationRules.Get( branchcode, c, i, 'finedays' ) %] + [% SET maxsuspensiondays = CirculationRules.Get( branchcode, c, i, 'maxsuspensiondays' ) %] + [% SET renewalsallowed = CirculationRules.Get( branchcode, c, i, 'renewalsallowed' ) %] + [% SET renewalperiod = CirculationRules.Get( branchcode, c, i, 'renewalperiod' ) %] + [% SET norenewalbefore = CirculationRules.Get( branchcode, c, i, 'norenewalbefore' ) %] + [% SET auto_renew = CirculationRules.Get( branchcode, c, i, 'auto_renew' ) %] + [% SET no_auto_renewal_after = CirculationRules.Get( branchcode, c, i, 'no_auto_renewal_after' ) %] + [% SET no_auto_renewal_after_hard_limit = CirculationRules.Get( branchcode, c, i, 'no_auto_renewal_after_hard_limit' ) %] + [% SET reservesallowed = CirculationRules.Get( branchcode, c, i, 'reservesallowed' ) %] + [% SET holds_per_record = CirculationRules.Get( branchcode, c, i, 'holds_per_record' ) %] + [% SET onshelfholds = CirculationRules.Get( branchcode, c, i, 'onshelfholds' ) %] + [% SET opacitemholds = CirculationRules.Get( branchcode, c, i, 'opacitemholds' ) %] + [% SET article_requests = CirculationRules.Get( branchcode, c, i, 'article_requests' ) %] + [% SET rentaldiscount = CirculationRules.Get( branchcode, c, i, 'rentaldiscount' ) %] + + [% SET show_rule = maxissueqty || maxonsiteissueqty || issuelength || lengthunit || hardduedate || hardduedatebefore || hardduedateexact || fine || chargeperiod + || chargeperiod_charge_at || firstremind || overduefinescap || cap_fine_to_replacement_price || finedays || maxsuspensiondays || renewalsallowed + || renewalsallowed || norenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed + || holds_per_record || onshelfholds || opacitemholds || article_requests || article_requests %] + [% IF show_rule %] + [% SET row_count = row_count + 1 %] + + + [% IF c == '*' %] + All + [% ELSE %] + [% Categories.GetName(c) %] + [% END %] + + + [% IF i == '*' %] + All + [% ELSE %] + [% ItemTypes.GetDescription(i) %] + [% END %] + + + [% IF maxissueqty %] + [% maxissueqty %] + [% ELSE %] + Unlimited + [% END %] + + + [% IF maxonsiteissueqty %] + [% maxonsiteissueqty %] + [% ELSE %] + Unlimited + [% END %] + + [% issuelength %] + + [% lengthunit %] + + + [% IF ( hardduedate ) %] + [% IF ( hardduedatecompare == '-1' ) %] + before [% hardduedate | $KohaDates %] + + [% ELSIF ( hardduedatecompare == '0' ) %] + on [% hardduedate | $KohaDates %] + + [% ELSIF ( hardduedatecompare == '1' ) %] + after [% hardduedate | $KohaDates %] + + [% END %] + [% ELSE %] + None defined + [% END %] + + [% fine %] + [% chargeperiod %] + [% IF chargeperiod_charge_at %]Start of interval[% ELSE %]End of interval[% END %] + [% firstremind %] + [% overduefinescap FILTER format("%.2f") %] + + [% IF cap_fine_to_replacement_price %] + + [% ELSE %] + + [% END %] + + [% finedays %] + [% maxsuspensiondays %] + [% renewalsallowed %] + [% renewalperiod %] + [% norenewalbefore %] + + [% IF auto_renew %] + Yes + [% ELSE %] + No + [% END %] + + [% no_auto_renewal_after %] + [% no_auto_renewal_after_hard_limit %] + [% reservesallowed %] + [% holds_per_record %] + + [% IF onshelfholds == 1 %] + Yes + [% ELSIF onshelfholds == 2 %] + If all unavailable + [% ELSE %] + If any unavailable + [% END %] + + [% IF opacitemholds == 'F'%]Force[% ELSIF opacitemholds == 'Y'%]Allow[% ELSE %]Don't allow[% END %] + + [% IF article_requests == 'no' %] + No + [% ELSIF article_requests == 'yes' %] + Yes + [% ELSIF article_requests == 'bib_only' %] + Record only + [% ELSIF article_requests == 'item_only' %] + Item only + [% END %] + + [% rentaldiscount %] + + Edit + Delete + + + [% END %] + [% END %] + [% END %]