use warnings;
use C4::Context;
-use C4::Search;
-use C4::Circulation qw( GetTransfers GetBranchItemRule );
+use C4::Circulation qw( GetBranchItemRule );
use Koha::DateUtils qw( dt_from_string );
use Koha::Items;
use Koha::Patrons;
TransportCostMatrix
UpdateTransportCostMatrix
GetPendingHoldRequestsForBib
+ load_branches_to_pull_from
+ update_queue_for_biblio
);
}
=head2 GetHoldsQueueItems
- GetHoldsQueueItems($branch);
+ GetHoldsQueueItems({ branchlimit => $branch, itemtypeslimit => $itype, ccodeslimit => $ccode, locationslimit => $location );
Returns hold queue for a holding branch. If branch is omitted, then whole queue is returned
=cut
sub GetHoldsQueueItems {
- my ($branchlimit) = @_;
+ my $params = shift;
my $dbh = C4::Context->dbh;
my @bind_params = ();
JOIN biblio USING (biblionumber)
LEFT JOIN biblioitems USING (biblionumber)
LEFT JOIN items USING ( itemnumber)
+ WHERE 1=1
/;
- if ($branchlimit) {
- $query .=" WHERE tmp_holdsqueue.holdingbranch = ?";
- push @bind_params, $branchlimit;
+ if ($params->{branchlimit}) {
+ $query .="AND tmp_holdsqueue.holdingbranch = ? ";
+ push @bind_params, $params->{branchlimit};
+ }
+ if( $params->{itemtypeslimit} ) {
+ $query .=" AND items.itype = ? ";
+ push @bind_params, $params->{itemtypeslimit};
+ }
+ if( $params->{ccodeslimit} ) {
+ $query .=" AND items.ccode = ? ";
+ push @bind_params, $params->{ccodeslimit};
+ }
+ if( $params->{locationslimit} ) {
+ $query .=" AND items.location = ? ";
+ push @bind_params, $params->{locationslimit};
}
$query .= " ORDER BY ccode, location, cn_sort, author, title, pickbranch, reservedate";
my $sth = $dbh->prepare($query);
my $bibs_with_pending_requests = GetBibsWithPendingHoldRequests();
foreach my $biblionumber (@$bibs_with_pending_requests) {
+
$total_bibs++;
- my $hold_requests = GetPendingHoldRequestsForBib($biblionumber);
- my $available_items = GetItemsAvailableToFillHoldRequestsForBib($biblionumber, $branches_to_use);
- $total_requests += scalar(@$hold_requests);
- $total_available_items += scalar(@$available_items);
- my $item_map = MapItemsToHoldRequests($hold_requests, $available_items, $branches_to_use, $transport_cost_matrix);
- $item_map or next;
- my $item_map_size = scalar(keys %$item_map)
- or next;
+ my $result = update_queue_for_biblio(
+ { biblio_id => $biblionumber,
+ branches_to_use => $branches_to_use,
+ transport_cost_matrix => $transport_cost_matrix,
+ }
+ );
- $num_items_mapped += $item_map_size;
- CreatePicklistFromItemMap($item_map);
- AddToHoldTargetMap($item_map);
- if (($item_map_size < scalar(@$hold_requests )) and
- ($item_map_size < scalar(@$available_items))) {
- # DOUBLE CHECK, but this is probably OK - unfilled item-level requests
- # FIXME
- #warn "unfilled requests for $biblionumber";
- #warn Dumper($hold_requests), Dumper($available_items), Dumper($item_map);
- }
+ $total_requests += $result->{requests};
+ $total_available_items += $result->{available_items};
+ $num_items_mapped += $result->{mapped_items};
}
}
my ($biblionumber, $branches_to_use) = @_;
my $dbh = C4::Context->dbh;
- my $items_query = "SELECT itemnumber, homebranch, holdingbranch, itemtypes.itemtype AS itype
+ my $items_query = "SELECT items.itemnumber, homebranch, holdingbranch, itemtypes.itemtype AS itype
FROM items ";
if (C4::Context->preference('item-level_itypes')) {
$items_query .= "JOIN biblioitems USING (biblioitemnumber)
LEFT JOIN itemtypes USING (itemtype) ";
}
- $items_query .= "WHERE items.notforloan = 0
+ $items_query .= " LEFT JOIN branchtransfers ON (items.itemnumber = branchtransfers.itemnumber)";
+ $items_query .= " WHERE items.notforloan = 0
AND holdingbranch IS NOT NULL
AND itemlost = 0
AND withdrawn = 0";
+ $items_query .= " AND branchtransfers.datearrived IS NULL
+ AND branchtransfers.datecancelled IS NULL";
$items_query .= " AND damaged = 0" unless C4::Context->preference('AllowHoldsOnDamagedItems');
$items_query .= " AND items.onloan IS NULL
AND (itemtypes.notforloan IS NULL OR itemtypes.notforloan = 0)
- AND itemnumber NOT IN (
+ AND items.itemnumber NOT IN (
SELECT itemnumber
FROM reserves
WHERE biblionumber = ?
$sth->execute(@params);
my $itm = $sth->fetchall_arrayref({});
- my @items = grep { ! scalar GetTransfers($_->{itemnumber}) } @$itm;
return [ grep {
- my $rule = GetBranchItemRule($_->{homebranch}, $_->{itype});
+ my $rule = C4::Circulation::GetBranchItemRule($_->{homebranch}, $_->{itype});
$_->{holdallowed} = $rule->{holdallowed};
$_->{hold_fulfillment_policy} = $rule->{hold_fulfillment_policy};
- } @items ];
+ } @{$itm} ];
}
=head2 _checkHoldPolicy
map { $_->{_object} = Koha::Items->find( $_->{itemnumber} ) } @$available_items;
my $libraries = {};
- map { $libraries->{$_->id} = $_ } Koha::Libraries->search();
+ map { $libraries->{$_->id} = $_ } Koha::Libraries->search->as_list;
# group available items by itemnumber
my %items_by_itemnumber = map { $_->{itemnumber} => $_ } @$available_items;
# return $branch[0] if @branch == 1;
}
+=head3 update_queue_for_biblio
+
+ my $result = update_queue_for_biblio(
+ {
+ biblio_id => $biblio_id,
+ [ branches_to_use => $branches_to_use,
+ transport_cost_matrix => $transport_cost_matrix,
+ delete => $delete, ]
+ }
+ );
+
+Given a I<biblio_id>, this method calculates and sets the holds queue entries
+for the biblio's holds, and the hold fill targets (items).
+
+=head4 Return value
+
+It return a hashref containing:
+
+=over
+
+=item I<requests>: the pending holds count for the biblio.
+
+=item I<available_items> the count of items that are available to fill holds for the biblio.
+
+=item I<mapped_items> the total items that got mapped.
+
+=back
+
+=head4 Optional parameters
+
+=over
+
+=item I<branches_to_use> a list of branchcodes to be used to restrict which items can be used.
+
+=item I<transport_cost_matrix> is the output of C<TransportCostMatrix>.
+
+=item I<delete> tells the method to delete prior entries on the related tables for the biblio_id.
+
+=back
+
+Note: All the optional parameters will be calculated in the method if omitted. They
+are allowed to be passed to avoid calculating them many times inside loops.
+
+=cut
+
+sub update_queue_for_biblio {
+ my ($args) = @_;
+
+ my $biblio_id = $args->{biblio_id};
+
+ my $branches_to_use = $args->{branches_to_use} // load_branches_to_pull_from( C4::Context->preference('UseTransportCostMatrix') );
+ my $transport_cost_matrix;
+
+ if ( !exists $args->{transport_cost_matrix}
+ && C4::Context->preference('UseTransportCostMatrix') ) {
+ $transport_cost_matrix = TransportCostMatrix();
+ } else {
+ $transport_cost_matrix = $args->{transport_cost_matrix};
+ }
+
+ if ( $args->{delete} ) {
+ my $dbh = C4::Context->dbh;
+
+ $dbh->do("DELETE FROM tmp_holdsqueue WHERE biblionumber=$biblio_id");
+ $dbh->do("DELETE FROM hold_fill_targets WHERE biblionumber=$biblio_id");
+ }
+
+ my $hold_requests = GetPendingHoldRequestsForBib($biblio_id);
+ my $available_items = GetItemsAvailableToFillHoldRequestsForBib( $biblio_id, $branches_to_use );
+
+ my $result = {
+ requests => scalar( @{$hold_requests} ),
+ available_items => scalar( @{$available_items} ),
+ };
+
+ my $item_map = MapItemsToHoldRequests( $hold_requests, $available_items, $branches_to_use, $transport_cost_matrix );
+ $result->{mapped_items} = scalar( keys %{$item_map} );
+
+ if ($item_map) {
+ CreatePicklistFromItemMap($item_map);
+ AddToHoldTargetMap($item_map);
+ }
+
+ return $result;
+}
1;