From ae60b6ebaad4dbdbf1dc2d157df8cc8a0cdec97a Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Tue, 16 Jun 2026 16:33:45 +0000 Subject: [PATCH] Bug 34632: Add Koha::BackgroundJob::PatronImport Introduces a new background job class for patron imports. enqueue() reads the uploaded file content into the job_args and uses line count as job_size for progress tracking. process() reconstitutes the file handle from the stored content, delegates to Koha::Patrons::Import with step_callback wired to $self->step, handles patron list creation, stores the import results, and clears file_content from the stored data to free space. Also registers patron_import in Koha::BackgroundJob::core_types_to_classes so _derived_class can resolve the job correctly. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Brendan Lawlor Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim --- Koha/BackgroundJob.pm | 1 + Koha/BackgroundJob/PatronImport.pm | 126 +++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 Koha/BackgroundJob/PatronImport.pm diff --git a/Koha/BackgroundJob.pm b/Koha/BackgroundJob.pm index ffcd3ffa48..5d86e3533c 100644 --- a/Koha/BackgroundJob.pm +++ b/Koha/BackgroundJob.pm @@ -455,6 +455,7 @@ sub core_types_to_classes { marc_import_revert_batch => 'Koha::BackgroundJob::MARCImportRevertBatch', pseudonymize_statistic => 'Koha::BackgroundJob::PseudonymizeStatistic', import_from_kbart_file => 'Koha::BackgroundJob::ImportKBARTFile', + patron_import => 'Koha::BackgroundJob::PatronImport', file_transport_test => 'Koha::BackgroundJob::TestTransport', }; } diff --git a/Koha/BackgroundJob/PatronImport.pm b/Koha/BackgroundJob/PatronImport.pm new file mode 100644 index 0000000000..987edb9fda --- /dev/null +++ b/Koha/BackgroundJob/PatronImport.pm @@ -0,0 +1,126 @@ +package Koha::BackgroundJob::PatronImport; + +# 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 . + +use Modern::Perl; +use Try::Tiny qw( catch try ); + +use Koha::List::Patron qw( AddPatronList AddPatronsToList ); +use Koha::Patrons::Import; + +use base 'Koha::BackgroundJob'; + +=head1 NAME + +Koha::BackgroundJob::PatronImport - Import patrons from a CSV file as a background job + +This is a subclass of Koha::BackgroundJob. + +=head1 API + +=head2 Class methods + +=head3 job_type + +Define the job type of this job: patron_import + +=cut + +sub job_type { return 'patron_import' } + +=head3 process + +Process the job. + +=cut + +sub process { + my ( $self, $args ) = @_; + + return if $self->status eq 'cancelled'; + + $self->start; + + my $file_content = $args->{file_content}; + open my $fh, '<', \$file_content or die "Cannot create in-memory file handle: $!"; + + my $result = try { + Koha::Patrons::Import->new->import_patrons( + { + file => $fh, + defaults => $args->{defaults}, + matchpoint => $args->{matchpoint}, + overwrite_cardnumber => $args->{overwrite_cardnumber}, + overwrite_passwords => $args->{overwrite_passwords}, + preserve_extended_attributes => $args->{preserve_extended_attributes}, + preserve_fields => $args->{preserve_fields}, + update_dateexpiry => $args->{update_dateexpiry}, + update_dateexpiry_from_today => $args->{update_dateexpiry_from_today}, + update_dateexpiry_from_existing => $args->{update_dateexpiry_from_existing}, + send_welcome => $args->{send_welcome}, + step_callback => sub { $self->step }, + } + ); + } catch { + $self->status('failed')->store; + return; + }; + + my $data = $self->decoded_data; + delete $data->{file_content}; # No longer needed; free DB space + + if ($result) { + if ( $args->{createpatronlist} && @{ $result->{imported_borrowers} // [] } ) { + my $list = AddPatronList( { name => $args->{patronlistname} } ); + AddPatronsToList( { list => $list, borrowernumbers => $result->{imported_borrowers} } ); + $data->{patron_list_name} = $args->{patronlistname}; + } + + $data->{feedback} = $result->{feedback}; + $data->{errors} = $result->{errors}; + $data->{imported} = $result->{imported}; + $data->{overwritten} = $result->{overwritten}; + $data->{already_in_db} = $result->{already_in_db}; + $data->{invalid} = $result->{invalid}; + $data->{total} = $result->{imported} + $result->{overwritten} + $result->{already_in_db} + $result->{invalid}; + } + + $self->finish($data); +} + +=head3 enqueue + +Enqueue the new job. + +=cut + +sub enqueue { + my ( $self, $args ) = @_; + + return unless $args->{file_content}; + + my $line_count = scalar grep { /\S/ } split /\n/, $args->{file_content}; + + $self->SUPER::enqueue( + { + job_size => $line_count > 1 ? $line_count - 1 : 1, + job_args => $args, + job_queue => 'long_tasks', + } + ); +} + +1;