Koha/Koha/CurbsidePickup.pm
David Gustafsson f726558510
Bug 32496: Reduce unnecessary unblessings of objects in Circulation.pm
Refactor the most performance critical subroutines in Circulation.pm
to take objects instead of unblessed ones to reduce unnecessary
unblessings and generally clean up the code.

To test:

1) Ensure the following tests all pass:
  t/db_dependent/Circulation.t
  t/db_dependent/Circulation/CalcDateDue.t
  t/db_dependent/Circulation/CheckIfIssuedToPatron.t
  t/db_dependent/Circulation/GetPendingOnSiteCheckouts.t
  t/db_dependent/Circulation/GetTopIssues.t
  t/db_dependent/Circulation/IsItemIssued.t
  t/db_dependent/Circulation/MarkIssueReturned.t
  t/db_dependent/Circulation/ReturnClaims.t
  t/db_dependent/Circulation/Returns.t
  t/db_dependent/Circulation/SwitchOnSiteCheckouts.t
  t/db_dependent/Circulation/TooMany.t
  t/db_dependent/Circulation/dateexpiry.t
  t/db_dependent/Circulation/issue.t
  t/db_dependent/Circulation/maxsuspensiondays.t
  t/db_dependent/Circulation/transferbook.t
  t/db_dependent/Circulation_holdsqueue.t
  t/db_dependent/DecreaseLoanHighHolds.t
  t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t
  t/db_dependent/Holds/RevertWaitingStatus.t
  t/db_dependent/ILSDI_Services.t
  t/db_dependent/Illrequests.t
  t/db_dependent/Koha/Account/Line.t
  t/db_dependent/Koha/Biblio.t
  t/db_dependent/Koha/Items.t
  t/db_dependent/Koha/Object.t
  t/db_dependent/Koha/Patrons.t
  t/db_dependent/Koha/Pseudonymization.t
  t/db_dependent/Koha/Template/Plugin/CirculationRules.t
  t/db_dependent/Letters/TemplateToolkit.t
  t/db_dependent/Members/GetAllIssues.t
  t/db_dependent/Members/IssueSlip.t
  t/db_dependent/Patron/Borrower_Discharge.t
  t/db_dependent/Patron/Borrower_PrevCheckout.t
  t/db_dependent/SIP/ILS.t
  t/db_dependent/Holds.t
  t/db_dependent/Holds/LocalHoldsPriority.t
  t/db_dependent/Holds/HoldFulfillmentPolicy.t
  t/db_dependent/Holds/HoldItemtypeLimit.t
  t/db_dependent/Reserves/GetReserveFee.t
  t/db_dependent/api/v1/return_claims.t
  t/db_dependent/api/v1/biblios.t
  t/db_dependent/api/v1/checkouts.t
  t/db_dependent/Reserves.t
  t/db_dependent/HoldsQueue.t
  t/db_dependent/selenium/regressions.t
  t/db_dependent/Koha/Plugins/Circulation_hooks.t
  t/db_dependent/Koha/Plugins/Recall_hooks.t
  t/db_dependent/Koha/Recalls.t
  t/db_dependent/Koha/Recall.t
  t/db_dependent/Circulation/_CalculateAndUpdateFine.t

Sponsored-by: Gothenburg University Library

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2023-09-22 10:52:39 -03:00

305 lines
7.7 KiB
Perl

package Koha::CurbsidePickup;
# 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 Carp;
use Koha::Database;
use base qw(Koha::Object);
use C4::Circulation qw( CanBookBeIssued AddIssue );
use C4::Members::Messaging qw( GetMessagingPreferences );
use C4::Letters qw( GetPreparedLetter EnqueueLetter );
use Koha::Calendar;
use Koha::DateUtils qw( dt_from_string );
use Koha::Patron;
use Koha::Library;
use Koha::CurbsidePickupIssues;
use Koha::Exceptions::CurbsidePickup;
=head1 NAME
Koha::CurbsidePickup - Koha Curbside Pickup Object class
=head1 API
=head2 Class methods
=cut
=head3 new
=cut
sub new {
my ( $self, $params ) = @_;
my $policy =
Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } );
Koha::Exceptions::CurbsidePickup::NotEnabled->throw
unless $policy && $policy->enabled;
my $calendar = Koha::Calendar->new( branchcode => $params->{branchcode} );
Koha::Exceptions::CurbsidePickup::LibraryIsClosed->throw
if $calendar->is_holiday( $params->{scheduled_pickup_datetime} );
if ( $policy->enable_waiting_holds_only ) {
my $patron = Koha::Patrons->find( $params->{borrowernumber} );
my $waiting_holds = $patron->holds->waiting->search( { branchcode => $params->{branchcode} } );
Koha::Exceptions::CurbsidePickup::NoWaitingHolds->throw
unless $waiting_holds->count;
}
my $existing_curbside_pickups = Koha::CurbsidePickups->search(
{
branchcode => $params->{branchcode},
borrowernumber => $params->{borrowernumber},
delivered_datetime => undef,
}
)->filter_by_scheduled_today;
Koha::Exceptions::CurbsidePickup::TooManyPickups->throw(
branchcode => $params->{branchcode},
borrowernumber => $params->{borrowernumber}
) if $existing_curbside_pickups->count;
my $is_valid =
$policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} );
unless ($is_valid) {
my $error = @{ $is_valid->messages }[0]->message;
Koha::Exceptions::CurbsidePickup::NoMatchingSlots->throw
if $error eq 'no_matching_slots';
Koha::Exceptions::CurbsidePickup::NoMorePickupsAvailable->throw
if $error eq 'no_more_available';
Koha::Exceptions->throw(
"Error message must raise the appropriate exception");
}
return $self->SUPER::new($params);
}
=head3 notify_new_pickup
$pickup->notify_new_pickup
Will notify the patron that the pickup has been created.
Letter 'NEW_CURBSIDE_PICKUP will be used', and depending on 'Hold_Filled' configuration.
=cut
sub notify_new_pickup {
my ( $self ) = @_;
my $patron = $self->patron;
my $library = $self->library;
$patron->queue_notice({ letter_params => {
module => 'reserves',
letter_code => 'NEW_CURBSIDE_PICKUP',
borrowernumber => $patron->borrowernumber,
branchcode => $self->branchcode,
tables => {
'branches' => $library->unblessed,
'borrowers' => $patron->unblessed,
},
substitute => {
curbside_pickup => $self,
}
}, message_name => 'Hold_Filled' });
}
=head3 checkouts
Return the checkouts linked to this pickup
=cut
sub checkouts {
my ( $self ) = @_;
my @pi = Koha::CurbsidePickupIssues->search({ curbside_pickup_id => $self->id })->as_list;
my @checkouts = map { $_->checkout } @pi;
@checkouts = grep { defined $_ } @checkouts;
return @checkouts;
}
=head3 patron
Return the patron linked to this pickup
=cut
sub patron {
my ( $self ) = @_;
my $rs = $self->_result->borrowernumber;
return unless $rs;
return Koha::Patron->_new_from_dbic( $rs );
}
=head3 staged_by_staff
Return the staff member that staged this pickup
=cut
sub staged_by_staff {
my ( $self ) = @_;
my $rs = $self->_result->staged_by;
return unless $rs;
return Koha::Patron->_new_from_dbic( $rs );
}
=head3 library
Return the branch associated with this pickup
=cut
sub library {
my ( $self ) = @_;
my $rs = $self->_result->branchcode;
return unless $rs;
return Koha::Library->_new_from_dbic( $rs );
}
=head3 mark_as_staged
Mark the pickup as staged
=cut
sub mark_as_staged {
my ( $self ) = @_;
my $staged_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef;
$self->set(
{
staged_datetime => dt_from_string(),
staged_by => $staged_by,
arrival_datetime => undef,
}
)->store;
}
=head3 mark_as_unstaged
Mark the pickup as unstaged
=cut
sub mark_as_unstaged {
my ( $self ) = @_;
$self->set(
{
staged_datetime => undef,
staged_by => undef,
arrival_datetime => undef,
}
)->store;
}
=head3 mark_patron_has_arrived
Set the arrival time of the patron
=cut
sub mark_patron_has_arrived {
my ( $self ) = @_;
$self->set(
{
arrival_datetime => dt_from_string(),
}
)->store;
}
=head3 mark_as_delivered
Mark the pickup as delivered. The waiting holds will be filled.
=cut
sub mark_as_delivered {
my ( $self ) = @_;
my $patron = $self->patron;
my $holds = $patron->holds;
my $branchcode = C4::Context->userenv ? C4::Context->userenv->{branch} : undef;
foreach my $hold ( $holds->as_list ) {
if ( $hold->is_waiting && $branchcode && $hold->branchcode eq $branchcode ) {
my ( $issuingimpossible, $needsconfirmation ) =
C4::Circulation::CanBookBeIssued( $patron, $hold->item->barcode );
unless ( keys %$issuingimpossible ) {
my $issue =
C4::Circulation::AddIssue( $patron, $hold->item->barcode );
if ($issue) {
Koha::CurbsidePickupIssue->new(
{
curbside_pickup_id => $self->id,
issue_id => $issue->id,
reserve_id => $hold->id,
}
)->store();
}
else {
Koha::Exceptions->throw(sprintf("Cannot checkout hold %s for patron %s: %s", $patron->id, $hold->id, join(", ", keys %$issuingimpossible)));
}
}
}
}
my $delivered_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef;
$self->arrival_datetime(dt_from_string) unless $self->arrival_datetime;
$self->set(
{
delivered_datetime => dt_from_string(),
delivered_by => $delivered_by,
}
)->store;
}
=head3 status
Return the status of the pickup, can be 'to-be-staged', 'staged-and-ready', 'patron-is-outside' or 'delivered'.
=cut
sub status {
my ($self) = @_;
return
!defined $self->staged_datetime ? 'to-be-staged'
: !defined $self->arrival_datetime ? 'staged-and-ready'
: !defined $self->delivered_datetime ? 'patron-is-outside'
: 'delivered';
}
=head2 Internal methods
=head3 _type
=cut
sub _type {
return 'CurbsidePickup';
}
1;