From fb9cc67e7dbfd53b196f742c418bb25319f349ab 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 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Minna Kivinen Signed-off-by: Joonas Kylmälä --- C4/Circulation.pm | 358 ++++++++++++--------- C4/Overdues.pm | 35 +- C4/Reserves.pm | 45 ++- Koha/Biblio.pm | 14 +- Koha/CirculationRules.pm | 43 ++- Koha/IssuingRule.pm | 68 ---- Koha/Item.pm | 15 +- Koha/Schema/Result/Issuingrule.pm | 327 ------------------- admin/smart-rules.pl | 115 +++---- installer/data/mysql/atomicupdate/bug_18936.perl | 45 +++ .../prog/en/modules/admin/smart-rules.tt | 330 ++++++++++--------- t/db_dependent/ArticleRequests.t | 49 ++- t/db_dependent/Circulation.t | 346 +++++++++++++++----- t/db_dependent/Circulation/CalcDateDue.t | 23 +- t/db_dependent/Circulation/CalcFine.t | 34 +- t/db_dependent/Circulation/GetHardDueDate.t | 314 ++++++------------ .../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 | 14 +- t/db_dependent/Circulation/issue.t | 16 +- t/db_dependent/DecreaseLoanHighHolds.t | 16 +- t/db_dependent/Fines.t | 35 +- t/db_dependent/Holds.t | 87 +++-- .../Holds/DisallowHoldIfItemsAvailable.t | 22 +- t/db_dependent/Koha/IssuingRules.t | 87 +++-- 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 | 16 +- 31 files changed, 1350 insertions(+), 1339 deletions(-) delete mode 100644 Koha/IssuingRule.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 9fe66251b5..d9fad947df 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -44,7 +44,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; @@ -423,18 +422,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; @@ -1391,14 +1392,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_object->effective_itemtype, - branchcode => $branchcode + branchcode => $branchcode, + 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. @@ -1539,67 +1542,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 ) = @_; + + # 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 => '*', + }, + ); - # 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, + # 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; } @@ -1614,19 +1627,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 ); } } } @@ -2245,14 +2260,20 @@ sub _calculate_new_debar_dt { 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); return unless $finedays; @@ -2263,7 +2284,7 @@ sub _calculate_new_debar_dt { # 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 @@ -2272,16 +2293,16 @@ sub _calculate_new_debar_dt { if ( $deltadays->subtract($grace)->is_positive() ) { my $suspension_days = $deltadays * $finedays; - if ( $issuing_rule->suspension_chargeperiod > 1 ) { + if ( $issuing_rule->{suspension_chargeperiod} > 1 ) { # No need to / 1 and do not consider / 0 $suspension_days = DateTime::Duration->new( - days => floor( $suspension_days->in_units('days') / $issuing_rule->suspension_chargeperiod ) + days => floor( $suspension_days->in_units('days') / $issuing_rule->{suspension_chargeperiod} ) ); } # 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 @@ -2749,15 +2770,23 @@ sub CanBookBeRenewed { return ( 1, undef ) if $override_limit; my $branchcode = _GetCircControlBranch( $item->unblessed, $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->effective_itemtype, - 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'); @@ -2777,23 +2806,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" ); } } @@ -2810,17 +2839,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' ); } @@ -3042,14 +3071,16 @@ sub GetRenewCount { # $item and $borrower should be calculated my $branchcode = _GetCircControlBranch($item->unblessed, $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->effective_itemtype, - 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 ); @@ -3087,25 +3118,29 @@ sub GetSoonestRenewDate { or return; my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed ); - my $issuing_rule = Koha::IssuingRules->get_effective_issuing_rule( + my $issuing_rule = Koha::CirculationRules->get_effective_rules( { categorycode => $patron->categorycode, itemtype => $item->effective_itemtype, - 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' ); } @@ -3146,30 +3181,36 @@ sub GetLatestAutoRenewDate { or return; my $branchcode = _GetCircControlBranch( $item->unblessed, $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->effective_itemtype, - 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; @@ -3216,19 +3257,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) { @@ -3241,37 +3273,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 cd4f838cfd..160bdb14ed 100644 --- a/C4/Overdues.pm +++ b/C4/Overdues.pm @@ -35,7 +35,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); @@ -238,27 +237,43 @@ 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', + ] + } + ); $itemtype = Koha::ItemTypes->find($itemtype); 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 || 0); + my $units_minus_grace = $chargeable_units - ($issuing_rule->{firstremind} || 0); 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 = $issuing_rule->{overduefinescap} if $issuing_rule->{overduefinescap} && $amount > $issuing_rule->{overduefinescap}; # This must be moved to Koha::Item (see also similar code in C4::Accounts::chargelostitem $item->{replacementprice} ||= $itemtype->defaultreplacecost @@ -266,7 +281,7 @@ sub CalcFine { && ( ! defined $item->{replacementprice} || $item->{replacementprice} == 0 ) && C4::Context->preference("useDefaultReplacementCost"); - $amount = $item->{replacementprice} if ( $issuing_rule->cap_fine_to_replacement_price && $item->{replacementprice} && $amount > $item->{replacementprice} ); + $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)", $amount, $units_minus_grace, $chargeable_units); return ($amount, $units_minus_grace, $chargeable_units); diff --git a/C4/Reserves.pm b/C4/Reserves.pm index f2bf8bd5d3..39e61a9d50 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -40,7 +40,6 @@ use Koha::Database; use Koha::DateUtils; use Koha::Hold; use Koha::Holds; -use Koha::IssuingRules; use Koha::ItemTypes; use Koha::Items; use Koha::Libraries; @@ -2206,24 +2205,40 @@ 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, holds_per_day - 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_x_rules = Koha::CirculationRules->get_effective_rules( + { + itemtype => $itemtype, + categorycode => $categorycode, + branchcode => $branchcode, + rules => ['holds_per_record', 'holds_per_day'], + order_by => { + -desc => [ 'categorycode', 'itemtype', 'branchcode' ] + } + } + ); + $rules->{holds_per_record} = $holds_per_x_rules->{holds_per_record}; + $rules->{holds_per_day} = $holds_per_x_rules->{holds_per_day}; - return $sth->fetchrow_hashref(); + return $rules; } =head1 AUTHOR diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index d5fe1f9fa6..a95822cafd 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -37,7 +37,7 @@ use Koha::ArticleRequest::Status; use Koha::ArticleRequests; use Koha::Biblio::Metadatas; use Koha::Biblioitems; -use Koha::IssuingRules; +use Koha::CirculationRules; use Koha::Item::Transfer::Limits; use Koha::Items; use Koha::Libraries; @@ -299,10 +299,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 1294eebde1..82ac198087 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. # @@ -42,6 +41,10 @@ Koha::CirculationRules - Koha CirculationRule 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}; @@ -55,6 +58,9 @@ sub get_effective_rule { $v = undef if $v and $v eq '*'; } + my $order_by = $params->{order_by} + // { -desc => [ 'branchcode', 'categorycode', 'itemtype' ] }; + my $search_params; $search_params->{rule_name} = $rule_name; @@ -65,9 +71,7 @@ sub get_effective_rule { my $rule = $self->search( $search_params, { - order_by => { - -desc => [ 'branchcode', 'categorycode', 'itemtype' ] - }, + order_by => $order_by, rows => 1, } )->single; @@ -75,6 +79,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 cb9ac702c2..0000000000 --- a/Koha/IssuingRule.pm +++ /dev/null @@ -1,68 +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 delete - -=cut - -sub delete { - my ($self) = @_; - - my $branchcode = $self->branchcode eq '*' ? undef : $self->branchcode; - my $categorycode = $self->categorycode eq '*' ? undef : $self->categorycode; - my $itemtype = $self->itemtype eq '*' ? undef : $self->itemtype; - - Koha::CirculationRules->search({ - branchcode => $branchcode, - itemtype => $itemtype, - categorycode => $categorycode, - rule_name => [qw( - maxissueqty - maxonsiteissueqty - max_holds - )], - })->delete; - - $self->SUPER::delete; - -} - -=head3 type - -=cut - -sub _type { - return 'Issuingrule'; -} - -1; diff --git a/Koha/Item.pm b/Koha/Item.pm index e77f8191c4..e8e5e21529 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -29,7 +29,7 @@ use C4::Context; use C4::Circulation; use C4::Reserves; use Koha::Checkouts; -use Koha::IssuingRules; +use Koha::CirculationRules; use Koha::Item::Transfer::Limits; use Koha::Item::Transfers; use Koha::Patrons; @@ -369,10 +369,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 ecc549e5a8..0000000000 --- a/Koha/Schema/Result/Issuingrule.pm +++ /dev/null @@ -1,327 +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 suspension_chargeperiod - - data_type: 'integer' - default_value: 1 - 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 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 holds_per_day - - data_type: 'smallint' - is_nullable: 1 - -=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 - -=head2 note - - data_type: 'varchar' - is_nullable: 1 - size: 100 - -=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 }, - "suspension_chargeperiod", - { data_type => "integer", default_value => 1, 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 }, - "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 }, - "holds_per_day", - { data_type => "smallint", is_nullable => 1 }, - "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, - }, - "note", - { data_type => "varchar", is_nullable => 1, size => 100 }, -); - -=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.07046 @ 2019-03-05 20:49:11 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6bPX0BRWWQZrWFun3GP86Q - -sub koha_object_class { - 'Koha::IssuingRule'; -} -sub koha_objects_class { - 'Koha::IssuingRules'; -} - -1; diff --git a/admin/smart-rules.pl b/admin/smart-rules.pl index 403f425e54..a8dc91e9d9 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; @@ -81,12 +79,41 @@ if ($op eq 'delete') { my $categorycode = $input->param('categorycode'); $debug and warn "deleting $1 $2 $branch"; - Koha::IssuingRules->find({ - branchcode => $branch, - categorycode => $categorycode, - itemtype => $itemtype - })->delete; - + 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'); @@ -264,10 +291,9 @@ elsif ($op eq 'add') { my $note = $input->param('note'); $debug and warn "Adding $br, $bor, $itemtype, $fine, $maxissueqty, $maxonsiteissueqty, $cap_fine_to_replacement_price"; - my $params = { - branchcode => $br, - categorycode => $bor, - itemtype => $itemtype, + my $rules = { + maxissueqty => $maxissueqty, + maxonsiteissueqty => $maxonsiteissueqty, fine => $fine, finedays => $finedays, maxsuspensiondays => $maxsuspensiondays, @@ -297,21 +323,12 @@ elsif ($op eq 'add') { note => $note, }; - 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, itemtype => $itemtype, branchcode => $br, - rules => { - maxissueqty => $maxissueqty, - maxonsiteissueqty => $maxonsiteissueqty, - } + rules => $rules, } ); @@ -548,62 +565,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 b2d4d4046d..738c2ad3f5 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,17 +1,26 @@ [% USE raw %] [% USE Asset %] [% USE Koha %] +[% 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 @@ -112,150 +121,179 @@ - [% FOREACH rule IN rules %] - - [% IF ( rule.default_humancategorycode ) %] - All - [% ELSE %] - [% rule.humancategorycode | html %] - [% END %] - - [% IF rule.default_translated_description %] - All - [% ELSE %] - [% rule.translated_description | html %] - [% END %] - - - Edit - Delete - - - - [% IF rule.note %] - View note - [% ELSE %] [% END %] - - - [% SET rule_value = CirculationRules.Search( rule.branchcode, rule.categorycode, rule.itemtype, 'maxissueqty' ) %] - [% IF rule_value || rule_value == "0" %] - [% rule_value | html %] - [% ELSE %] - Unlimited - [% END %] - - - [% SET rule_value = CirculationRules.Search( rule.branchcode, rule.categorycode, rule.itemtype, 'maxonsiteissueqty' ) %] - [% IF rule_value || rule_value == "0" %] - [% rule_value | html %] - [% ELSE %] - Unlimited - [% END %] - - [% rule.issuelength | html %] - - [% IF ( rule.lengthunit == 'days' ) %] - Days - [% ELSIF ( rule.lengthunit == 'hours') %] - Hours - [% ELSE %] - Undefined - [% END %] - - - [% IF ( rule.hardduedate ) %] - [% IF ( rule.hardduedatebefore ) %] - before [% rule.hardduedate | html %] - - [% ELSIF ( rule.hardduedateexact ) %] - on [% rule.hardduedate | html %] - - [% ELSIF ( rule.hardduedateafter ) %] - after [% rule.hardduedate | html %] - - [% END %] - [% ELSE %] - None defined - [% END %] - - [% rule.fine | html %] - [% rule.chargeperiod | html %] - - [% IF rule.chargeperiod_charge_at %] - Start of interval - [% ELSE %] - End of interval - [% END %] - - [% rule.firstremind | html %] - [% rule.overduefinescap FILTER format("%.2f") %] - - [% IF rule.cap_fine_to_replacement_price %] - - [% ELSE %] - - [% END %] - - [% rule.finedays | html %] - [% rule.maxsuspensiondays | html %] - [% rule.suspension_chargeperiod | html %] - [% rule.renewalsallowed | html %] - [% rule.renewalperiod | html %] - [% rule.norenewalbefore | html %] - - [% IF ( rule.auto_renew ) %] - Yes - [% ELSE %] - No - [% END %] - - [% rule.no_auto_renewal_after | html %] - [% rule.no_auto_renewal_after_hard_limit | html %] - [% rule.reservesallowed | html %] - [% IF rule.unlimited_holds_per_day %] - Unlimited - [% ELSE %] - [% rule.holds_per_day | html %] - [% END %] - - [% rule.holds_per_record | html %] - - [% 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 | html %] - - Edit - Delete - - - - [% END %] + [% SET row_count = 0 %] + [% FOREACH c IN categorycodes %] + [% FOREACH i IN itemtypes %] + [% SET note = CirculationRules.Get( branchcode, c, i, 'note' ) %] + [% 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 suspension_chargeperiod = CirculationRules.Get( branchcode, c, i, 'suspension_chargeperiod' ) %] + [% 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_day = CirculationRules.Get( branchcode, c, i, 'holds_per_day' ) %] + [% 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 || suspension_chargeperiod || renewalsallowed + || renewalsallowed || norenewalbefore || auto_renew || no_auto_renewal_after || no_auto_renewal_after_hard_limit || reservesallowed + || holds_per_day || 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 rule.note %] + View note + [% ELSE %] [% END %] + + + [% IF maxissueqty %] + [% maxissueqty %] + [% ELSE %] + Unlimited + [% END %] + + + [% IF maxonsiteissueqty %] + [% maxonsiteissueqty %] + [% ELSE %] + Unlimited + [% END %] + + [% issuelength %] + + [% IF ( lengthunit == 'days' ) %] + Days + [% ELSIF ( lengthunit == 'hours') %] + Hours + [% ELSE %] + Undefined + [% END %] + + + [% 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 %] + [% suspension_chargeperiod %] + [% renewalsallowed %] + [% renewalperiod %] + [% norenewalbefore %] + + [% IF auto_renew %] + Yes + [% ELSE %] + No + [% END %] + + [% no_auto_renewal_after %] + [% no_auto_renewal_after_hard_limit %] + [% reservesallowed %] + + [% IF holds_per_day.defined && holds != '' %] + [% holds_per_day %] + [% ELSE %] + Unlimited + [% END %] + + [% 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 %]