Koha/circ/reserveratios.pl
Nick Clemens 6754e92c1c Bug 25760: (bug 15422 follow-up) Display record with hold ratio greater than or equal to the value entered
On bug 15422 we made it so that only holds with copies to buy to acheive the holds ratio
showed

Users have reported that they want to see record where there are 0 copies to buy i.e.
the holds ration matches the value entered

This patch changes the criteria for returning holds to be if the ratio for a given title
is equal to or greater then the ratio specified in the form

I also renamed 'ratiocalc' to 'copies_to_buy' since that is what is contains

Test plan:
1. Create bibliographic records with 1, 2 and 3 items
2. Place 1 hold on each of them
3. Go to the Hold ratios report and search with ratio = 1, 2 then 3
4. You expect to see:
   the title with 1 item with ratio 1
   nothing otherwise
5. Place another hold on each of the record
6. Repeat 3 you expect to see:
   titles with 1 or 2 items with ratio 1
   title with 1 item for ratio 2
   nothing with ratio 3
7. Place another hold on each of the record
8. Repeat 3 you expect to see:
   titles with 1 or 2 or 3 items with ratio 1
   title with 1 item or 2 items for ratio 2
   nothing with ratio 3
9. Make sure there is no regression in the test plan of bug 15422

Comments from Frank Hansen:

Some comments.
When I adding the third hold on each record in step 7, It will result in
the following result:

titles with 1 or 2 or 3 items with ratio 1
title with 1 items with ratio 2 because the title with 2 items will get
a ratio of 1.50 and not 2.
title with 1 items with with ratio 3

Signed-off-by: Frank Hansen <frank.hansen@ub.lu.se>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
2021-05-10 15:46:55 +02:00

224 lines
7.8 KiB
Perl
Executable file

#!/usr/bin/perl
# Copyright 2000-2002 Katipo Communications
#
# 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, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use CGI qw ( -utf8 );
use Date::Calc qw/Today Add_Delta_YM/;
use POSIX qw( ceil );
use C4::Context;
use C4::Output;
use C4::Auth;
use C4::Debug;
use C4::Acquisition qw/GetOrdersByBiblionumber/;
use Koha::DateUtils;
use Koha::Acquisition::Baskets;
my $input = CGI->new;
my $startdate = $input->param('from');
my $enddate = $input->param('to');
my $ratio = $input->param('ratio');
my $include_ordered = $input->param('include_ordered');
my $include_suspended = $input->param('include_suspended');
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
template_name => "circ/reserveratios.tt",
query => $input,
type => "intranet",
flagsrequired => { circulate => "circulate_remaining_permissions" },
debug => 1,
}
);
my $booksellerid = $input->param('booksellerid') // '';
my $basketno = $input->param('basketno') // '';
if ($booksellerid && $basketno) {
$template->param( booksellerid => $booksellerid, basketno => $basketno );
}
my $effective_create_items = q{};
if ( $basketno ){
my $basket = Koha::Acquisition::Baskets->find( $basketno );
if ($basket){
$effective_create_items = $basket->effective_create_items;
} else {
$effective_create_items = C4::Context->preference('AcqCreateItem');
}
}
$startdate = eval { dt_from_string( $startdate ) } if $startdate;
$enddate = eval { dt_from_string( $enddate ) } if $enddate;
my $todaysdate = dt_from_string;
# A default of the prior years's holds is a reasonable way to pull holds
$enddate = $todaysdate unless $enddate;
$startdate = $todaysdate->clone->subtract( years => 1 ) unless $startdate;
if (!defined($ratio)) {
$ratio = 3;
}
# Force to be a number
$ratio += 0;
if ($ratio <= 0) {
$ratio = 1; # prevent division by zero
}
my $dbh = C4::Context->dbh;
my $sqldatewhere = "";
$debug and warn output_pref({ dt => $startdate, dateformat => 'iso', dateonly => 1 }) . "\n" . output_pref({ dt => $enddate, dateformat => 'iso', dateonly => 1 });
my @query_params = ();
$sqldatewhere .= " AND reservedate >= ?";
push @query_params, output_pref({ dt => $startdate, dateformat => 'iso' }) ;
$sqldatewhere .= " AND reservedate <= ?";
push @query_params, output_pref({ dt => $enddate, dateformat => 'iso' });
my $include_aqorders_qty =
$effective_create_items eq 'receiving'
? '+ COALESCE(aqorders.quantity, 0) - COALESCE(aqorders.quantityreceived, 0)'
: q{};
my $include_aqorders_qty_join =
$effective_create_items eq 'receiving'
? 'LEFT JOIN aqorders ON reserves.biblionumber=aqorders.biblionumber'
: q{};
my $nfl_comparison = $include_ordered ? '<=' : '=';
my $sus_comparison = $include_suspended ? '<=' : '<';
my $strsth =
"SELECT reservedate,
reserves.borrowernumber as borrowernumber,
reserves.biblionumber,
reserves.branchcode as branch,
items.holdingbranch,
items.itemcallnumber,
items.itemnumber,
GROUP_CONCAT(DISTINCT items.itemcallnumber
ORDER BY items.itemnumber SEPARATOR '|') as listcall,
GROUP_CONCAT(DISTINCT homebranch
ORDER BY items.itemnumber SEPARATOR '|') as homebranch_list,
GROUP_CONCAT(DISTINCT holdingbranch
ORDER BY items.itemnumber SEPARATOR '|') as holdingbranch_list,
GROUP_CONCAT(DISTINCT items.location
ORDER BY items.itemnumber SEPARATOR '|') as l_location,
GROUP_CONCAT(DISTINCT items.itype
ORDER BY items.itemnumber SEPARATOR '|') as l_itype,
reserves.found,
biblio.title,
biblio.subtitle,
biblio.medium,
biblio.part_number,
biblio.part_name,
biblio.author,
count(DISTINCT reserves.borrowernumber) as reservecount,
count(DISTINCT items.itemnumber) $include_aqorders_qty as itemcount
FROM reserves
LEFT JOIN items ON items.biblionumber=reserves.biblionumber
LEFT JOIN biblio ON reserves.biblionumber=biblio.biblionumber
$include_aqorders_qty_join
WHERE
notforloan $nfl_comparison 0 AND damaged = 0 AND itemlost = 0 AND withdrawn = 0
AND suspend $sus_comparison 1
$sqldatewhere
";
if (C4::Context->preference('IndependentBranches')){
$strsth .= " AND items.holdingbranch=? ";
push @query_params, C4::Context->userenv->{'branch'};
}
$strsth .= " GROUP BY reserves.biblionumber ORDER BY reservecount DESC";
$template->param(sql => $strsth);
my $sth = $dbh->prepare($strsth);
$sth->execute(@query_params);
my @reservedata;
while ( my $data = $sth->fetchrow_hashref ) {
my $thisratio = $data->{reservecount} / $data->{itemcount};
my $copies_to_buy = ceil($data->{reservecount}/$ratio - $data->{itemcount});
$thisratio >= $ratio or next; # TODO: tighter targeting -- get ratio limit into SQL using HAVING clause
push(
@reservedata,
{
reservedate => $data->{reservedate},
priority => $data->{priority},
name => $data->{borrower},
title => $data->{title},
subtitle => $data->{subtitle},
medium => $data->{medium},
part_number => $data->{part_number},
part_name => $data->{part_name},
author => $data->{author},
itemnum => $data->{itemnumber},
biblionumber => $data->{biblionumber},
holdingbranch => $data->{holdingbranch},
homebranch_list => [split('\|', $data->{homebranch_list})],
holdingbranch_list => [split('\|', $data->{holdingbranch_list})],
branch => $data->{branch},
itemcallnumber => $data->{itemcallnumber},
location => [split('\|', $data->{l_location})],
itype => [split('\|', $data->{l_itype})],
reservecount => $data->{reservecount},
itemcount => $data->{itemcount},
copies_to_buy => sprintf( "%d", $copies_to_buy ),
thisratio => sprintf( "%.2f", $thisratio ),
thisratio_atleast1 => ( $thisratio >= 1 ) ? 1 : 0,
listcall => [split('\|', $data->{listcall})]
}
);
}
for my $rd ( @reservedata ) {
next unless $rd->{biblionumber};
$rd->{pendingorders} = CountPendingOrdersByBiblionumber( $rd->{biblionumber} );
}
$template->param(
todaysdate => $todaysdate,
from => $startdate,
to => $enddate,
ratio => $ratio,
include_ordered => $include_ordered,
include_suspended => $include_suspended,
reserveloop => \@reservedata,
);
output_html_with_http_headers $input, $cookie, $template->output;
sub CountPendingOrdersByBiblionumber {
my $biblionumber = shift;
my @orders = GetOrdersByBiblionumber( $biblionumber );
my $cnt = 0;
if (scalar(@orders)) {
for my $order ( @orders ) {
next if $order->{datecancellationprinted};
my $onum = $order->{quantity} // 0;
my $rnum = $order->{quantityreceived} // 0;
next if $rnum >= $onum;
$cnt += ($onum - $rnum);
}
}
return $cnt;
}